When a function returns EOF (or, occasionally, 0 or NULL, as in the case of fread and fgets respectively), we commonly say that we have reached ``end of file,'' but it turns out that it's also possible that there's been some kind of I/O error. When you want to distinguish between end-of-file and error, you can do so with the feof and ferror functions. feof(fp) returns nonzero (that is, ``true'') if end-of-file has been reached on the stream fp, and ferror(fp) returns nonzero if there has been an error. Notice the past tense and passive voice: feof returns nonzero if end-of-file has been reached. It does not tell you that the next attempt to read from the stream will reach end-of-file, but rather that the previous attempt (by some other function) already did. (If you know Pascal, you may notice that the end-of-file detection situation in C is therefore quite different from Pascal.) Therefore, you would never write a loop like
while(!feof(fp)) fgets(line, max, fp);Instead, check the return value of the input function directly:
while(fgets(line, max, fp) != NULL)With a very few possible exceptions, you don't use feof to detect end-of-file; you use feof or ferror to distinguish between end-of-file and error. (You can also use ferror to diagnose error conditions on output files.)
Since the end-of-file and error conditions tend to persist on a stream, it's sometimes necessary to clear (reset) them, which you can do with clearerr(FILE *fp).
What should your program do if it detects an I/O error? Certainly, it cannot continue as usual; usually, it will print an error message. The simplest error messages are of the form
fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "can't open file\n");
return;
}
or
while(fgets(line, max, fp) != NULL)
{
... process input ...
}
if(ferror(fp))
fprintf(stderr, "error reading input\n");
or
fprintf(ofp, "%d %d %d\n", a, b, c); if(ferror(ofp)) fprintf(stderr, "output write error\n");Error messages are much more useful, however, if they include a bit more information, such as the name of the file for which the operation is failing, and if possible why it is failing. For example, here is a more polite way to report that a file could not be opened:
#include <stdio.h> /* for fopen */
#include <errno.h> /* for errno */
#include <string.h> /* for strerror */
fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "can't open %s for reading: %s\n",
filename, strerror(errno));
return;
}
errno is a global variable, declared in <errno.h>,
which may
contain
a numeric code
indicating the reason for a recent system-related error
such as inability to open a file.
The strerror function takes an errno code
and returns a human-readable string
such as ``No such file'' or ``Permission denied''.
An even more useful error message, especially for a ``toolkit'' program intended to be used in conjunction with other programs, would include in the message text the name of the program reporting the error.
Read sequentially: prev next up top
This page by Steve Summit // Copyright 1996-1999 // mail feedback