C / CHAPTER 11
Streams, end-of-file, and error handling
IntermediateKeep byte values distinct from stream status.
By the end of this chapter
- Store fgetc results in int
- Distinguish end-of-file from errors
- Close owned streams on every exit path
The idea
A FILE pointer represents a C stream whose operations can fail independently of your program’s logic. fgetc returns the next unsigned-char value converted to int, or EOF. Store that result in int until checking EOF; narrowing to char first can lose the distinction between an ordinary byte and the status value. Do not use feof as a prediction that the next read will succeed.
After a read loop stops, inspect ferror when you need to distinguish a failure from ordinary end-of-file. Check creation and write results as well as reads. A function that owns a stream should close it on every relevant exit path, while a function borrowing a caller’s stream should follow the caller’s ownership contract. The demonstration uses a temporary stream and reports output only on successful I/O.
#include <stdio.h>
int main(void) {
FILE *file = tmpfile();
if (!file) return 1;
if (fputs("AB", file) == EOF) { fclose(file); return 1; }
rewind(file);
int ch, count = 0;
while ((ch = fgetc(file)) != EOF) ++count;
if (ferror(file)) { fclose(file); return 1; }
printf("%d\n", count);
return fclose(file) == 0 ? 0 : 1;
}2 on the successful temporary-stream path.
The loop counts the two bytes and stops on the read that reports EOF.
Try it yourself
Count newline bytes in a borrowed stream and return a status that distinguishes success from a read error.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING