Search code examples
cfgets

Does fgets() always terminate the char buffer with \0?


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);
}

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 :)