हमेशा गलत क्यों होता है?


573

मैंने देखा है कि लोग बहुत सी पोस्ट में इस तरह से फाइल पढ़ने की कोशिश कर रहे हैं:

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
    char *path = "stdin";
    FILE *fp = argc > 1 ? fopen(path=argv[1], "r") : stdin;

    if( fp == NULL ) {
        perror(path);
        return EXIT_FAILURE;
    }

    while( !feof(fp) ) {  /* THIS IS WRONG */
        /* Read and process data from file… */
    }
    if( fclose(fp) != 0 ) {
        perror(path);
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

इस लूप में क्या गलत है?



जवाबों:


453

मैं एक सार, उच्च-स्तरीय परिप्रेक्ष्य प्रदान करना चाहूंगा।

संगति और साथ साथ

आई / ओ संचालन पर्यावरण के साथ बातचीत करते हैं। पर्यावरण आपके कार्यक्रम का हिस्सा नहीं है, और आपके नियंत्रण में नहीं है। पर्यावरण वास्तव में आपके कार्यक्रम के साथ "समवर्ती" मौजूद है। समवर्ती चीजों के साथ, "वर्तमान स्थिति" के बारे में प्रश्न कोई मतलब नहीं रखते हैं: समवर्ती घटनाओं में "एक साथ" की कोई अवधारणा नहीं है। राज्य के कई गुण समवर्ती रूप से मौजूद नहीं हैं

मुझे इसे और सटीक बनाने दें: मान लीजिए कि आप पूछना चाहते हैं, "क्या आपके पास अधिक डेटा है"। आप इसे एक समवर्ती कंटेनर, या आपके I / O सिस्टम से पूछ सकते हैं। लेकिन जवाब आम तौर पर अस्थिर है, और इस तरह अर्थहीन है। तो क्या हुआ अगर कंटेनर "हाँ" कहता है - जब तक आप पढ़ने की कोशिश करते हैं, तब तक उसके पास डेटा नहीं रह सकता है। इसी तरह, यदि उत्तर "नहीं" है, तो जब तक आप पढ़ने की कोशिश करते हैं, तब तक डेटा आ गया होगा। निष्कर्ष यह है कि बस है"मेरे पास डेटा" जैसी कोई संपत्ति नहीं है, क्योंकि आप किसी भी संभावित जवाब के जवाब में सार्थक रूप से कार्य नहीं कर सकते हैं। (बफ़र्ड इनपुट के साथ स्थिति थोड़ी बेहतर है, जहां आप गर्भ धारण कर सकते हैं "हाँ, मेरे पास डेटा है" जो किसी प्रकार की गारंटी देता है, लेकिन आपको अभी भी विपरीत मामले से निपटने में सक्षम होना चाहिए और आउटपुट स्थिति के साथ। निश्चित रूप से केवल उतना ही बुरा है जितना मैंने वर्णित किया है: आप कभी नहीं जानते कि क्या वह डिस्क या वह नेटवर्क बफर भरा हुआ है।)

इसलिए हम निष्कर्ष निकालते हैं कि यह असंभव है, और वास्तव में एक उचित , एक I / O प्रणाली से पूछना है कि क्या यह I / O ऑपरेशन करने में सक्षम होगा । एकमात्र संभव तरीका है कि हम इसके साथ बातचीत कर सकते हैं (बस एक समवर्ती कंटेनर के साथ) ऑपरेशन का प्रयास करें और जांचें कि क्या यह सफल हुआ या असफल। उस क्षण जहां आप पर्यावरण के साथ बातचीत करते हैं, तब और केवल तभी आप यह जान सकते हैं कि क्या वास्तव में बातचीत संभव थी, और उस बिंदु पर आपको बातचीत करने के लिए प्रतिबद्ध होना चाहिए। (यह एक "तुल्यकालन बिंदु" है, यदि आप करेंगे।)

EOF

अब हम ईओएफ पर पहुंचते हैं। EOF है प्रतिक्रिया आप एक से प्राप्त करने का प्रयास किया आई / ओ आपरेशन। इसका मतलब है कि आप कुछ पढ़ने या लिखने की कोशिश कर रहे थे, लेकिन ऐसा करते समय आप किसी डेटा को पढ़ने या लिखने में विफल रहे, और इसके बजाय इनपुट या आउटपुट का अंत सामने आया। यह अनिवार्य रूप से सभी I / O API के लिए सही है, चाहे वह C मानक लाइब्रेरी हो, C ++ iostreams, या अन्य लाइब्रेरी। जब तक I / O ऑपरेशन सफल होते हैं, आप बस यह नहीं जान सकते कि आगे चलकर, भविष्य के ऑपरेशन सफल होंगे या नहीं । आपको हमेशा ऑपरेशन का प्रयास करना चाहिए और फिर सफलता या विफलता का जवाब देना चाहिए।

उदाहरण

प्रत्येक उदाहरण में, ध्यान से देखें कि हम पहले I / O ऑपरेशन का प्रयास करते हैं और फिर परिणाम मान्य होने पर उपभोग करते हैं। आगे ध्यान दें कि हमें हमेशा I / O ऑपरेशन के परिणाम का उपयोग करना चाहिए, हालांकि परिणाम प्रत्येक उदाहरण में अलग-अलग आकार और रूप लेता है।

  • सी stdio, एक फ़ाइल से पढ़ें:

    for (;;) {
        size_t n = fread(buf, 1, bufsize, infile);
        consume(buf, n);
        if (n < bufsize) { break; }
    }
    

    परिणाम जो हमें उपयोग करना चाहिए n, वह उन तत्वों की संख्या है जो पढ़े गए थे (जो कि शून्य से कम हो सकते हैं)।

  • सी stdio scanf:

    for (int a, b, c; scanf("%d %d %d", &a, &b, &c) == 3; ) {
        consume(a, b, c);
    }
    

    जिस परिणाम का हमें उपयोग करना चाहिए, वह वापसी मान है scanf, परिवर्तित तत्वों की संख्या।

  • C ++, iostreams स्वरूपित निष्कर्षण:

    for (int n; std::cin >> n; ) {
        consume(n);
    }
    

    हमें जिस परिणाम का उपयोग करना चाहिए वह std::cinस्वयं है, जिसका मूल्यांकन एक बूलियन संदर्भ में किया जा सकता है और हमें बता सकता है कि क्या धारा अभी भी good()राज्य में है।

  • C ++, iostreams getline:

    for (std::string line; std::getline(std::cin, line); ) {
        consume(line);
    }
    

    परिणाम हमें std::cinपहले की तरह ही फिर से उपयोग करना चाहिए ।

  • POSIX, write(2)बफर को फ्लश करने के लिए:

    char const * p = buf;
    ssize_t n = bufsize;
    for (ssize_t k = bufsize; (k = write(fd, p, n)) > 0; p += k, n -= k) {}
    if (n != 0) { /* error, failed to write complete buffer */ }
    

    हमारे द्वारा उपयोग किया जाने वाला परिणाम k, लिखित बाइट्स की संख्या है। यहां मुद्दा यह है कि हम केवल यह जान सकते हैं कि राइट ऑपरेशन के बाद कितने बाइट्स लिखे गए थे ।

  • POSIX getline()

    char *buffer = NULL;
    size_t bufsiz = 0;
    ssize_t nbytes;
    while ((nbytes = getline(&buffer, &bufsiz, fp)) != -1)
    {
        /* Use nbytes of data in buffer */
    }
    free(buffer);
    

    हमें जिस परिणाम का उपयोग करना चाहिए वह है nbytes, न्यूलाइन और (या ईओएफ सहित यदि फाइल नई लाइन के साथ समाप्त नहीं हुई) तो बाइट्स की संख्या।

    ध्यान दें कि -1जब कोई त्रुटि होती है या यह EOF तक पहुँचता है, तो फ़ंक्शन स्पष्ट रूप से वापस लौटता है (और EOF नहीं!)।

आप देख सकते हैं कि हमने वास्तविक शब्द "ईओएफ" को बहुत कम ही लिखा है। हम आम तौर पर कुछ अन्य तरीके से त्रुटि की स्थिति का पता लगाते हैं जो हमारे लिए और अधिक दिलचस्प है (उदाहरण के लिए प्रदर्शन करने में विफलता I / O के रूप में ज्यादा के रूप में हम चाहते थे)। हर उदाहरण में कुछ एपीआई सुविधा है जो हमें स्पष्ट रूप से बता सकती है कि ईओएफ राज्य का सामना किया गया है, लेकिन यह वास्तव में जानकारी का एक बहुत उपयोगी टुकड़ा नहीं है। यह हमारे द्वारा अक्सर देखभाल की तुलना में बहुत अधिक विवरण है। क्या मायने रखता है कि क्या आई / ओ सफल हुआ, इससे अधिक-कैसे यह विफल रहा।

  • एक अंतिम उदाहरण जो वास्तव में ईओएफ राज्य पर सवाल उठाता है: मान लीजिए कि आपके पास एक स्ट्रिंग है और यह परीक्षण करना चाहता है कि यह व्हाट्सएप को छोड़कर अंत में बिना किसी अतिरिक्त बिट्स के पूर्णांक में पूर्णांक का प्रतिनिधित्व करता है। C ++ iostreams का उपयोग करना, यह इस प्रकार है:

    std::string input = "   123   ";   // example
    
    std::istringstream iss(input);
    int value;
    if (iss >> value >> std::ws && iss.get() == EOF) {
        consume(value);
    } else {
        // error, "input" is not parsable as an integer
    }
    

    हम यहां दो परिणामों का उपयोग करते हैं। पहला है iss, स्ट्रीम ऑब्जेक्ट खुद, यह जांचने के लिए कि स्वरूपित निष्कर्षण valueसफल हुआ। लेकिन फिर, व्हॉट्सएप का उपभोग करने के बाद, हम एक और I / O / ऑपरेशन करते हैं, iss.get()और उम्मीद करते हैं कि यह EOF के रूप में विफल हो सकता है, जो कि अगर पूरे स्ट्रिंग पहले से ही स्वरूपित निष्कर्षण द्वारा खा लिया गया है।

    सी मानक लाइब्रेरी में आप strto*lफ़ंक्शन स्ट्रिंग के अंत तक पहुँच चुके हैं कि जाँच करके कुछ समान कार्यों को प्राप्त कर सकते हैं ।

उत्तर

while(!feof)गलत है क्योंकि यह ऐसी चीज़ के लिए परीक्षण करता है जो अप्रासंगिक है और उस चीज़ के लिए परीक्षण करने में विफल रहती है जिसे आपको जानना आवश्यक है। परिणाम यह है कि आप गलत तरीके से कोड को निष्पादित कर रहे हैं जो मानता है कि यह उस डेटा तक पहुंच रहा है जो सफलतापूर्वक पढ़ा गया था, जब वास्तव में ऐसा कभी नहीं हुआ था।


34
@CiaPan: मुझे नहीं लगता कि यह सच है। C99 और C11 दोनों इसकी अनुमति देते हैं।
केरेके एसबी

11
लेकिन एएनएसआई सी नहीं करता है।
सियापन

3
@JonathanMee: मेरे द्वारा उल्लिखित सभी कारणों से यह बुरा है: आप भविष्य में नहीं देख सकते। आप यह नहीं बता सकते कि भविष्य में क्या होगा।
केरेक एसबी

3
@JonathanMee: हां, यह उचित होगा, हालांकि आमतौर पर आप इस चेक को ऑपरेशन में जोड़ सकते हैं (क्योंकि अधिकांश iostreams ऑपरेशन स्ट्रीम ऑब्जेक्ट को वापस कर देते हैं, जिसमें स्वयं बूलियन रूपांतरण होता है), और इस तरह से आप यह स्पष्ट कर देते हैं कि आप नहीं हैं वापसी मूल्य की अनदेखी।
केरेके एसबी

4
तीसरा पैराग्राफ एक स्वीकृत और उच्चतर उत्तर के लिए उल्लेखनीय रूप से भ्रामक / गलत है। feof()"I / O सिस्टम से यह नहीं पूछता कि क्या उसके पास अधिक डेटा है"। feof()(लिनक्स) मैनपेज के अनुसार : "स्ट्रीम द्वारा इंगित की गई स्ट्रीम के लिए फ़ाइल के इंडिकेटर का परीक्षण करता है, यदि यह सेट है तो नॉनज़ेरो को लौटाता है।" (यह भी, clearerr()इस सूचक को रीसेट करने का एकमात्र तरीका स्पष्ट कॉल है); इस लिहाज से विलियम पुरसेल का जवाब ज्यादा बेहतर है।
अर्ने वोगेल

234

यह गलत है क्योंकि (एक पढ़ने में त्रुटि के अभाव में) यह लेखक की अपेक्षा एक बार लूप में प्रवेश करता है। यदि कोई पठन त्रुटि है, तो लूप कभी समाप्त नहीं होता है।

निम्नलिखित कोड पर विचार करें:

/* WARNING: demonstration of bad coding technique!! */

#include <stdio.h>
#include <stdlib.h>

FILE *Fopen(const char *path, const char *mode);

int main(int argc, char **argv)
{
    FILE *in;
    unsigned count;

    in = argc > 1 ? Fopen(argv[1], "r") : stdin;
    count = 0;

    /* WARNING: this is a bug */
    while( !feof(in) ) {  /* This is WRONG! */
        fgetc(in);
        count++;
    }
    printf("Number of characters read: %u\n", count);
    return EXIT_SUCCESS;
}

FILE * Fopen(const char *path, const char *mode)
{
    FILE *f = fopen(path, mode);
    if( f == NULL ) {
        perror(path);
        exit(EXIT_FAILURE);
    }
    return f;
}

यह प्रोग्राम लगातार इनपुट स्ट्रीम में वर्णों की संख्या से अधिक प्रिंट करेगा (कोई त्रुटि नहीं पढ़ता है)। उस मामले पर विचार करें जहां इनपुट स्ट्रीम खाली है:

$ ./a.out < /dev/null
Number of characters read: 1

इस मामले में, feof()किसी भी डेटा को पढ़ने से पहले कहा जाता है, इसलिए यह गलत है। लूप में प्रवेश किया fgetc()जाता है, (और रिटर्न EOF) कहा जाता है , और गिनती बढ़ जाती है। फिर feof()कहा जाता है और सच लौटाता है, जिससे लूप गर्भपात हो जाता है।

ऐसा सभी मामलों में होता है। feof()तब तक सही नहीं होता जब तक स्ट्रीम पर एक रीड के बाद फाइल का अंत नहीं हो जाता। feof()यदि अगला रीड फ़ाइल के अंत तक पहुंच जाएगा, तो जांच का उद्देश्य नहीं है। इसका उद्देश्य feof()रीड एरर और फाइल के अंत तक पहुंचने के बीच अंतर करना है। यदि fread()रिटर्न 0 है, तो आपको यह निर्धारित करने के लिए feof/ ferrorका उपयोग करना होगा कि क्या कोई त्रुटि आई थी या यदि सभी डेटा का उपभोग किया गया था। इसी तरह अगर fgetcरिटर्न EOFfeof()के बाद ही उपयोगी है शून्य वापस आ गया है या fgetcवापस आ गया है EOF। ऐसा होने से पहले, feof()हमेशा 0 वापस आ जाएगा।

यह हमेशा आवश्यक पढ़ने की वापसी मान की जाँच करने (या तो एक है fread(), या एक fscanf(), या एक fgetc()) कॉल करने से पहले feof()

इससे भी बदतर, उस मामले पर विचार करें जहां एक पढ़ने में त्रुटि होती है। उस स्थिति में, fgetc()रिटर्न EOF, feof()गलत रिटर्न, और लूप कभी समाप्त नहीं होता है। सभी मामलों में, जहां while(!feof(p))उपयोग किया जाता है, कम से कम लूप के अंदर एक चेक होना चाहिए ferror(), या बहुत कम से कम जबकि स्थिति के साथ प्रतिस्थापित किया जाना चाहिए while(!feof(p) && !ferror(p))या एक अनंत लूप की बहुत वास्तविक संभावना है, संभवतः सभी प्रकार के कचरे को उगलते हुए। अमान्य डेटा संसाधित किया जा रहा है।

इसलिए, संक्षेप में, हालांकि मैं यह निश्चितता के साथ नहीं बता सकता कि ऐसी कोई स्थिति नहीं है जिसमें यह लिखना शब्दबद्ध रूप से सही हो सकता है " while(!feof(f))" (हालांकि एक पढ़ने में त्रुटि पर अनंत लूप से बचने के लिए लूप के अंदर एक और जांच होनी चाहिए) ), यह मामला है कि यह लगभग निश्चित रूप से हमेशा गलत है। और यहां तक ​​कि अगर कोई मामला कभी उत्पन्न हुआ, जहां यह सही होगा, तो यह बहुत ही गलत है कि यह कोड लिखने का सही तरीका नहीं होगा। किसी को भी उस कोड को देखकर तुरंत संकोच करना चाहिए और कहना चाहिए, "यह एक बग है"। और संभवतः लेखक को थप्पड़ मारें (जब तक कि लेखक आपका बॉस न हो, जिसमें विवेक की सलाह दी जाती है।)


7
यकीन है कि यह गलत है - लेकिन इससे अलग यह "गंभीर रूप से बदसूरत" नहीं है।
नोबार

89
आपको सही कोड का एक उदाहरण जोड़ना चाहिए, क्योंकि मुझे लगता है कि बहुत से लोग जल्दी ठीक होने की तलाश में यहां आएंगे।
जैलहि जूल

6
@ थोमस: मैं C ++ विशेषज्ञ नहीं हूं, लेकिन मेरा मानना ​​है कि file.eof () प्रभावी रूप से उसी परिणाम को लौटाता है feof(file) || ferror(file), इसलिए यह बहुत अलग है। लेकिन यह प्रश्न C ++ पर लागू होने का इरादा नहीं है।
विलियम पर्सेल

6
@ m-ric यह सही भी नहीं है, क्योंकि आप अभी भी पढ़ने की प्रक्रिया को विफल करने का प्रयास करेंगे।
मार्क रैनसम

4
यह वास्तविक सही उत्तर है। पिछले रीड प्रयास के परिणाम को जानने के लिए feof () का उपयोग किया जाता है। इस प्रकार शायद आप इसे अपने लूप ब्रेक कंडीशन के रूप में उपयोग नहीं करना चाहते हैं। +1
जैक

63

नहीं, यह हमेशा गलत नहीं होता। यदि आपकी लूप की स्थिति "है जबकि हमने फ़ाइल के पिछले सिरे को पढ़ने की कोशिश नहीं की है" तो आप उपयोग करते हैं while (!feof(f))। यह हालांकि एक सामान्य लूप की स्थिति नहीं है - आमतौर पर आप किसी और चीज़ के लिए परीक्षण करना चाहते हैं (जैसे "मैं और अधिक पढ़ सकता हूं")। while (!feof(f)), गलत नहीं है यह सिर्फ है इस्तेमाल किया गलत।


1
मुझे आश्चर्य है ... f = fopen("A:\\bigfile"); while (!feof(f)) { /* remove diskette */ }या (यह परीक्षण करने के लिए जा रहा है)f = fopen(NETWORK_FILE); while (!feof(f)) { /* unplug network cable */ }
pmg

1
@pmg: जैसा कि कहा गया है, "एक आम लूप की स्थिति नहीं" हे। मैं वास्तव में किसी भी मामले के बारे में सोच नहीं सकता, जिसकी मुझे आवश्यकता है, आमतौर पर मैं "मैं जो चाहता था, वह पढ़ सकता था" जो सभी त्रुटि त्रुटि से तात्पर्य है
एरिक

@pmg: जैसा कि कहा गया है, आप शायद ही कभी चाहते हैंwhile(!eof(f))
एरिक

9
अधिक सटीक रूप से, यह स्थिति "जब हमने फ़ाइल के अंत को पढ़ने की कोशिश नहीं की है और कोई रीड त्रुटि नहीं थी" feofफ़ाइल के अंत का पता लगाने के बारे में नहीं है; यह निर्धारित करने के बारे में है कि क्या त्रुटि के कारण कोई रीड छोटा था या इनपुट समाप्त हो गया है।
विलियम पर्सेल

35

feof()इंगित करता है कि क्या किसी ने फ़ाइल के अंत में पिछले पढ़ने की कोशिश की है। इसका मतलब है कि इसका थोड़ा पूर्वानुमानात्मक प्रभाव है: यदि यह सच है, तो आप सुनिश्चित हैं कि अगला इनपुट ऑपरेशन विफल हो जाएगा (आपको यकीन नहीं है कि पिछला एक असफल बीटीडब्ल्यू), लेकिन अगर यह गलत है, तो आपको यकीन नहीं है कि अगला इनपुट ऑपरेशन सफल होगा। अधिक जानकारी के लिए, फ़ाइल के अंत की तुलना में इनपुट संचालन अन्य कारणों से विफल हो सकता है (स्वरूपित इनपुट के लिए एक प्रारूप त्रुटि, एक शुद्ध IO विफलता - डिस्क विफलता, नेटवर्क टाइमआउट - सभी इनपुट प्रकारों के लिए), भले ही आप के बारे में पूर्वानुमान हो सकता है फ़ाइल का अंत (और कोई भी जिसने Ada एक को लागू करने की कोशिश की है, जो कि पूर्वानुमान है, आपको बताएगा कि क्या आपको रिक्त स्थान छोड़ने की आवश्यकता है, और यह कि इंटरेक्टिव उपकरणों पर अवांछनीय प्रभाव पड़ता है - कभी-कभी अगले के इनपुट को मजबूर करना पिछले एक की हैंडलिंग शुरू करने से पहले लाइन),

तो C में सही मुहावरे को लूप स्थिति के रूप में IO ऑपरेशन की सफलता के साथ लूप करना है, और फिर विफलता के कारण का परीक्षण करना है। उदाहरण के लिए:

while (fgets(line, sizeof(line), file)) {
    /* note that fgets don't strip the terminating \n, checking its
       presence allow to handle lines longer that sizeof(line), not showed here */
    ...
}
if (ferror(file)) {
   /* IO failure */
} else if (feof(file)) {
   /* format error (not possible with fgets, but would be with fscanf) or end of file */
} else {
   /* format error (not possible with fgets, but would be with fscanf) */
}

2
किसी फ़ाइल के अंत में जाना एक त्रुटि नहीं है, इसलिए मैं सवाल पूछता हूं कि "फ़ाइल के अंत की तुलना में अन्य कारणों से इनपुट ऑपरेशन विफल हो सकते हैं"।
विलियम पर्ससेल ने

@WilliamPursell, eof तक पहुंचना आवश्यक रूप से त्रुटि नहीं है, लेकिन eof के कारण इनपुट ऑपरेशन करने में असमर्थ होना एक है। और सी में असंभव है कि इनपुट ऑपरेशन विफल होने के बिना मज़बूती से ईओफ़ का पता लगाना।
एपीग्रामग्राम

सहमत elseनहीं पिछले साथ संभव है sizeof(line) >= 2और fgets(line, sizeof(line), file)लेकिन पैथोलॉजिकल size <= 0और के साथ संभव है fgets(line, size, file)। शायद साथ भी संभव हो sizeof(line) == 1
chux -

1
सभी "भविष्य कहनेवाला मूल्य" बात करते हैं ... मैंने इसके बारे में कभी नहीं सोचा था। मेरी दुनिया में, feof(f)कुछ भी PREDICT नहीं करता है। यह बताता है कि एक PREVIOUS ऑपरेशन ने फ़ाइल के अंत को मारा है। न कुछ ज्यादा, न कुछ कम। और अगर कोई पिछला ऑपरेशन नहीं था (बस इसे खोला गया), यह फ़ाइल के अंत की रिपोर्ट नहीं करता है, भले ही फ़ाइल को शुरू करने के लिए खाली हो। इसलिए, ऊपर दिए गए दूसरे उत्तर में संक्षिप्त विवरण के अलावा, मुझे नहीं लगता कि लूप न करने का कोई कारण है feof(f)
BitTickler

@AProgrammer: एक "एन बाइट्स तक पढ़ें" अनुरोध जो कि पैदावार देता है, चाहे "स्थायी" ईओएफ के कारण या क्योंकि अभी तक कोई और डेटा उपलब्ध नहीं है , एक त्रुटि नहीं है। हालांकि फ़ॉफ़ () भविष्य के अनुरोधों का अनुमान नहीं लगा सकते हैं कि भविष्य के अनुरोध डेटा प्राप्त करेंगे, यह मज़बूती से संकेत दे सकता है कि भविष्य के अनुरोध नहीं होंगे । शायद एक स्थिति समारोह होना चाहिए जो यह संकेत देगा कि "यह प्रशंसनीय है कि भविष्य में पढ़ने के अनुरोध सफल होंगे", शब्दार्थ के साथ कि एक साधारण फ़ाइल के अंत में पढ़ने के बाद, एक गुणवत्ता कार्यान्वयन को यह कहना चाहिए कि भविष्य में पढ़े जाने वाले कुछ कारणों से अनुपस्थित रहने की संभावना नहीं है विश्वास है कि वे हो सकता है
सुपर स्टार

0

feof()बहुत सहज नहीं है। मेरी बहुत विनम्र राय में, FILEफ़ाइल trueके अंत में किसी भी रीड ऑपरेशन के परिणाम तक पहुँचने के लिए फ़ाइल की स्थिति समाप्त हो जानी चाहिए । इसके बजाय, आपको मैन्युअल रूप से जांचना होगा कि क्या प्रत्येक रीड ऑपरेशन के बाद फ़ाइल का अंत पहुंच गया है या नहीं। उदाहरण के लिए, कुछ इस तरह से काम करेगा यदि पाठ फ़ाइल का उपयोग करके पढ़ा जाए fgetc():

#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *in = fopen("testfile.txt", "r");

  while(1) {
    char c = fgetc(in);
    if (feof(in)) break;
    printf("%c", c);
  }

  fclose(in);
  return 0;
}

यह बहुत अच्छा होगा अगर ऐसा कुछ इसके बजाय काम करेगा:

#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *in = fopen("testfile.txt", "r");

  while(!feof(in)) {
    printf("%c", fgetc(in));
  }

  fclose(in);
  return 0;
}

1
printf("%c", fgetc(in));? यह अपरिभाषित व्यवहार है। fgetc()रिटर्न int, नहीं char
एंड्रयू हेनले

यह मुझे लगता है कि मानक मुहावरा while( (c = getchar()) != EOF)बहुत कुछ "ऐसा ही कुछ" है।
विलियम पर्ससेल

while( (c = getchar()) != EOF)GNU C 10.1.0 पर चलने वाले मेरे एक डेस्कटॉप पर काम करता है, लेकिन GNU C 9.3.0 पर चलने वाले मेरे रास्पबेरी पाई 4 पर विफल रहता है। मेरे RPi4 पर, यह फ़ाइल के अंत का पता नहीं लगाता है, और बस चलता रहता है।
स्कॉट डीगन

@AndrewHenle तुम सही हो! बदलने char cके लिए int cकाम करता है! धन्यवाद!!
स्कॉट डीगन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.