This is the description of fgets()
from the man page:
char *fgets(char *s, int size, FILE *stream);
...
RETURN VALUE
fgets() returns s on success, and NULL on error or when end of file
occurs while no characters have been read.
It doesn't follow the pattern of read
, which returns -1 on failure and the number of bytes read on success. Instead, it returns a char*
which is NULL
on failure and s
on success. This doesn't give me any info about how long the input is. So if I have something like this:
char input_buffer[256];
fgets(input_buffer, sizeof(input_buffer), stdin);
After the fgets
call, is there any way to tell how long the input is WITHOUT zero-initializing the buffer first?
Thanks.
How to determine number of characters that were read with fgets()?
char *fgets(char *s, int size, FILE *stream);
Use strlen(s)
after checking the fgets()
return value.
if (fgets(s, size, stream)) {
printf("number of characters that were read: %zu\n", strlen(s));
} else if (feof(stream)) {
printf("number of characters that were read:0 End-of-file\n");
} else {
printf("number of characters that were read unknown due to input error\n");
}
This works unless a null character '\0'
is read as strlen()
will encounter that '\0'
before the appended one by the function. In that case, strlen(s)
after fgets()
will report a smaller value.
There are various tricks to pre-fill s
and then call fgets()
, yet it is undefined what happens to the rest of the unread buffer. Other short comings exist.
If null characters as part of a valid input stream are a concern, use fgetc()
or something like getline()
.
A common scenario where null characters are text is when text is encoded as UTF-16. Of course code should not use fgets()
to read that text, yet that requires prior knowledge. Much code that reads text has failed in mysterious ways due to the incorrect assumption that a text file is a non-null character text file.
Further, even with a text file supposedly lacking a null characters, what happens with the following code?
if (fgets(s, size, stream)) {
size_t len = strlen(s);
s[--len] = '\0'; // poor way to lop off the trailing \n, this could be UB
}
Such code invokes undefined behavior with a hacker exploit: slipping a null character in the file at the beginning of the line. (See this and this for better solutions to lop off the potential \n
)
Robust code does not assume the text is well formed and takes measures to detect abnormalities.
Pedantic note: there are pathological problems with fgets(char *s, int size, FILE *stream);
with a size < 2
.