Program doesn't execute gets() after scanf(), even using fflush(stdin) - c

After wasting too much time searching why my program doesn't execute gets() after using scanf(), I found a solution which is to use fflush(stdin) after scanf() to enable gets() to get a string.
The problem is that fflush(stdin) doesn't do what is expected from it: The program continues skipping gets() and I can't write any phrase in the console to be read.
My code is the next one:
#include <string.h>
#include <stdio.h>
int main(){
char nombre[10];
char mensaje[80];
printf("Type your name:\n");
scanf("%s", nombre);
fflush(stdin);
printf("Now, type a message:\n");
gets(mensaje);
printf("3/%s:%s",nombre,mensaje);
return 0;
}

If flushing std doesn't work, then try reading in the extra characters and discarding, as suggested here.
This will work:
#include <string.h>
#include <stdio.h>
int main(){
char nombre[10];
char mensaje[80];
int c;
printf("Type your name:\n");
scanf("%9s", nombre);
while((c= getchar()) != '\n' && c != EOF)
/* discard */ ;
printf("Now, type a message:\n");
gets(mensaje);
printf("%s:%s",nombre,mensaje);
return 0;
}

Two big, major issues:
DO NOT USE fflush ON INPUT STREAMS; the behavior of fflush on input streams is not defined. Just because it appears to work in this situation does not mean it is correct.
NEVER NEVER NEVER NEVER NEVER NEVER NEVER use gets - it was deprecated in the C99 standard and has been removed completely from the C2011 standard. It will (not might, will) introduce a major point of failure in your code.
It's never a good idea to follow a scanf call with a gets call, since gets won't skip over any leading newlines left in the input stream by scanf. Use scanf to read both nombre and mesaje.
printf("Type your name:\n");
scanf("%9s", nombre);
printf("Now, type a message:\n");
scanf("%79s", mensaje);
It's a good idea to use an explicit length specifier in the scanf call for %s and %[, otherwise you introduce the same security hole that gets does.
EDIT
D'oh. I'm an idiot. If you're trying to read a string containing spaces, you can't use the %s conversion specifier. Use the %[ conversion specifier instead:
scanf( "%79[^\n]", mensage );
That will read up to the next 79 characters or the newline, whichever comes first, and leaves the newline in the input stream.

Try this instead:
scanf("%s\n", nombre);
scanf stops at whitespace when reading a part. gets reads until the first new line. So what happens is scanf leaves behind a newline in the buffer, which gets immediately sees and thinks it was given a blank line.
If you take your original code and enter "name message", two pieces all on one line, you can see this in action - gets will still immediately return, but it will see the second part.
The \n in the scanf thing tells it to go ahead and consume that too.

Try gets(stdin); instead of
fflush(stdin);

while (fgetc(stdin) != '\n'); // seems to work

Related

Why my C program output is different with my friend, but the code is the same? [duplicate]

After wasting too much time searching why my program doesn't execute gets() after using scanf(), I found a solution which is to use fflush(stdin) after scanf() to enable gets() to get a string.
The problem is that fflush(stdin) doesn't do what is expected from it: The program continues skipping gets() and I can't write any phrase in the console to be read.
My code is the next one:
#include <string.h>
#include <stdio.h>
int main(){
char nombre[10];
char mensaje[80];
printf("Type your name:\n");
scanf("%s", nombre);
fflush(stdin);
printf("Now, type a message:\n");
gets(mensaje);
printf("3/%s:%s",nombre,mensaje);
return 0;
}
If flushing std doesn't work, then try reading in the extra characters and discarding, as suggested here.
This will work:
#include <string.h>
#include <stdio.h>
int main(){
char nombre[10];
char mensaje[80];
int c;
printf("Type your name:\n");
scanf("%9s", nombre);
while((c= getchar()) != '\n' && c != EOF)
/* discard */ ;
printf("Now, type a message:\n");
gets(mensaje);
printf("%s:%s",nombre,mensaje);
return 0;
}
Two big, major issues:
DO NOT USE fflush ON INPUT STREAMS; the behavior of fflush on input streams is not defined. Just because it appears to work in this situation does not mean it is correct.
NEVER NEVER NEVER NEVER NEVER NEVER NEVER use gets - it was deprecated in the C99 standard and has been removed completely from the C2011 standard. It will (not might, will) introduce a major point of failure in your code.
It's never a good idea to follow a scanf call with a gets call, since gets won't skip over any leading newlines left in the input stream by scanf. Use scanf to read both nombre and mesaje.
printf("Type your name:\n");
scanf("%9s", nombre);
printf("Now, type a message:\n");
scanf("%79s", mensaje);
It's a good idea to use an explicit length specifier in the scanf call for %s and %[, otherwise you introduce the same security hole that gets does.
EDIT
D'oh. I'm an idiot. If you're trying to read a string containing spaces, you can't use the %s conversion specifier. Use the %[ conversion specifier instead:
scanf( "%79[^\n]", mensage );
That will read up to the next 79 characters or the newline, whichever comes first, and leaves the newline in the input stream.
Try this instead:
scanf("%s\n", nombre);
scanf stops at whitespace when reading a part. gets reads until the first new line. So what happens is scanf leaves behind a newline in the buffer, which gets immediately sees and thinks it was given a blank line.
If you take your original code and enter "name message", two pieces all on one line, you can see this in action - gets will still immediately return, but it will see the second part.
The \n in the scanf thing tells it to go ahead and consume that too.
Try gets(stdin); instead of
fflush(stdin);
while (fgetc(stdin) != '\n'); // seems to work

Using getchar() after scanf()? [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 5 years ago.
I have two questions:
why only when i do space in "%d " --> scanf("%d ", &num); it works?
I tried fflush(stdin) \ _flushall() between the scnaf and the gets and it doesn't works, it skips the gets.
When I do the space, it first does scanf then the gets and after that it print the number and print the string.
void main()
{
char ch, str[10];
int num;
printf("Enter your number : ");
scanf("%d ", &num);
printf("%d\n",num);
gets(str);
puts(str);
system("pause");
}
why only when i do space in "%d " --> scanf("%d ", &num); it works?
scanf("%d", &num); without a space after the "%d", stops scanning after reading a number. So with input 123Enter, the '\n' remains in stdin for the next input function like the now non-standard gets(). gets() reads that single '\n' and returns. By adding a space, scanf("%d ", &num); consumes the white-space after the number and does not return until non-white-scape is entered after the number.
When I do the space, it first does scanf then the gets and after that it print the number and print the string.
By adding a space, scanf("%d ", &num); does not return until non-white-space is entered after the number (as in 'a' in the following). Since stdin is usually line buffered, this means input of 2 lines needs to first occur. 123Enter abcEnter.
Recommend to instead use fgets() to read a line of user input.
char str[10*2]; // no need for such a small buffer
int num;
printf("Enter your number : ");
fflush(stdout);
fgets(str, sizeof str, stdin);
sscanf(str, "%d", &num);
printf("%d\n",num);
printf("Enter data : ");
fflush(stdout);
fgets(str, sizeof str, stdin);
fputs(str, stdout);
More robust code would check the results of fgets(), sscanf() and use strtol() rather than sscanf().
The C FAQ covers all these problems with scanf. See Why does everyone say not to use scanf? What should I use instead? and associated entries. Generally you'll use fgets followed by processing the resulting line such as with sscanf and checking that sscanf succeeded. This avoids leaving unparsed input and risking an infinite loop.
int number;
char line[255];
fgets( line, sizeof(line), stdin );
if( sscanf( line, "%d", &number ) != 1 ) {
fputs("That doesn't look like a number.\n", stdin);
}
Note that fgets will read to a newline or as much as your buffer can hold. If the line is larger than your buffer, it might only read part of the line. Next read from input will get the rest of the line. There's ways to avoid this, such as the POSIX getline function, but at least you don't wind up in an infinite loop.
Let's decipher some comments.
Do not ever use gets. Use fgets.
The reason you don't use gets is because there's no way to limit how much is read from stdin. This means the user can overflow the buffer causing havoc.
char buffer[32];
// What the line is more than 31 characters?
gets(buffer);
fgets() takes the size of the buffer and will read that many characters at most. This prevents a buffer overflow.
char buffer[32];
// If there's more than 31 characters it will stop reading.
// The next read of stdin will get the rest of the line.
fgets( buffer, sizeof(buffer), stdin );
"There's no gets() function in C."
Yes, there is a gets() function in C.
Yes, there isn't a gets() function in C.
It depends on which C you're talking about.
Some people when they say "C" mean C11, the current standard. Others when they say "C" mean C99 the previous standard. Some still adhere to C90, the original standard. There is a gets() function in C90. It was deprecated in C99. It was removed from the language in C11.
C compilers and documentation lag very, very, very far behind the standard. Many are still working on full support of C99. If you work to C11 you're going to be very surprised by the lack of support. If you want your code to work on most any compiler, write to C99.
Anyway, don't use gets.

Reading newline from previous input when reading from keyboard with scanf()

This was supposed to be very simple, but I'm having trouble to read successive inputs from the keyboard.
Here's the code:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
What is happening
When I enter a string (e.g.: computer), the program reads the newline ('\n') and puts it in character. Here is how the display looks like:
write something: computer
computer
Character:
Correspondent number: 10
Moreover, the program does not work for strings with more than one word.
How could I overcome these problems?
First scanf read the entered string and left behind \n in the input buffer. Next call to scanf read that \n and store it to character.
Try this
scanf (" %c", &characte);
// ^A space before %c in scanf can skip any number of white space characters.
Program will not work for strings more than one character because scanf stops reading once find a white space character. You can use fgets instead
fgets(string, 200, stdin);
OP's first problem is typically solved by prepending a space to the format. This will consume white-space including the previous line's '\n'.
// scanf("%c", &character);
scanf(" %c", &character);
Moreover, the program does not work for strings with more than one word. How could I overcome these problems?
For the the 2nd issue, let us go for a more precise understanding of "string" and what "%s" does.
A string is a contiguous sequence of characters terminated by and including the first null character. 7.1.1 1
OP is not entering a string even though "I enter a string (e.g.: computer)," is reported. OP is entering a line of text. 8 characters "computer" followed by Enter. There is no "null character" here. Instead 9 char "computer\n".
"%s" in scanf("%s", string); does 3 things:
1) Scan, but not save any leading white-space.
2) Scan and save into string any number of non-white-space.
3) Stop scanning when white-space or EOF reached. That char is but back into stdin. A '\0' is appended to string making that char array a C string.
To read a line including spaces, do not use scanf("%s",.... Consider fgets().
fgets(string, sizeof string, stdin);
// remove potential trailing \r\n as needed
string[strcspn(string, "\n")] = 0;
Mixing scanf() and fgets() is a problem as calls like scanf("%s", string); fgets(...) leave the '\n' in stdin for fgets() to read as a line consisting of only "\n". Recommend instead to read all user input using fgets() (or getline() on *nix system). Then parse the line read.
fgets(string, sizeof string, stdin);
scanf(string, "%c", &character);
If code must user scanf() to read user input including spaces:
scanf("%*[\n]"); // read any number of \n and not save.
// Read up to 199 `char`, none of which are \n
if (scanf("%199[^\n]", string) != 1) Handle_EOF();
Lastly, code should employ error checking and input width limitations. Test the return values of all input functions.
What you're seeing is the correct behavior of the functions you call:
scanf will read one word from the input, and leave the input pointer immediately after the word it reads. If you type computer<RETURN>, the next character to be read is the newline.
To read a whole line, including the final newline, use fgets. Read the documentation carefully: fgets returns a string that includes the final newline it read. (gets, which shouldn't be used anyway for a number of reasons, reads and discards the final newline.)
I should add that while scanf has its uses, using it interactively leads to very confusing behavior, as I think you discovered. Even in cases where you want to read word by word, use another method if the intended use is interactive.
You can make use of %*c:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s%*c", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c%*c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
%*c will accept and ignore the newline or any white-spaces
You cal also put getchar() after the scanf line. It will do the job :)
The streams need to be flushed. When performing successive inputs, the standard input stream, stdin, buffers every key press on the keyboard. So, when you typed "computer" and pressed the enter key, the input stream absorbed the linefeed too, even though only the string "computer" was assigned to string. Hence when you scanned for a character later, the already loaded new line character was the one scanned and assigned to character.
Also the stdout streams need to be flushed. Consider this:
...
printf("foo");
while(1)
{}
...
If one tries to execute something like this then nothing is displayed on the console. The system buffered the stdout stream, the standard output stream, unaware of the fact it would be encounter an infinite loop next and once that happens, it never gets a chance to unload the stream to the console.
Apparently, in a similar manner whenever scanf blocks the program and waits on stdin, the standard input stream, it affects the other streams that are buffering. Anyway, whatsoever may be the case it's best to flush the streams properly if things start jumbling up.
The following modifications to your code seem to produce the desired output
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
fflush(stdout);
scanf ("%s", string);
fflush(stdin);
printf ("%s", string);
printf ("\nwrite a character: ");
fflush(stdout);
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
Output:
write something: computer
computer
write a character: a
Character a Correspondent number: 97

Why is gets() not consuming a full line of input?

I'm trying to use gets() to get a string from the user, but the program seems to be passing right over gets(). There is no pause for the user to give input. Why is gets() not doing anything?
char name[13];
printf("Profile name: ");
gets(name);
printf("\n%s", name);
Call getchar() before you call gets() or fgets(). Since gets() or fgets() is getting skipped due to an already present '\n' from previous inputs in stdin, calling getchar() would lead to itself getting skipped instead of gets() or fgets() or any other similar function. But remember its more of a hack and not a standard solution (I think so), and also use of gets() is forbidden.
printf("\nEnter a String: ");
getchar();
//fgets(inputString, 100, stdin);
gets(inputString);
printf("\n%s", inputString);
It's because gets() it's so incredibly dangerous to use, that some C libraries have removed it completely and replaced it with a version that does nothing.
Use fgets() instead.
Use fflush(stdin); before gets()
You get lot of troubles using gets()
Instead go for fgets()
fgets(name,13,stdin);
See this SO question Why is the gets function so dangerous that it should not be used?
The reason why fgets() does not work, may be you are not handling the newline left behind by scanf in your previous statements.
You can modify your scanf format string to take it into account:
scanf("%d *[^\n]", &N);
*[^\n] says to ignore everything after your integer input that isn't a newline, but don't do anything with the newline (skip it).
When you use scanf("%d",&num) you hit 13 and enter and 13 is stored in num and the newline character is still in the input buffer when you read fgets from stdin it treats \n as the data you have entered and the fgets() statement is skipped
You cannot flush input buffer however you can do this fseek(stdin,0,SEEK_END); add this before your every fgets statement
Take a look at gets() reference
Get string from stdin
Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached.
The newline character, if found, is not copied into str.
A terminating null character is automatically appended after the characters copied to str.
Notice that gets is quite different from fgets: not only gets uses stdin as source, but it does not include the ending newline character in the resulting string and does not allow to specify a maximum size for str (which can lead to buffer overflows).
So, basically gets() is not only unsafe (can lead to buffer overflows) but also reads what's in the input buffer.
I recommend you to use fgets(), but if you want a quick (and lazy and stupid) solution, just flush the input buffer:
char name[13];
printf("Profile name: ");
fflush(stdin);
gets(name);
printf("\n%s", name);
Add this below function to your code and enjoy it.
string GetString()
{
char ch;
string Line="";
while(1)
{
ch=getchar();
if(ch=='\n')
break;
else
Line+=ch;
}
return Line;
}
This function can effect all Spaces and Backspaces too!!!
You might need to discard the rest of the line and move on to the beginning of the next one. You can do:
int c; while((c=getchar()) != '\n' && c != EOF);
This discards the rest of the current line (which might have been partially read with scanf(), etc.) and moves on to the next one.
Although fflush(stdin) might also discard the input, it is non-standard behaviour and discouraged.
You should never ever use gets(myString), as it has been completely removed from the C standard due to how unsafe it is. It doesn't enforce the length of the string, so you can go past the end of the buffer and overwrite other values in RAM, causing a buffer overflow, which can be a security vulnerability. Use fgets(myString, myStringSize, stdin); instead. To get rid of the newline in the resulting string, use myString[strcspn(myString, "\n")] = 0;.

Noticing strange behavior with strings in c

Still in learning mode and may be the following question is a really dumb but I dont have any idea why it is happening..
#include<stdio.h>
int main()
{
/* code to accept string and then a character from stdin */
char str[20], inp;
/*take string from stdin */
printf("string:\n");
scanf("%s",str);
fflush(stdin);
/*input a character */
printf("char:\n");
scanf("%c",&inp);/* code does not reach this point and exits */
}
As mentioned in the comment, after I input the string , for eg. 'strng' the code just exits after printing char: but it does not wait for me input the character. As per my understanding, I have given the size of the array large enough to store the string and if the string entered is smaller than the size of the str array, the compiler will automatically add null character at the end of the string and proceed further. Am I missing something or is there a mistake in my code. Please suggest.
Thanks.
Try removing fflush(stdin);
and put a space before %c in scanf(" %c",&inp);
First of all fflush(stdin) is wrong. Many people recommend it but it is plain and simple undefined.
The problem is caused by scanf leaving \n in the input buffer because "%s" doesn't read whitespace characters. When scanf("%c"..) is reached, it is immediately "satisfied" and fills inp with \n and calls it a day.
The problem is common enough, see these C FAQs:
Scanf interlace
Scanf problems
One (possibly dangerous) solution is to discard \n input:
while((c = getchar()) != '\n' && c != EOF)
;
Another solution might be to use fgets and parse that, or possibly read one character at a time with getc, or maybe tweak the second scamf to discard whitespace characters.
Put a space before the %c in the second scanf like this:
scanf(" %c",&inp)
And as stated by others fflush is defined only for output streams.

Resources