5

I am new in C. And I found some problem in puts and printf of C.

char str[10];
printf("Input a string.\n");
gets(str);
printf("The string you input is: %s",str);

The output is these if I put more than 10 char

1ang:lab lang$ ./exercise 
Input a string.
warning: this program uses gets(), which is unsafe.
0123456789
Abort trap: 6

But when I add \n at the end of printf, printf("The string you input is: %s\n",str); the output is different.

1ang:lab lang$ ./exercise 
Input a string.
warning: this program uses gets(), which is unsafe.
0123456789
The string you input is: 0123456789
Abort trap: 6

It will first print the string and then occur the error. Could someone explain it?

Dummy00001
  • 16,630
  • 5
  • 41
  • 63
1ang
  • 321
  • 2
  • 3
  • 11
  • 4
    'gets()' is deprecated, use fgets() instead. – tigris Feb 23 '16 at 11:21
  • 5
    No - we don't explain UB here. – Martin James Feb 23 '16 at 11:22
  • I'm pretty sure it's a buffering issue. Try using another `printf("\n") ` after the one with %s. And try to avoid gets, as it's unsave, as your libc suggest. – Marandil Feb 23 '16 at 11:24
  • 1
    Note that 'char str[10]' is too small even for "0123456789" – Martin James Feb 23 '16 at 11:25
  • 2
    An Undefined Behaviour can not be explained. Its just Undefined. Use `fgets` instead of `gets`. – SKD Feb 23 '16 at 11:29
  • @MartinJames I know that, I just tried to break down the code – 1ang Feb 23 '16 at 11:29
  • `gets` has been removed from the C language, so the code doesn't compile. If you are writing code for an old version of the C standard, you should tag your question C90 or C99. I'm curious why you are learning old versions of C instead of learning ISO standard C. – Lundin Feb 23 '16 at 12:00
  • Even your executable yelling not to use `gets()`, so I would really be concerned about it in the first place! – fnisi Feb 23 '16 at 21:11

4 Answers4

7

You didn't reserve enough space for your string.

Remember that you need an extra element for the null-terminator (\0) that gets added to an array of characters. str[10] is not big enough.

Since the str argument to printf doesn't contain a \0, it overruns the buffer with undefined results.

One way round this is to consider using fgets instead. In its current form, but even reserving enough memory for your test string, you can easily supply a longer one which will again crash your program.

Also, consider appending \n to your printf string: this newline character flushes the output buffer, which will help timely writeback to your console.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

gets is unsafe, in your code, I think it overwrite a part of your stack, maybe the return pointer register (I'am not sure of the name).

Now, why do you have a message in a case, and not in another?

Because printing "\n" in printf will force a flush of what have been bufferized so far.

In first case, the crash occurs before the text have been displayed on your console, but if you use a debugger, will see that it occurs at the same point.

Mathieu
  • 8,840
  • 7
  • 32
  • 45
1

Your compiler told you, "warning: this program usesgets(), which is unsafe." but you went ahead anyway. Then you read enough data to overflow your array, presumably corrupting other storage.

What happens next is undefined behaviour, and so anything can happen. In your case, it appears that the printf succeeds, but the corruption causes later code (perhaps the return from the function) to crash. If you flushed stdout (which happens implicitly when you print \n if stdout is a terminal), then you will see the output. If you didn't, the buffered output is lost when the process is destroyed.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
0

What you have there is a great example of undefined behavior. It is not definied what happens if you exceed the bufferd size of an array. As others have pointed out you realy should not use gets. The function is not considered deprecated for no reason. Better use fgets or fscanf.

I would also recommend you to write a "safe" input function using the return value of scanf. Or you could use a combination of fgets and sscanf to read whole lines from the input and manipulate the read string afterwards using sscanf as in this answer.

Community
  • 1
  • 1
muXXmit2X
  • 2,745
  • 3
  • 17
  • 34