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