pureofpure
pureofpure

Reputation: 1090

Difference between fgets and gets

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

Upvotes: 5

Views: 12213

Answers (4)

chux
chux

Reputation: 154218

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.

Upvotes: 3

Barmar
Barmar

Reputation: 782407

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

Upvotes: 4

levif
levif

Reputation: 2176

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.

Upvotes: 0

user3710044
user3710044

Reputation: 2334

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.

Upvotes: 0

Related Questions