Very strange error regarding gets(string)

113 views Asked by At
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
   int a;
   char c[1];
   printf("\n%d\n", a);
   gets(c);
   printf("\n%d\n", a);
   return 0;
}

When reading c using gets the value of a, printed previously, is printed as having the value: 0; when using scanf("%c", &c); as a replacement for gets(c); the value of a stays the same throughout the code.

I can't seem to figure out why this is, could someone please explain how this is possible?

4

There are 4 answers

1
John Bode On

Just to get this out of the way, NEVER NEVER NEVER NEVER use gets: it will introduce a point of failure in your program. It was deprecated in the C99 standard and has been removed from the C2011 standard. It is evil.

Having said all that, let's walk through all the issues in your code.

Remember that in C a string is a sequence of characters terminated by a 0-valued byte. This means that to store an N-character string, you must set aside N+1 char elements of storage. Your c array is sized to hold 1 element, meaning the only string it can store is the empty string.

The problem with gets is that it doesn't know how big the target buffer is; when you pass an array as a parameter, all the called function receives is a pointer to the first element. If you type in 10 non-whitespace characters, or 100, or 1000, gets will happily store the excess to the memory immediately following your array; this is why your a variable gets overwritten. This is also why gets has finally been removed from the language standard; that behavior enabled a lot of malware exploits.

The reason your scanf call didn't cause a problem is because you used the %c conversion specifier, which only reads a single character from the input stream. Had you used the %s conversion specifier, you would have seen the same result as you did with the gets call.

So, you need to do two things: first, you need to declare c to be large enough to hold the largest string you expect plus 1 for the 0 terminator:

#define MAX_SIZE 10 // or however large the string needs to be
...
char c[MAX_SIZE+1];

then you need to use fgets to read the input:

if ( fgets( c, sizeof c, stdin ) != NULL )
{
  // work with c
}
0
chux - Reinstate Monica On

You only have room for \0 in the string a and gets() does not care that there is not enough room. It evidently overwrote parts of memory resulting in your problem. Instead of gets(), use fgets().

char c[100];
if (fgets(c, sizeof c, stdin) == NULL) Handle_EOForIOError();
size_t len = strlen(c);
if (len && c[len-1] == '\n') c[--len] = '\0';

C standard (2011) has removed gets()from its specification.


OP: ... when using scanf("%c",&c); as a replacement for gets(c); the value of a stays the same throughout the code.

This is good as scanf("%c",&c); should not affect a.

If you are hoping for some overwriting of a due to a small c by using gets(c);, you may try char c[1]; int a;, but any such code invokes undefined behavior.

1
TypeIA On

You are probably experiencing stack corruption. gets() writes input characters to the memory address you passed in (a pointer to the first element of c). However, you only allocated 1 character, which is only enough for an empty string (including the null terminator).

This is why gets() should never be used. It is not safe because it can overwrite the end of its destination array. Use a safer function instead, like fgets().

2
haccks On

You program is invoking undefined behavior
1. unless you are not passing an empty string (\n).
2. as a is uninitialized.

In this this case anything could happen. You may get the expected or unexpected result, segmentation fault and even the program crash.