问题
I am using gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
I am writing a very simple script to take string as input and print the same with the some custom message. First user enters the T(no. of times to take string) and then takes input by fgets.
. I used this&this as reference.
I am getting a very strange output ie fgets is adding some extra new lines and even loop is not working properly for T=2 it is asking input only once.
Can anybody explain me what is wrong with snippet. Thanks in advance!
#include<stdio.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[100]={""};
int i;
printf("Hello\n");
fgets(str,80,stdin);
i = strlen(str)-1;
if(str[i]=='\n')
str[i]='\0';
printf("World\n");
printf("%s\n",str);
}
return 0;
}
Please see the image reference for T=2, even T=2 it is taking string only once and order of printing statement is also not as expected.

回答1:
This is because your scanf()
call
scanf("%d",&T);
does not consume the new line character \n
accompanied by your input.
When you input T
, your input is 2Enter.
scanf()
consumes the 2
, sees \n
and stops consuming, leaving \n
in the input buffer.
When the fgets()
gets called, it sees the \n
in the buffer and treats this as the input.
To solve this, you have a few choices (in decreasing order of my subjective preference):
Use
fgets()
to get the first input, then parse it usingstrtol()
to getT
.Add an extra
fgets()
after thescanf()
.Add
getchar()
to consume one extra character. This works if you are certain that exactly one\n
will be present after the input. So for example it won't work if you type 2SpaceEnter. Alternatively, you may usewhile(getchar() != '\n');
after thescanf()
to consume everything up to a new line, but this may cause problems if an empty line is a valid input to your laterfgets()
calls.If your implementation supports it, you may use
fpurge(stdin)
or__fpurge(stdin)
.
And, very importantly, do not use fflush(stdin)
unless your implementation clearly defines its behavior. Otherwise it is undefined behavior. You may refer to this question for more details. Also, note that the fpurge()
and fflush()
methods may not work correctly if your input can be piped into the program.
回答2:
This line
scanf("%d",&T);
reads the input until the first non-numeral is found, which is newline
. Then fgets()
reads that newline for its first input.
I suggest using fgets()
to read the number too.
fgets(str,80,stdin);
sscanf(str, "%d", &T);
回答3:
With your first call to scanf you allow the user to input an integer for the number of loops. They do so, and use a carriage return to signal the end of input. At this point scanf reads the integer, but leaves the end-of-line (\n) in the stream..
So when you call fgets, fgets gets from the stream until it reaches the first newline -- in you code, on the first loop, this is the very first character it encounters.
If you discard the newline before calling fgets, you should get your desired results. You can do this, for example by changing your first three lines to:
int T;
char newline;
scanf("%d%c",&T, &newline);
Although there are probably stylistically superior ways of doing this.
回答4:
You have a newline character in the input stream when you press "enter" after typing 2 for the first scanf. This is consumed by fgets() initially, hence it prints nothing (You replace the newline by
\0
).In the next line, your input is read and echoed after
World
because you are printing it after it.
来源:https://stackoverflow.com/questions/30697465/how-fget-works