1

While reading the C99 draft ISO/IEC 9899:TC2 WG14/N1124, I stumbled upon some statements that worries me:

Is the string/buffer given to fgets also guaranteed to be null terminated if fgets returns NULL?

§7.19.7.2 states in the description

A null character is written immediately after the last character read into the array.

But under return:

If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.

So the last statement implies in my interpretation that this guarantee is not given in any NULL-returning case. I'm already about to correct http://en.cppreference.com, since they are using errno, which fgets isn't obliged to set. But I'm not sure if I maybe misinterpret this.

Superlokkus
  • 4,731
  • 1
  • 25
  • 57
  • I understand that it would not be possible to verify the buffer as null-terminated in the NULL-returning case. If there's any doubt, just don't count on having that handy trailing zero. ;-) – owacoder Mar 08 '16 at 13:15
  • 2
    Since there was no character read into the array, how can a `null` character be written after it? – Weather Vane Mar 08 '16 at 13:16
  • "*I'm already about to correct ...*" why, what? – alk Mar 08 '16 at 13:16
  • 4
    "If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned." sounds pretty clear to me. The content of the buffer is **indeterminate** period. – Jabberwocky Mar 08 '16 at 13:17
  • Maybe I should ask this as a wiki question?! I was hoping someone could post an answer with some further references that prevent this possible misinterpretation. – Superlokkus Mar 08 '16 at 13:23
  • @alk See http://en.cppreference.com/mwiki/index.php?title=c%2Fio%2Ffgets&diff=83790&oldid=78932 – Superlokkus Mar 08 '16 at 13:32
  • I see. However, if referring to a Standard, I'd refer to C11: http://www.iso-9899.info/n1570.html#7.21.7.2 – alk Mar 08 '16 at 13:41
  • But I see no reference to `errno`, neither in the Standard C99 version, nor in C11. – alk Mar 08 '16 at 13:42
  • Notes about `fgets(char *s, int n, FILE *stream);` `s` may contain more than 1 null character, ones that are read and the final appended one. A null character should not be expected in pathological cases when `n <= 0`. When `n==1` is also program case too. – chux - Reinstate Monica Mar 08 '16 at 14:49

1 Answers1

3

You interpret the standard correctly. In case there are errors, the function will return NULL and the contents of the buffer are not to be trusted.

This allows fgets to read straight into the target buffer without any double buffer in between. So upon error half-ways through the expected data, it may simply stop and return NULL.

Also note this special case (7.21.7.2):

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • So if the buffer was null terminated before, it's stays that way, if also `feof` returned nonzero? (Sorry I've edited my question right in the moment you posted your answer) – Superlokkus Mar 08 '16 at 13:42
  • 1
    @Superlokkus If the stream is checked with `feof` before the call to `fgets` and `fgets` encounters an error, then the contents of the buffer is indeterminate. Imagine this scenario: your buffer contains the text "hi", that is the 3 characters: `{'h','i','\0'}` followed by any random garbage. You then tell fgets to read 10 characters and overwrite the buffer, but after 5 there is an error. The buffer might at that point contain something like `{'a','b','c','d','e', }`. The `\0` has been overwritten. Indeterminate means that the data has turned into garbage and shouldn't be used. – Lundin Mar 08 '16 at 13:51
  • OK, but I guess it would be still null terminated if some additional conditions are true, like *the last character at least was already \0* or the count to fgets is >= than the times before etc. But I guess that many preconditions would just clutter up your answers and my question. – Superlokkus Mar 08 '16 at 14:02
  • 2
    @Superlokkus Indeterminate value means that if you try to use the value for any purpose, you invoke undefined behavior. So upon error, `fgets` could as well write the string "nonsense" into the buffer and then return NULL, and it would still be strictly conforming as far as the C standard is concerned. – Lundin Mar 08 '16 at 14:23
  • I thought that the special case you mentioned implies that if EOF is encountered, I could still use it, even though NULL is returned. But I overlooked the also possible scenario of feof() && ferror(). Thanks for the clarifikation. – Superlokkus Mar 08 '16 at 14:32
  • @Superlokkus You can't know why it returned NULL unless you call `feof`. But the special case only applies when it has not read any characters yet, so that case is probably of rather mild interest. – Lundin Mar 08 '16 at 14:37
  • 1
    For completeness, you may be interesting is a [3rd reason](http://stackoverflow.com/q/23388620/2410359) `fgets()` may return `NULL`. – chux - Reinstate Monica Mar 08 '16 at 15:00