C Library Functions -feof()
C Standard Library - <stdio.h>
feof()Used to detect whether the file has already been read to the end.
We can think of it as an "end detector" — each time you finish reading a portion of the content, you ask it: "Have we reached the end?"
Description
C Library Functionsint feof(FILE *stream)Tests the end-of-file indicator of the given stream.
Two new concepts appear here; let me explain them separately first:
streamIt is an abstraction of input/output in the C language. Whether it's a file on a hard disk, keyboard input, or network data, in C it is uniformly treated as a "stream." You can imagine a stream as a water pipe, with data flowing from one end to the other.
End-of-file indicator (EOF marker)It is an internal status flag carried by each file stream. It is like a bookmark that automatically flips to the "finished reading" page when the file content has been fully read.
The purpose of feof() is to check this bookmark—if the bookmark shows "finished reading", feof() returns a non-zero value. If the bookmark is still at "not finished reading", feof() returns 0.
Declaration
Below is the declaration of the feof() function; let's break down its meaning part by part:
int feof(FILE *stream)
intThis is the return type — feof() returns an integer; non-zero means the end has been reached, 0 means it hasn't.
FILE *streamThis is the parameter — you need to pass in a file pointer (the pointer returned by fopen() when opening the file) to tell feof() which file stream to check.
Parameter
feof() takes one parameter:
| Parameter | Type | Description |
|---|---|---|
| stream | FILE * | File pointer, returned by the fopen() function, pointing to the opened file to be checked. |
Return Value
The return value is described as follows:
| Return Value | Meaning |
|---|---|
| non-zero value | The file has been read to the end; there is no more content to read. |
| 0 | The file has not been fully read yet, so reading can continue |
Key point: feof() only returns a non-zero value after "attempting to read past the end of the file". If you have just read the last character but have not yet tried to continue reading, feof() still returns 0. This timing issue will be explained in detail in the next section.
Example
The following example demonstrates the correct usage of the feof() function.
The program reads the file content character by character, and every time it reads a character, it uses feof() to check whether the end has been reached.
Example
int main ()
{
// FILE * is a file pointer type, used to point to an open file
FILE *fp;
// fgetc() returns int instead of char, because it may need to return EOF (-1)
int c;
// fopen() opens a file, "r" indicates read-only mode (read)
fp = fopen("file.txt","r");
// If the file does not exist or permission is denied, fopen() returns NULL
if(fp == NULL)
{
// perror() prints system error messages to help locate the problem
perror("Error opening file");
return(-1);
}
// Use an infinite loop + internal checks
// This ensures "read first, then check", avoiding reading extra content
while(1)
{
// Step 1: Read a character from the file
c = fgetc(fp);
// Step 2: Immediately after reading, use feof() to check whether the end has been reached
if( feof(fp) )
{
// If the end is reached, break out of the loop and stop processing c
break ;
}
// Step 3: Only use the value of c after confirming the end has not been reached
printf("%c", c);
}
// fclose() closes the file and releases system resources
fclose(fp);
return(0);
}
Suppose we have a text filefile.txt, whose content is as follows:
这里是 example.com
Compile and run the above program, the output is:
这里是 example.com
The program correctly printed all the file contents, without any extra garbled characters.
Common pitfall: why you cannot put feof() in the loop condition
Many beginners write the following style of code, which looks more concise, but is actually wrong:
Incorrect example
int main ()
{
FILE *fp;
int c;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("Error opening file");
return(-1);
}
// Incorrect: using feof() as the loop entry condition
while( !feof(fp) )
{
c = fgetc(fp);
printf("%c", c);
}
fclose(fp);
return(0);
}
The output of this incorrect code would be:
这里是 example.com
There is an extra garbled character at the end. Why is that? Let's trace the loop's execution process round by round below:
| Loop iterations | Loop entry feof() | fgetc() reads | printf() outputs | Description |
|---|---|---|---|---|
| Round 1 | Returns 0 (not yet read) | '这' | 这 | normal |
| Round 2 | Returns 0 (not yet at end) | '里' | 里 | normal |
| ... | ... | ... | ... | Middle characters output normally |
| Last round | Returns 0 (not yet at end) | 'm' | m | The last normal character |
| An extra round | Returns 0 (Note! At this point, 'm' has just been read, and feof doesn't know yet that the end has been reached.) | EOF(-1) | (garbled) | Bug! Read one extra time |
The root of the problem is: when you have just read 'm' (the last character of the file), feof() still returns 0.
It has to wait until you "try to read once more" and discover there is no more content to read, and only then will it flip the internal flag to "ended".
So the while(!feof(fp)) pattern causes the loop to run one extra iteration. In that extra iteration, fgetc() returnsEOF(-1), printf tries to print -1 as a character, resulting in garbled output.
One sentence to remember:feof() is a 'post-hoc report', not an 'advance warning'EOF. It answers "whether the end was reached during the last read," not "whether the end will be reached on the next read." So never use feof() as the entry condition of a loop.
The correct pattern is the approach in the earlier example—read first, then check, and only use the read content after confirming it is safe.
When to use feof()
feof() is mainly used in the following two scenarios:
| Scenarios | Usage | Example |
|---|---|---|
| Read file in a loop | Read first, then check (Recommended) | while(1) { c = fgetc(fp); if(feof(fp)) break; ... } |
| Troubleshooting read errors | Distinguishing between "normal termination" and "read error" | if(feof(fp)) { /* read completed normally */ } else if(ferror(fp)) { /* read error */ } |
In the second scenario, fgetc() returning EOF has two possibilities: either the content has really been fully read (determined with feof()), or an error occurred during reading (determined with ferror()). The two need to be distinguished and handled separately.
other extensions