0

I have tried to use gets() library function in C and found that printf() statement output is delayed and got displayed after gets() receiving the input from stdin (i.e. from keyboard). Please check below C code and its output.

 #include<stdio.h>
 #include<stdlib.h>
 int main()
 {
    int n, i, j;
    char ch, *str;

    printf("Enter size of input:\n");
    scanf("%d\n", &n);

    str = (char *) malloc(sizeof(char) * n);
    printf("Enter input string: \n");
    gets(str);

    printf("Given input string is : %s\n", str);
    return 0;
 }

Output:

Enter size of input: 9

R Raj Kumar <-- This name is given from input since program is waiting for input for gets() function even though printf("Enter input string\n") is present before gets() and printf() statement is not displayed on the console. It is getting printed after receiving gets() input from console.

Enter input string:

Given input string is : R Raj Kumar

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Raj
  • 1,013
  • 2
  • 11
  • 23
  • 6
    The input is far bigger than you say, so UB ensues. `gets` is deprecated for a reason. – Deduplicator Nov 11 '16 at 14:02
  • The function `gets` is obsolete, please switch to `fgets` soon as. – Weather Vane Nov 11 '16 at 14:04
  • 2
    You should [never, ever use `gets()`](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) for the reasons described in the linked Q&A. – Jonathan Leffler Nov 11 '16 at 14:08
  • Thanks for quick replies. I want to read a string from console which may have spaces and the length of the string is not known at the compile time. Hence, I used gets() function (which considers spaces as well) and dynamic memory allocation for 'str ' variable. Please let me know if any other library function can be used to read a string value which satisfies my requirement here. – Raj Nov 11 '16 at 14:10
  • 2
    The `'\n'` in `scanf("%d\n", &n);` "delays". `scanf("%d\n", &n)` does not return until non-white- space is entered after the number. @JonathanLeffler Disagree that the posted dupe is a good explanation of this - which is the first of many problems with this code. – chux - Reinstate Monica Nov 11 '16 at 14:17
  • If you want to read a string of any length, `malloc` some memory first and use `fgets` to get the input. Now, `fgets` retains the `newline` you typed, at the end of the string, so if the input string does not contain such a `newline` you know there is more data to come. So you `realloc` a larger memory space, and repeat, until the input contains said `newline` (or `fgets` fails). But you must not mix `scanf("%d",...)` with `fgets` - instead use `fgets` followed by `sscanf`. – Weather Vane Nov 11 '16 at 14:19
  • 1
    @chux: I agree with your disagreement...it's the wrong dup, but it is a dup. I missed the trailing white space in the format string. – Jonathan Leffler Nov 11 '16 at 14:22
  • @chux: One alternative from 2013 (I suspect there are earlier ones, but this is one possibility): [`scanf` asking twice for input while I expect to ask only one](http://stackoverflow.com/questions/15740024/scanf-asking-twice-for-input-while-i-expect-it-to-ask-only-one/) – Jonathan Leffler Nov 11 '16 at 14:27
  • Below is the output when I use fgets() function: Enter size of input: 13 R Raj Kumar Enter input string: Given input string is : R Raj Kumar I am able to read a string of required size, but the issue is same. I have removed unused variables i, j, and ch in my code. printf("Enter input string: \n") is not getting displayed at right place. I need to print this statement just before giving input from console. – Raj Nov 11 '16 at 14:28
  • 1
    The problem is the trailing `\n` in the `scanf()` format `"%d\n"` as chux said. Remove it. Then add a 'gobble' loop: `int ch; while ((ch = getchar()) != EOF && ch != '\n') ;` (empty loop body). That reads the trailing newline. – Jonathan Leffler Nov 11 '16 at 14:35
  • @JonathanLeffler: The solution worked perfectly. But, is it a right solution for this problem ? Do I need to add the same while loop code, wherever scanf() and fgets() (or any string/char read function) used together ? – Raj Nov 11 '16 at 14:44
  • [Don't cast the result of malloc in C](http://stackoverflow.com/q/605845/995714) – phuclv Nov 11 '16 at 14:44
  • 1
    It is one of the correct and standard ways to deal with the issue of `scanf()` leaving newlines (and trailing blanks, or non-digits after the digits) on the input line. Alternatively, and very often, it is better to read lines only (all input with `fgets()`) and then parse the strings with `sscanf()`. This has advantages, not least that if the first attempt at parsing doesn't work, you can have another go with a different format, and you can report the whole line of data in the error messages. – Jonathan Leffler Nov 11 '16 at 14:48
  • Your input, by my count, is at least 12 characters long, you're passing in 9 as size. You're not allocating enough memory... you need enough space to store `R[space]Raj[space]Kumar\0` -> 12 `char`s – Elias Van Ootegem Nov 11 '16 at 15:19
  • Hi Elias Van Ootegem, my query here is that why console is waiting for input from user without displaying the printf() statement as explained in the description. See, there is a printf("Enter input string:"); just before gets() call, but this print is not getting displayed and the console is waiting for user input string. Once I entered the string, both printf() statements are getting displayed. – Raj Jan 20 '17 at 10:37

2 Answers2

1

When you use gets(...) you need to have a buffer large enough to hold the input. Your input has 9 printed characters, but the actual input also has 2 spaces, and a terminating null character, so the size of your input is actually 12.

You have designed your program such that it is trivial to perform a buffer overflow. I suggest you read upon buffer overflows now, and learn to program defensively, avoiding buffer overflows.

Even if you are in a rush, reading up on how to avoid buffer overflows will save you time. The costs to fix a buffer overflow add up quickly, and far outweigh the time spent learning to avoid them.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
0

I have made changes in my program based on the comments/suggestions here. Below is the program that gives the right & desired output

Program:

#include<stdio.h>
 #include<stdlib.h>
 int main()
 {
    int n;
    char ch, *str;

    printf("Enter size of input:\n");
    scanf("%d", &n);

    while ((ch = getchar()) != EOF && ch != '\n');

    str = (char *) malloc(sizeof(char) * n);
    printf("Enter input string: ");
    fgets(str, n, stdin);

    printf("Given input string is : %s\n", str);
    return 0;
 }

Output:

Enter size of input: 9

Enter input string: R Raj Kumar

Given input string is: R Raj Ku

Raj
  • 1,013
  • 2
  • 11
  • 23