Never use the function gets . Why? It is unsafe. Since the maximum string size cannot be specified, it is always susceptible to buffer overflow.

This snippet shows one way to do a safe version of gets . It reads characters from the stdin into a string up to the specified size and discards the trailing newline. It does not remove excess characters from the stdin either.

See also Read a Line of Text from the User.

#include <stdio.h>

char *sgets(char *line, size_t size)
   size_t i;
   for ( i = 0; i < size - 1; ++i )
      int ch = fgetc(stdin);
      if ( ch == '\n' || ch == EOF )
      line[i] = ch;
   line[i] = '\0';
   return line;

int main(void)
   int i;
   for ( i = 0; i < 3; ++i )
      char text[20] = "";
      fputs("prompt: ", stdout);
      printf("text = \"%s\"\n", sgets(text, sizeof text));
   return 0;

/* my input/output
prompt: 1234567890123456789012345
text = "1234567890123456789"
prompt: text = "012345"
prompt: hello world
text = "hello world"
11 Years
Discussion Span
Last Post by Narue

Could you instead just use fscanf with a formatted string which includes the max number of characters to be read? For example, with an 8 char buffer this would be

int found = fscanf(stdin, "%7[^\n]\n" buffer);


You could, but a real programmer wouldn't use scanf() or fscanf() to read strings in the first place. Dave's suggestion is the second best choice. Best is to use fgets()


why is scanf() unreliable and unwanted?

scanf can be reliable when used correctly, but it's typically unwanted for string input because achieving reliability in that case is more difficult than simply using a more appropriate function. For example, here is fgets simulated using fscanf:

char *myfgets(char *dst, size_t limit, FILE *in)
    char fmt[50]; /* Arbitrary "big" size; laziness FTW */
    int len;

    /* Necessary to set a variable-based field width */
    sprintf(fmt, "%%%d[^\n]%%n", limit - 1);

    if (fscanf(in, fmt, dst, &len) != 1)
        return NULL;

    /* Is the buffer full? */
    if (len < limit - 1)
        /* Extract and store the newline */
        dst[len++] = getc(in);
        dst[len] = '\0';

    return dst;

On top of a relatively complex format string, the format string needs to be generated using sprintf to avoid using a magic number in many cases and because the magic number is pretty much impossible in this case (the limit is an unknown quantity by myfgets until runtime).

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.