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
.
int len= strlen(input_buffer);
will give you that. – Ligurianfgets()
, I preferfread()
but it doesn't handle locale. – Maddenstrlen
will do the trick, but is there any solution that doesn't involve O(n) iteration? Seems wasteful that you have to figure it out again whenfgets
already knows what the length is. – Sheolfread()
does not NUL terminate the input, butfgets()
does. Sostrlen()
works forfgets()
but not forfread()
. Each function has its' purpose and capabilities. the functionfgets()
is written so it can be 'chained' The function:fread()
is not. the function:fgets()
is for text input. the function:fread()
is for binary input. – Cismontaneint
type of size argument offgets()
, I don't like to need to usestrlen()
to know the size of my string.getline()
is so mush better but posix,fread()
don't add nul byte but you can do it easilly. Like I sayfread()
isn't equal tofgets()
locale, nul byte etc... but it has a better design. – Madden