Upon looking at the ISO C11 standard for fgets
§7.21.7.2, 3, the return value is stated regarding the synopsis code:
#include <stdio.h>
char *fgets(char* restrict s, int n, FILE* restrict stream);
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.
The standard says that a null pointer is returned for either an end-of-file and no characters have been read in or a read error occurs. My question is, just from fgets
, and the returned null pointer, is there a way to distinguish which of the two cases caused the error?
Yes, use
feof()
andferror()
to distinguish. @Nothing NothingYet it is important to use correctly. Consider the two codes:
The second properly tests the return value against
NULL
, as suggested by OP.The first can encounter a rare problem. The
ferror(stream)
tests a flag. This flag may have been set by a prior I/O function call onstream
so thisfgets()
is not necessarily the cause of the error. Best to check the result offgets()
to see if this function failed.If code is to continue using
stream
after an error detected, be sure to clear the error before continuing - like maybe to attempt a re-try.Note that
clearerr()
clears both the error and end-of-file flags.The same applies for
feof()
, yet most code is written to quit usingstream
once an end-of-file is true.There is a 3rd pathological way to receive
NULL
and neitherfeof()
norferror()
returnsNULL
as detailed in Is fgets() returning NULL with a short buffer compliant?. Careful reading of the C spec has 3 "ifs", of which it is possible that not of them are true as so the spec is lacking - which implies UB.