Why is “while ( !feof (file) )” always wrong?

why is the sky blue
why is the sky red
why is the sun yellow
why is the sky blue and sunsets red
why is the sea blue
why is the sky pink
why is the sky blue for kids?
why is grass green

I've seen people trying to read files like this in a lot of posts lately:

#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;
}

What is wrong with this loop?

Why is Cats?, Don't get cocky. Nebula exclusive Les Miserables video: https://watchnebula.com​ Duration: 57:30 Posted: Apr 3, 2020 noun, plural whys. a question concerning the cause or reason for which something is done, achieved, etc.: a child's unending hows and whys. the cause or reason: the whys and wherefores of a troublesome situation. interjection. (used as an expression of surprise, hesitation, etc., or sometimes a mere expletive): Why, it's all gone!

It's wrong because (in the absence of a read error) it enters the loop one more time than the author expects. If there is a read error, the loop never terminates.

Consider the following code:

/* 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;
}

This program will consistently print one greater than the number of characters in the input stream (assuming no read errors). Consider the case where the input stream is empty:

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

In this case, feof() is called before any data has been read, so it returns false. The loop is entered, fgetc() is called (and returns EOF), and count is incremented. Then feof() is called and returns true, causing the loop to abort.

This happens in all such cases. feof() does not return true until after a read on the stream encounters the end of file. The purpose of feof() is NOT to check if the next read will reach the end of file. The purpose of feof() is to distinguish between a read error and having reached the end of the file. If fread() returns 0, you must use feof/ferror to decide whether an error was encountered or if all of the data was consumed. Similarly if fgetc returns EOF. feof() is only useful after fread has returned zero or fgetc has returned EOF. Before that happens, feof() will always return 0.

It is always necessary to check the return value of a read (either an fread(), or an fscanf(), or an fgetc()) before calling feof().

Even worse, consider the case where a read error occurs. In that case, fgetc() returns EOF, feof() returns false, and the loop never terminates. In all cases where while(!feof(p)) is used, there must be at least a check inside the loop for ferror(), or at the very least the while condition should be replaced with while(!feof(p) && !ferror(p)) or there is a very real possibility of an infinite loop, probably spewing all sorts of garbage as invalid data is being processed.

So, in summary, although I cannot state with certainty that there is never a situation in which it may be semantically correct to write "while(!feof(f))" (although there must be another check inside the loop with a break to avoid a infinite loop on a read error), it is the case that it is almost certainly always wrong. And even if a case ever arose where it would be correct, it is so idiomatically wrong that it would not be the right way to write the code. Anyone seeing that code should immediately hesitate and say, "that's a bug". And possibly slap the author (unless the author is your boss in which case discretion is advised.)

Why is cotton in everything? - Michael R. Stiff, Dig into the science of how cotton transforms from seed to fiber, and how these cotton fibers are Duration: 4:54 Posted: Jan 23, 2020 Noun. 1. why - the cause or intention underlying an action or situation, especially in the phrase `the whys and wherefores'. wherefore. reason, ground - a rational motive for a belief or action; "the reason that war was declared"; "the grounds for their declaration".

No it's not always wrong. If your loop condition is "while we haven't tried to read past end of file" then you use while (!feof(f)). This is however not a common loop condition - usually you want to test for something else (such as "can I read more"). while (!feof(f)) isn't wrong, it's just used wrong.

Why Is the Sky Blue?, Blue light is scattered more than other colors because it travels as shorter, smaller waves. This is why we see a blue sky most of the time. Like most curious​  adverb. Why is defined as for what purpose, cause or reason. An example of why is when it is used to ask a question such as "Why are you drinking water? YourDictionary definition and usage example.

feof() indicates if one has tried to read past the end of file. That means it has little predictive effect: if it is true, you are sure that the next input operation will fail (you aren't sure the previous one failed BTW), but if it is false, you aren't sure the next input operation will succeed. More over, input operations may fail for other reasons than the end of file (a format error for formatted input, a pure IO failure -- disk failure, network timeout -- for all input kinds), so even if you could be predictive about the end of file (and anybody who has tried to implement Ada one, which is predictive, will tell you it can complex if you need to skip spaces, and that it has undesirable effects on interactive devices -- sometimes forcing the input of the next line before starting the handling of the previous one), you would have to be able to handle a failure.

So the correct idiom in C is to loop with the IO operation success as loop condition, and then test the cause of the failure. For instance:

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) */
}

Why is the sky blue?, Why is the sky blue? The sky appears blue to the human eye as the short waves of blue light are scattered more than the other colours in  The question: "Why is [etc.]" is a question form in English: Why is the sky blue? Why is it that children require so much attention? Why is it [or some thing] like that? When that form is put into what is called indirect speech, it becomes: Please tell me why the sky is blue. Please tell me why children require so much attention.

Terry Moore: Why is 'x' the unknown?, Why is 'x' the symbol for an unknown? In this short and funny talk, Terry Moore gives the Duration: 3:57 Posted: Mar 10, 2014 Blue light is scattered in all directions by the tiny molecules of air in Earth's atmosphere. Blue is scattered more than other colors because it travels as shorter, smaller waves. This is why we see a blue sky most of the time. Closer to the horizon, the sky fades to a lighter blue or white.

Why is the ocean blue?, Big Sur coastline looking north to Bixby Canyon Bridge in California. The ocean is blue because water absorbs colors in the red part of the light spectrum. Like a  Cholesterol is a substance made in the liver that’s vital to human life. Cholesterol isn’t all good, nor is it all bad. It’s a complex topic and one worth knowing more about. Learn what you

Why, Why definition, for what? for what reason, cause, or purpose?: Why did you behave so badly? for what cause or reason: I don't know why he is leaving. Gwyneth has made a candle called This Smells Like My Vagina for her website, Goop. And, of course, it has sold out

Comments
  • Why it's bad to use feof() to control a loop
  • Why is iostream::eof inside a loop condition considered wrong?
  • @CiaPan: I don't think that's true. Both C99 and C11 allow this.
  • But ANSI C does not.
  • @JonathanMee: It's bad for all the reasons I mention: you cannot look into the future. You cannot tell what will happen in the future.
  • @JonathanMee: Yes, that would be appropriate, though usually you can combine this check into the operation (since most iostreams operations return the stream object, which itself has a boolean conversion), and that way you make it obvious that you're not ignoring the return value.
  • Third paragraph is remarkably misleading/inaccurate for an accepted and highly upvoted answer. feof() does not "ask the I/O system whether it has more data". feof(), according to the (Linux) manpage: "tests the end-of-file indicator for the stream pointed to by stream, returning nonzero if it is set." (also, an explicit call to clearerr() is the only way to reset this indicator); In this respect, William Pursell's answer is much better.
  • Sure it's wrong -- but aside from that it isn't "gratingly ugly".
  • You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.
  • @Thomas: I'm not a C++ expert, but I believe file.eof() returns effectively the same result as feof(file) || ferror(file), so it is very different. But this question is not intended to be applicable to C++.
  • @m-ric that's not right either, because you'll still try to process a read that failed.
  • this is the actual correct answer. feof() is used to know the outcome of previous read attempt. Thus probably you don't want to use it as your loop break condition. +1
  • I wonder ... f = fopen("A:\\bigfile"); while (!feof(f)) { /* remove diskette */ } or (going to test this) f = fopen(NETWORK_FILE); while (!feof(f)) { /* unplug network cable */ }
  • @pmg: As said, "not a common loop condition" hehe. I can't really think of any case I've needed it, usually I'm interested in "could I read what I wanted" with all that implies of error handling