Error Handling
errno, perror, and checking return values that are easy to skip.
The habit this chapter is really building: check the return value, every time, even when it's tempting to assume the call just worked.
FILE *f = fopen("missing.txt", "r");
if (f == NULL) {
perror("fopen failed"); /* prints: fopen failed: No such file or directory */
return -1;
}errno is a global (thread-local, really) set by the last failed call, and perror prints a human-readable message for whatever it currently holds. The pattern is always the same: check the return value for the failure signal first (NULL, -1, whatever that function uses), and only then bother consulting errno for why.
It's an easy check to skip because most of the time the call does succeed — right up until it's running against a full disk, a missing device, or a permissions problem, and the program either crashes on a NULL dereference or silently does nothing.
Notes from readers
Comments — via GitHub