Difference between fgets and gets

2019-02-27 05:11发布

问题:

What is the difference between fgets() and gets()?

I am trying break my loop when the user hits just "enter". It's working well with gets(), but I don't want to use gets(). I tried with fgets() and scanf() but I don't have the same results as with gets(). fgets() breaks the loop whatever user enters in text! Here is my code :

void enter(void)
{
  int i,

  for(i=top; i<MAX; i++)
    {
      printf(".> Enter name (ENTER to quit): ");
      gets(cat[i].name);

      if(!*cat[i].name)
         break;

      printf(".> Enter Last Name: ");
      scanf("%s",cat[i].lastname);
      printf(".> Enter Phone Number: ");
      scanf("%s",cat[i].phonenum);
      printf(".> Enter e-Mail: ");
      scanf("%s",cat[i].info.mail);
      printf(".> Enter Address: ");
      scanf("%s",cat[i].info.address);
      printf("\n");
    }
  top = i;
}

回答1:

Drop gets() and scanf().
Create a helper function to handle and qualify user input.

// Helper function that strips off _potential_ \n
char *read1line(const char * prompt, char *dest, sizeof size) {
  fputs(prompt, stdout);
  char buf[100];
  *dest = '\0';
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    return NULL;  // EOF or I/O error
  }
  // Remove potential \n
  size_t len = strlen(buf);
  if (len > 0 && buf[len-1] == '\n') {
    buf[--len] = `\0`;
  }
  // Line is empty or too long
  if (len == 0 || len >= size) return NULL;
  return memcpy(dest, buf, len+1);
}

void enter(void)
{
  int i;

  for(i=top; i<MAX; i++)
    {
      if (read1line(".> Enter name (ENTER to quit): ", 
          cat[i].name, sizeof cat[i].name) == NULL) break;
      if (read1line(".> Enter Last Name: ", 
          cat[i].lastname, sizeof cat[i].lastname) == NULL) break;
      if (read1line(".> Enter Phone Number: ", 
          cat[i].phonenum, sizeof cat[i].phonenum) == NULL) break;
      if (read1line(".> Enter e-Mail: ", 
          cat[i].info.mail, sizeof cat[i].info.mail) == NULL) break;
      if (read1line(".> Enter Address: ", 
          cat[i].info.address, sizeof cat[i].info.address) == NULL) break;
    }
  top = i;
}

Some attributes of fgets() and gets():

fgets() reads input and saves to a buffer until:
1) The buffer is 1 shy of being full - or -
2) '\n' is encountered - or -
3) The stream reaches an end-of-file condition - or -
4) An input error occurs.

gets() does #2 - #4 above except it scans, but does not save a '\n'.
gets() is depreciated in C99 and no longer part of C11.



回答2:

A difference between gets() and fgets() is that fgets() leaves the newline in the buffer. So instead of checking whether the first element of the input is 0, check whether it's '\n';

fgets(cat[i].name, sizeof cat[i].name, stdin);
if (cat[i].name[0] == '\n' || cat[i].name[0] == 0) {
    // empty line or no input at all
    break;
} else {
    // remove the trailing newline
    int len = strlen(cat[i].name);
    cat[i].name[len-1] = 0;
}


回答3:

The problematic difference between gets and fgets is that gets removes the trailing '\n' from an input line but fgets keeps it.

This means an 'empty' line returned by fgets will actually be the string "\n".

The nasty difference, that means it's best to avoid gets altogether, is that if you give gets a line that's too long your program will crash in very bad ways.



回答4:

you can use fgets() with STDIN instead. This function is secured and always insert a '\0' at the string end.

An example:

char inputbuffer[10];
char *p;
p = fgets(inputbuffer, sizeof(inputbuffer), stdin);
printf(">%s<\n", p);    /* p is NULL on error, but printf is fair */

You'll get at most 9 characters + '\0', in this example.



标签: c scanf fgets gets