In C standard library "end of file" is not an independent self-detecting condition. "End of file" is merely a file state set by the preceding read operation. Until you perform a read operation and until that read operation bumps into the actual end of file, "eof" state is not set and feof()
returns 0.
Many (most) standard I/O functions in C standard library already return some completion code that can be used to detect "end of file" condition (like fgetc()
returning EOF
value). This means that most of the time calling feof()
is unnecessary.
In other words, if you think about "end of file" as a brick wall, in C standard library it is not sufficient to stand right in front of that wall in order to detect it. It is necessary to actually bump into that wall with your forehead in order to discover its presence.
When you open an empty file, you begin in a state "right before the wall". At this point "end of file" condition is not detected yet. You have to try reading something in order to crash into that wall and thus detect its presence.
The reasons for this design are perfectly logical. C language is designed to support various input streams and file systems, including 1) file systems that do not store file sizes at all, as well as 2) file systems that know only approximate file size (like rounded to a nearest cluster). In such file systems the end of file is usually designated by a special marker. You don't know where that marker is until you run into it while reading the file. (For the very same reason C streams do not guarantee support for positioning from SEEK_END
origin in fseek
function.)
As @Barmar noted in the comments, an even better example of an input stream without a pre-determined "end of file" position is standard input linked to terminal.