c - how gets() work after scanf? [duplicate] - c

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.

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 a paragraph in c language

#include<Stdio.h>
#include<conio.h>
void main()
{
char a[100];
clrscr();
printf("enter a paragraph\n");
scanf("%s",a);
printf("%s",a);
getch();
}
output:
enter a paragraph
my name is vasanth
my
how do I read the entire line "my name is vasanth" using scanf function?
Using the scanf function:
scanf("%99[^\n]", a);
Where %[^\n] is a character set specifier that allows all characters except newlines, and %99[^\n] limits the match to at most 99 characters (since a has space for that many characters plus the null terminator).
Alternatively, you can use
fgets(a, 100, stdin);
This is arguably more common, but be aware that it leaves the newline at the end intact.
This question has been asked multiple times and the answer to this is
Use
fgets(a,sizeof(a),stdin);
size_t n = strlen(a);
if(n>0 && a[n-1] == '\n')
a[n-1] = '\0';
If you want to use scanf() only then you need to do
scanf("%99[^\n]",a);
Where [^\n] tells read until newline character is encountered and 99 makes sure that there is not buffer overflow. Still fgets() is a good option to read strings compared to scanf()
You can use fgets as below
fgets (a, 100, stdin);
You can use fgets( ) function to read a line of text.
fgets(str , 100 , stdin);
You can also use gets( ) function if your string is small since this funtion has no buffer overflow protection.
gets(str)
U can also use scanf to do this as others have mentioned.

Scanf is being ignored, how to prevent?

I got this code:
#include <stdio.h>
int main(void){
char ordet;
int again = 1;
while(again == 1){
printf("Write a name: \n");
while (ordet!='\n'){
scanf("%c",&ordet);
if('A'<= ordet && ordet <='W')
{
printf("%c",ordet+3);
}
else if('W'<=ordet){
printf("%c", ordet-22);
}
}
printf("\nDo you want to write a new name? 1/0");
scanf("%d", &again);
}
return 0;
}
It runs fine the first time but as soon as you press 1 to write a new name you never get the chance to write it, it just keeps asking "Do you want to write a new name?" and ignores "Write a name:". I have tested with fflush(stdin), != EFO and space infront of %c but nothing works. How could I fix this since I really have no idea, started out with C a few days ago.
while (ordet!='\n'){
ordet is used without initialization here. Not quite UB (if your implementation uses unsigned char or signed char has no trap-representations), but bad enough.
scanf("%c",&ordet);
The above line is the only line potentially setting ordet. Please take note that the loop starting with it is only entered when ordet is not '\n'.
You probably want to reset it before entering the inner loop, or use a do-while-loop.
Actually, changing both loops to do-while-loops would be good.
scanf("%d", &again);
The above line reads a number from beginning of stdin, but leaves the newline.
This must be dealt with by consuming all whitespace on repeat.
Luckily, that's easily done as the inner loop ignores whitespace.
Change "%c" to " %c".
Also, all your scanf-invocations can fail. Check them!
There are 2 problems with your code:
ordet is not initialized before its first usage. It is undefined behavior.
You do not reset ordet anywhere outside the inner loop. That is, once ordet becomes equal to \n, the body of the inner loop is never executed again.
To fix it, you can write something like ordet = 0 before inner loop. And don't forget to skip new line character that is left in the buffer after reading again variable.
All input you write in the console from the keyboard is placed in a buffer, scanf reads from this buffer however if there are more characters in the buffer than what your format specifier specifies those characters will remain in the buffer.
e.g.
scanf( "%d", &n );
when you enter a numerical value 100 and press ENTER afterwards, the ENTER character is placed in the buffer as well "100\n" when you do scanf on the buffer (stdin) the 100 is extracted from the buffer but the \n remains.
Next time you write scanf("%d", &n ); the \n is still in there and will not be read by %d since it is not a %d number.
IMO the best way to handle this is instead to read from the keyboard using fgets, then after the content has been read use sscanf to extract the information you want:
char buffer[128];
fgets( buffer, sizeof(buffer), stdin );
sscanf( buffer, "%d", &n );
you also then can have additional error checks:
if (fgets( buffer, sizeof(buffer), stdin ) != NULL )
{
if (sscanf( buffer, "%d", &n ) ==1)
{
...
}
}
now to your code:
if you want to read character by character from the keyboard use fgetc() not scanf()
Use the C-runtime function isalpha()/toupper() to recognize a character.
In C, a character is an int, that is why most functions like fgetc return an int and not a char.
In general I would recommend using fgets() instead of reading one character at a time.

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

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

Resources