Question

Does fgets() always terminate the char buffer with \0 even if EOF is already reached? It looks like it does (it certainly does in the implementation presented in the ANSI K&R book), but I thought I would ask to be sure.

I guess this question applies to other similar functions such as gets().

EDIT: I know that \0 is appended during "normal" circumstances, my question is targeted at EOF or error conditions. For example:

FILE *fp;
char b[128];
/* ... */
if (feof(fp)) {
    /* is \0 appended after EACH of these calls? */
    fgets(b, 128, fp);
    fgets(b, 128, fp);
    fgets(b, 128, fp);
}
Was it helpful?

Solution

Never use gets!!

    7.19.7.2 The fgets function
    Synopsis
1           #include <stdio.h>
            char *fgets(char * restrict s, int n,
                 FILE * restrict stream);
    Description
2   The fgets function reads at most one less than the number of characters
    specified by n from the stream pointed to by stream into the array pointed
    to by s. No additional characters are read after a new-line character
    (which is retained) or after end-of-file. A null character is written
    immediately after the last character read into the array.
    Returns
3   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.

So, yes, when fgets() does not return NULL the destination array always has a null character.

If fgets() returns NULL, the destination array may have been changed and may not have a null character. Never rely on the array after getting NULL from fgets().


Edit example added

$ cat fgets_error.c
#include <stdio.h>

void print_buf(char *buf, size_t len) {
  int k;
  printf("%02X", buf[0]);
  for (k=1; k<len; k++) printf(" %02X", buf[k]);
}

int main(void) {
  char buf[3] = {1, 1, 1};
  char *r;

  printf("Enter CTRL+D: ");
  fflush(stdout);
  r = fgets(buf, sizeof buf, stdin);
  printf("\nfgets returned %p, buf has [", (void*)r);
  print_buf(buf, sizeof buf);
  printf("]\n");

  return 0;
}
$ ./a.out
Enter CTRL+D:
fgets returned (nil), buf has [01 01 01]
$

See? no NUL in buf :)

OTHER TIPS

fgets does always add a '\0' to the read buffer, it reads at most size - 1 characters from the stream (size being the second parameter) because of this.

Never use gets as you can never guarantee that it won't overflow any buffer that you give it, so while it technically does always terminate the read string this doesn't actually help.

man fgets:

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a new‐line is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer.

If you did open the file in binary mode "rb", and if you want to read Text line by line by using fgets you can use the following code to protect your software of loosing text, if by a mistake the text contained a '\0' byte. But finally like the others mentioned, normally you should not use fgets if the stream contains '\0'.


size_t filepos=ftell(stream);
fgets(buffer, buffersize, stream);
len=strlen(buffer);
/* now check for > len+1 since no problem if the 
   last byte is 0 */
if(ftell(stream)-filepos > len+1) 
{
    if(!len) filepos++;
    if(!fseek(stream, filepos, SEEK_SET) && len)
    {
        fread(buffer, 1, len, stream);
        buffer[len]='\0';
    }
}

Yes it does. From CPlusPlus.com

Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or a the End-of-File is reached, whichever comes first.

A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str.

A null character is automatically appended in str after the characters read to signal the end of the C string.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top