c eof feof file while-loop

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


What is wrong with using feof() to control a read loop? For example:

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

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

    if( fp == NULL ){
        return EXIT_FAILURE;

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

What is wrong with this loop?




while(!feof) is wrong because it tests for something that is irrelevant and fails to test for something that you need to know. The result is that you are erroneously executing code that assumes that it is accessing data that was read successfully, when in fact this never happened.

I’d like to provide an abstract, high-level perspective. So continue reading if you’re interested in what while(!feof) actually does.

Concurrency and simultaneity

I/O operations interact with the environment. The environment is not part of your program, and not under your control. The environment truly exists “concurrently” with your program. As with all things concurrent, questions about the “current state” don’t make sense: There is no concept of “simultaneity” across concurrent events. Many properties of state simply don’t exist concurrently.

Let me make this more precise: Suppose you want to ask, “do you have more data”. You could ask this of a concurrent container, or of your I/O system. But the answer is generally unactionable, and thus meaningless. So what if the container says “yes” – by the time you try reading, it may no longer have data. Similarly, if the answer is “no”, by the time you try reading, data may have arrived. The conclusion is that there simply is no property like “I have data”, since you cannot act meaningfully in response to any possible answer. (The situation is slightly better with buffered input, where you might conceivably get a “yes, I have data” that constitutes some kind of guarantee, but you would still have to be able to deal with the opposite case. And with output the situation is certainly just as bad as I described: you never know if that disk or that network buffer is full.)

So we conclude that it is impossible, and in fact unreasonable, to ask an I/O system whether it will be able to perform an I/O operation. The only possible way we can interact with it (just as with a concurrent container) is to attempt the operation and check whether it succeeded or failed. At that moment where you interact with the environment, then and only then can you know whether the interaction was actually possible, and at that point you must commit to performing the interaction. (This is a “synchronisation point”, if you will.)


Now we get to EOF. EOF is the response you get from an attempted I/O operation. It means that you were trying to read or write something, but when doing so you failed to read or write any data, and instead the end of the input or output was encountered. This is true for essentially all the I/O APIs, whether it be the C standard library, C++ iostreams, or other libraries. As long as the I/O operations succeed, you simply cannot know whether further, future operations will succeed. You must always first try the operation and then respond to success or failure.


In each of the examples, note carefully that we first attempt the I/O operation and then consume the result if it is valid. Note further that we always must use the result of the I/O operation, though the result takes different shapes and forms in each example.

  • C stdio, read from a file:

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

    The result we must use is n, the number of elements that were read (which may be as little as zero).

  • C stdio, scanf:

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

    The result we must use is the return value of scanf, the number of elements converted.

  • C++, iostreams formatted extraction:

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

    The result we must use is std::cin itself, which can be evaluated in a boolean context and tells us whether the stream is still in the good() state.

  • C++, iostreams getline:

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

    The result we must use is again std::cin, just as before.

  • POSIX, write(2) to flush a buffer:

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

    The result we use here is k, the number of bytes written. The point here is that we can only know how many bytes were written after the write operation.

  • 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 */

    The result we must use is nbytes, the number of bytes up to and including the newline (or EOF if the file did not end with a newline).

    Note that the function explicitly returns -1 (and not EOF!) when an error occurs or it reaches EOF.

You may notice that we very rarely spell out the actual word “EOF”. We usually detect the error condition in some other way that is more immediately interesting to us (e.g. failure to perform as much I/O as we had desired). In every example there is some API feature that could tell us explicitly that the EOF state has been encountered, but this is in fact not a terribly useful piece of information. It is much more of a detail than we often care about. What matters is whether the I/O succeeded, more-so than how it failed.

  • A final example that actually queries the EOF state: Suppose you have a string and want to test that it represents an integer in its entirety, with no extra bits at the end except whitespace. Using C++ iostreams, it goes like this:

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

We use two results here. The first is iss, the stream object itself, to check that the formatted extraction to value succeeded. But then, after also consuming whitespace, we perform another I/O/ operation, iss.get(), and expect it to fail as EOF, which is the case if the entire string has already been consumed by the formatted extraction.

In the C standard library you can achieve something similar with the strto*l functions by checking that the end pointer has reached the end of the input string.


  • 38

    @CiaPan: I don’t think that’s true. Both C99 and C11 allow this.

    – Kerrek SB

    Jan 29, 2015 at 12:10

  • 4

    @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.

    – Kerrek SB

    Feb 3, 2015 at 20:52

  • 4

    @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.

    – Kerrek SB

    Feb 3, 2015 at 21:02

  • 13

    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.

    Sep 10, 2018 at 11:53

  • 4

    @MinhNghĩa: That’s a blocking method, right? That’s basically just a convenience wrapper around “try to read (blocking if necessary), then report the success state, and if successful store the read result in a special buffer”. You can implement the same in C and in C++ if you like.

    – Kerrek SB

    May 31, 2019 at 9:30


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! */
    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 ) {
    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 determine the status of a previous read function
and distinguish between an error condition and the end of the data stream. If fread() returns 0, you must use feof/ferror to decide whether an error occurred 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.)


  • 104

    You should add an example of correct code, as I imagine lots of people will come here looking for a quick fix.

    – jleahy

    Jul 12, 2013 at 16:27

  • 1

    Is this different from file.eof()?

    – Thomas

    Aug 26, 2014 at 22:48

  • 6

    @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++.

    Aug 26, 2014 at 23:36

  • 6

    @m-ric that’s not right either, because you’ll still try to process a read that failed.

    Apr 9, 2015 at 18:25

  • 5

    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

    – Jack

    Jan 28, 2017 at 16:06


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.


  • 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

    Mar 25, 2011 at 11:53

  • 1

    @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

    – Erik

    Mar 25, 2011 at 11:56

  • @pmg: As said, you rarely want while(!eof(f))

    – Erik

    Mar 25, 2011 at 12:41

  • 11

    More accurately, the condition is “while we haven’t tried to read past the end of the file and there was no read error” feof is not about detecting end of file; it is about determining whether a read was short because of an error or because the input is exhausted.

    Jul 3, 2013 at 15:18