Blythe S.
Blythe S.

Reputation: 11

What alternative can I use instead of gets() and puts()?

Code snippet for gets()

int main(int argc, char *argv[])
{
    char str[MAX_SIZE]
    gets(str);
    printf("\n");

Code snippet for puts()

  printf("The most probable key is: %d\n", max2);
  puts(output);
  return 0;

I did not paste my whole code since it seems pretty irrelevant for my question. I just want to know a way I could fix this because when I run my code through GCC, it gives me errors and is not allowing me to use gets(). How would I fix this?

Upvotes: 1

Views: 2872

Answers (4)

chux
chux

Reputation: 154085

alternative can I use instead of gets()

char str[MAX_SIZE]; gets() has problems when reading a line of N characters. (N also counts the '\n').

  • When N > MAX_SIZE, the result is undefined behavior (UB). Too much input and no place to go. Often this UB writes into places used by other objects. Bad - very bad.

  • C11 eliminated gets() and is not a standard function since then.

The usual fgets() solution is well suggested by @Stephan Lechner. fgets() has some short comings listed below.

  1. str[MAX_SIZE] now needs to be str[MAX_SIZE + 1] as fgets() also saves the '\n', unlike gets(). Sometimes adding + 1 is not practical.

  2. fgets() retains the potential '\n'. See Removing trailing newline character from fgets()

  3. When input is excessive, fgets() simply does not read it, unlike gets(). This is well behaved (not UB) yet we are still stuck with that problem: how to detect excessive input and what to do about it?

If code can live with these, use fgets(). Otherwise, read on.


mygets() alternative

This function does not need a +1 to the size of the s buffer.

Excessively long input returns NULL. All the line is read. The s buffer is filled with the initial characters.

char *mygets(char *s, size_t n) {
  char *dest = s;

  // Pathological case of n==0
  char dummy[1];
  if (n == 0) {
    n = sizeof dummy;
    dest = dummy;
  }

  size_t i = 0;
  int ch;
  n--;
  while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
    if (i < n) {
      dest[i++] = (char) ch;
    } else {
      s = NULL; // Not enough room
    }
  }

  if (ch == EOF) {
    if (feof(stdin)) {  // end-of-file
      if (i == 0) {
        s = NULL;
      }
    } else { // input error
      i = 0;
      s = NULL;
    }
  }

  dest[i] = '\0';
  return s;
}

Subtle bonuses:

  • s buffer is well defined on rare input error. With gets/fgets buffer contents are then undefined.

  • Pathological size of 0 is well defined. fgets() is a bit iffy on that.

  • Buffer size is the idiomatic size_t rather than int as with fgets().


Usage

str[MAX_SIZE];

if (mygets(str, sizeof str)) {
  printf("Success <%s>\n", str);
} else {
  if (feof(str)) printf("End of file detected. <%s>\n", str);
  else if (ferror(str)) printf("End of file detected.  <%s>\n", str);
  else printf("Input too long <%s>.", str);
}

Upvotes: 0

Mayur
Mayur

Reputation: 2731

Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security.
Use fgets() instead
char * fgets ( char * str, int num, FILE * stream );

The following example shows the usage of fgets() function.

#include <stdio.h>

int main () {
   FILE *fp;
   char str[60];

   /* opening file for reading */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* writing content to stdout */
      puts(str);
   }
   fclose(fp);

   return(0);
}

Upvotes: 1

Stephan Lechner
Stephan Lechner

Reputation: 35154

Use fgets and fputs instead. There is - beside removing all the flaws of gets- also a main difference in the usage between gets and fgets: fgets stores a new line character in the buffer (and gets does not).

So an equivalent - i.e. eliminating any new line if not desired - could look as follows. Function call strcspn(buffer,"\n") gives the longest sequence of characters until a new line is encountered (or strlen(buffer), if the string does not contain a new line). By writing a 0 to the index at this position a new line - if any - is eliminated.

char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
  buffer[strcspn(buffer,"\n")] = '\0';
}

Upvotes: 4

Sourav Ghosh
Sourav Ghosh

Reputation: 134366

You should absolutely, positively avoid using gets(), its dangerous and removed from the recent C standard. That's why you see the warning

C11, Foreword, Paragraph 6 mentions

Major changes from the previous edition include:

[....]

  • removed the gets function (<stdio.h>)

Instead, use fgets().


To add, puts() is just fine, I see no reason for replacing that one.

Upvotes: 3

Related Questions