Why is the fgets function deprecated?
Solution 1
No, fgets
is not actually deprecated in C99 or the current standard, C11. But the author of that tutorial is right that fgets
will not stop when it encounters a NUL, and has no mechanism for reporting its reading of such a character.
The
fgets
function reads at most one less than the number of characters specified byn
from the stream pointed to bystream
into the array pointed to bys
. No additional characters are read after a new-line character (which is retained) or after end-of-file.
(§7.21.7.2)
GNU's getdelim
and getline
have been standardized in POSIX 2008, so if you're targeting a POSIX platform, then it might not be a bad idea to use those instead.
EDIT I thought there was absolutely no safe way to use fgets
in the face of NUL characters, but R.. (see comments) pointed out there is:
char buf[256];
memset(buf, '\n', sizeof(buf)); // fgets will never write a newline
fgets(buf, sizeof(buf), fp);
Now look for the last non-\n
character in buf
. I wouldn't actually recommend this kludge, though.
Solution 2
This is just GNU propaganda. In no official sense is fgets
deprecated. gets
however is dangerous and deprecated.
Comments
-
Vilhelm Gray about 2 years
From The GNU C Programming Tutorial:
The
fgets
("file get string") function is similar to the gets function. This function is deprecated -- that means it is obsolete and it is strongly suggested you do not use it -- because it is dangerous. It is dangerous because if the input data contains a null character, you can't tell. Don't usefgets
unless you know the data cannot contain a null. Don't use it to read files edited by the user because, if the user inserts a null character, you should either handle it properly or print a clear error message. Always usegetline
orgetdelim
instead offgets
if you can.I thought the
fgets
function stops when it encounters a\0
or\n
; why does this manual page suggest a null byte is "dangerous" whenfgets
should handle the input properly? Furthermore, what is the difference betweengetline
andfgets
, and is thefgets
function truly considered deprecated in the C99 or future C standards? -
Vilhelm Gray about 11 yearsSo
fgets
keeps reading past null bytes, searching just for the newline character? -
Fred Foo about 11 years@VilhelmGray: that's right, and it won't tell you it did. There's no way to be sure that the first '\0' you find was added by
fgets
or not. -
pmg about 11 yearsnull bytes do not belong in text files.
fgets()
was designed to work with text files: usingfgets()
with files of binary data is not recommended. -
Fred Foo about 11 years@pmg: they might wind up in text files by accident, and it would be nice if
stdio
were more robust against such errors (it should at least report them, but it doesn't). -
Vilhelm Gray about 11 yearsI wonder why
fgets
wasn't designed to return the number of bytes read. -
Fred Foo about 11 years@VilhelmGray:
stdio
tends to trust the user too much -- it just doesn't anticipate long lines, null characters in text files, etc. It's from the 1970s, when defensive programming wasn't deemed as important as it is now (no internet, no script kiddies trying to break into your system, no noob users that will spam you when they screw up a text file). -
Keith Thompson about 11 years
gets
was actually removed from the 2011 ISO C standard. (It was not officially deprecated or obsolescent in C99.) -
R.. GitHub STOP HELPING ICE about 11 years@larsman: Actually you can know if you pre-fill the buffer right.
-
Fred Foo about 11 years@R..: how? By filling it with
\n
then searching for the last non-newline? -
R.. GitHub STOP HELPING ICE about 11 yearsYep, if you pre-fill the buffer with
'\n'
then you can search for the first newline; if it's followed by a 0 byte, that newline was the last read byte. Otherwise, the byte before that newline was the last read byte. -
Fred Foo about 11 years@R..: I'd rather reimplement
fgets
with a saner interface than do that, but I'll edit my answer. -
R.. GitHub STOP HELPING ICE about 11 yearsThe only way to reimplement
fgets
is by repeatedly callinggetc
, which will be many times slower than the trick I just described. -
Fred Foo about 11 years@R..: probably, but when I/O is not the bottleneck I prefer my code clean.
-
R.. GitHub STOP HELPING ICE about 11 yearsYes I would not do that inline in other code but as a function it's reasonable.
-
CB Bailey almost 11 years@KeithThompson: Section 7.26.9 of ISO/IEC 9899:1999 TC3 says "The
gets
function is obsolescent, and is deprecated." so I believe thatgets
was officially deprecated in C99. -
R.. GitHub STOP HELPING ICE almost 11 yearsWas that language added in one of the TC's, or was it in the original publication of C99?
-
Keith Thompson almost 11 years@R..: It was added by TC3.
-
chux - Reinstate Monica over 7 years
// fgets will never write a newline
comment is unclear. Certainly a'\n'
is written to the buffer on manyfgets()
calls. Did you mean// fgets will never read after a newline
? -
chux - Reinstate Monica over 7 years
memset(buf, '\n', sizeof(buf)); fgets(buf, sizeof(buf), fp);
is good except for a) The C spec is weak/inadequate on the stability of contents after the appended null character, so searching from the end is on thin ice. Searching from the beginning past a null character is of similar concern. b) When an input error occurs - buffer is explicitly undefined - of course, no need to read the buffer then.