scanf ignoring, infinite loop - c

int flag = 0;
int price = 0;
while (flag==0)
{
printf("\nEnter Product price: ");
scanf("%d",&price);
if (price==0)
printf("input not valid\n");
else
flag=1;
}
When I enter a valid number, the loop ends as expected. But if I enter something that isn't a number, like hello, then the code goes into an infinite loop. It just keeps printing Enter Product price: and input not valid. But it doesn't wait for me to enter a new number. Why is that?

When you enter something that isn't a number, scanf will fail and will leave those characters on the input. So if you enter hello, scanf will see the h, reject it as not valid for a decimal number, and leave it on the input. The next time through the loop, scanf will see the h again, so it just keeps looping forever.
One solution to this problem is to read an entire line of input with fgets and then parse the line with sscanf. That way, if the sscanf fails, nothing is left on the input. The user will have to enter a new line for fgets to read.
Something along these lines:
char buffer[STRING_SIZE];
...
while(...) {
...
fgets(buffer, STRING_SIZE, stdin);
if ( sscanf(buffer, "%d", &price) == 1 )
break; // sscanf succeeded, end the loop
...
}
If you just do a getchar as suggested in another answer, then you might miss the \n character in case the user types something after the number (e.g. a whitespace, possibly followed by other characters).
You should always test the return value of sscanf. It returns the number of conversions assigned, so if the return value isn't the same as the number of conversions requested, it means that the parsing has failed. In this example, there is 1 conversion requested, so sscanf returns 1 when it's successful.

The %d format is for decimals. When scanf fails (something other a decimal is entered) the character that caused it to fail will remain as the input.
Example.
int va;
scanf("%d",&va);
printf("Val %d 1 \n", val);
scanf("%d",&va);
printf("Val %d 2 \n", val);
return 0;
So no conversion occurs.
The scanf function returns the value of the macro EOF if an input failure occurs before
any conversion. Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the event of an early
matching failure
7.19.6. The scanf function - JTC1/SC22/WG14 - C
So you should note that scanf returns its own form of notice for success
int scanf(char *format)
so you could have also did the following
do {
printf("Enter Product \n");
}
while (scanf("%d", &sale.m_price) == 1);
if(scanf("%d", &sale.m_price) == 0)
PrintWrongInput();
Also keep in the back of your head to try to stay away from scanf. scanf or scan formatted should not be used for interactive user input. See the C FAQ 12.20

After the first number, a '\n' will be in the input buffer (the return you pressed to input the number), so in the second iteration the scanf call will fail (becouse \n isn't a number), scanf will not remove that \n from the buffer, so in the next iteration it will fail again and so on.
You can fix that by reading the '\n' with a getchar() call after scanf.

The "answers" that say it will because there is a '\n' in the buffer are mistaken -- scanf("%d", ...) skips white space, including newlines.
It goes into an infinite loop if x contains 0 and scanf encounters a non-number (not just whitespace) or EOF because x will stay 0 and there's no way for it to become otherwise. This should be clear from just looking at your code and thinking about what it will do in that case.

It goes into an infinite loop because scanf() will not consumed the input token if match fails. scanf() will try to match the same input again and again. you need to flush the stdin.
if (!scanf("%d", &sale.m_price))
fflush(stdin);

Edit: Back when I first wrote this answer, I was so stupid and ignorant about how scanf() worked.
First of all let me clear something, scanf() is not a broken function, if I don't know how scanf() works and I don't know how to use it, then I probably haven't read the manual for scans() and that cannot be scanf()'s fault.
Second in order to understand what is wrong with your code you need to know how scanf() works.
When you use scanf("%d", &price) in your code, the scanf() tries to read in an integer from the input, but if you enter a non numeric value, scanf() knows it isn't the right data type, so it puts the read input back into the buffer, on the next loop cycle however the invalid input is still in the buffer which will cause scanf() to fail again because the buffer hasn't been emptied, and this cycle goes on forever.
In order to tackle this problem you can use the return value of scanf(), which will be the number of successful inputs read, however you need to discard the invalid inputs by flushing the buffer in order to avoid an infinite loop, the input buffer is flushed when the enter key is pressed, you can do this using the getchar() function to make a pause to get an input, which will require you to press the enter key thus discarding the invalid input, note that, this will not make you press the enter key twice whether or not you entered the correct data type, because the newline character will still be in the buffer. After scanf() has successfully finished reading the integer from input, it will put \n back into the buffer, so getchar() will read it, but since you don't need it, it's safe to discard it:
#include <stdio.h>
int main(void)
{
int flag = 0;
int price = 0;
int status = 0;
while (flag == 0 && status != 1)
{
printf("\nEnter Product price: ");
status = scanf("%d", &price);
getchar();
if (price == 0)
printf("input not valid\n");
else
flag = 1;
}
return 0;
}

Related

why the below code is taking two input on single execution of scanf funcion

#include<stdio.h>
#include<conio.h>
int main()
{
int Dividend,divisor;
printf("Checking Divisiblity of 1st number with 2nd number \n\n") ;
printf("Enter Number \n") ;
scanf("%d",&Dividend);
printf("Enter Divisor = ");
scanf("%d",&divisor) ;
if(Dividend % divisor == 0)
{
printf("Number %d is divisible by %d",Dividend,divisor) ;
}
else
{
printf("Number %d is not divisible by %d",Dividend,divisor) ;
}
getch();
return 0;
}
Above is my code that i have written in C ;
on running this program . Only on first execution of scanf function if i give two input space seperated , the second input is going on right variable . and on hitting enter i am getting result . I am not understanding how is this happing .
When space is pressed, scanf doesn't see anything yet. Something happens only after enter is pressed. It then takes everything to the left of the space character and assigns it to the first variable, and everything to the right of the space character and assigns it to the second variable.
If you don't press the spacebar, scanf will interpret everything you type as a single number and will assign it to the first variable.
Instead what you may want to do is use the %c format specifier to read a single character at a time. You can then check if the character is a space character and if it is, you can break out of the loop. Otherwise, you can keep reading characters until you reach a space character.
stdin is line based by default. Your program gets nothing until you press enter. Then your program has the entire line of text available.
Result of this is, that scanf, getchar, fgets, etc calls will not return until you press enter. After enter press, entire line is available and the function starts to process it.
scanf is kinda special, that if you have int parsed_count = scanf("%d%d", &a, &b);, it will read two integers, no matter how many times you press enter, so you can either do
1 2<enter>
Or you can do
<enter>
1<enter>
<enter>
2<enter>
and scanf will still read these two integers (it returns early if there is parse error, which is why you need to check the return value!).
And vice versa, if there is already input available, then scanf may return immediately, so if you have this code
scanf("%d",&Dividend);
printf("Enter Divisor = ");
scanf("%d",&divisor) ;
and enter text
1 2<enter>
Then first scanf will wait for enter press, then consume the first integer, leaving 2<enter> still unread. Then there's print, and then 2nd scanf starts reading, skipping the whitespace and immediately getting 2nd integer. So you see
1 2 <- this is your typing echoed, not print from your program
Enter Divisor = <- printf printed this
If you want to take only one input per enter press, you can simply read characters until newline, because scanf leaves them there. Example loop to read until newline, or exit program at end of file/error:
while(true) {
int ch = getchar();
if (ch == EOF) exit(1);
if (ch == '\n') break;
}

Terminate scanf on EOF and ignore strings

I am using the following code to scan for integers input from the user until end of line occurs.
while (scanf(" %d", &num) != EOF) {
printf("Do something")
}
This works as expected until the user inputs a string instead of an integer. The program would then endlessly keep printing Do something. Why is that happening?
How can I stop the loop only when End of line occurs, but ignore string inputs and only perform my logic if integer inputs have occured?
scanf() returns the number of input items successfully assigned. That is, in your example, 1 if a number is entered, or 0 otherwise. (Unless an input error occurs prior to the first input item, in which case it returns EOF.)
In case a string is entered, this fails to match %d, scanf() returns zero, the loop is entered, "Do something" is printed, and scanf() is called again.
But the string has not been consumed by any input function.
So the string fails to match, "Do something" is printed... you get the idea.
Be happy you do not access num, because if you haven't initialized that beforehand, accessing it would be undefined behaviour (as it still isn't initialized)...
Generally speaking, do not use scanf() on potentially malformed (user) input. By preference, read whole lines of user input with fgets() and then parse them in-memory with e.g. strtol(), strtof(), strtok() or whatever is appropriate -- this allows you to backtrack, identify exactly the point where the input failed to meet your expectations, and print meaningful error messages including the full input.
How can I stop the loop only when End of line occurs, but ignore string inputs and only perform my logic if integer inputs have occured?
When scanf(" %d", &num) returns 0, read a single character and toss it.
int count;
while ((count = scanf("%d", &num)) != EOF) {
if (count > 0) printf("Do something with %d\n", num);
else getchar();
}

Validate integer against chars

I'm trying to make a program where the user inputs value to an array. What is actually required is that the program should validate against a char character. So if the user inputs a random char such as 'n' the program should tell him "You introduced a char, please input an integer: ".
How is that possible to make that without using a char variable?
for (i = 1; i <= size; i++) {
printf("Introduce the value #%d of the list: ", i);
scanf("%d", &list[i]);
if () { // I'm blocked right in this line of code.
printf("What you tried to introduce is a char, please input an integer: ");
scanf("%d", &list[i]);
}
Thanks in advance.
As #MFisherKDX says, check the return value of scanf. From the scanf man page:
These functions return the number of input items successfully matched
and assigned, which can be fewer than provided for, or even zero in
the event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set
indicate the error.
So capturing the return value of scanf in an int variable and then comparing that variable to 1 (in your case, because you are only attempting to read 1 item) should tell you if scanf successfully read an integer value.
However, there is a nasty pitfall when using scanf that you should be aware of. If you do type n at the prompt, scanf will fail and return 0, but it will also not consume the input you typed. Which means that the next time you call scanf, it will read the same input (the n character you typed), and fail again. And it will keep doing so no matter how many times you call scanf. It always amazes me that computer science educators continue to teach scanf to students, given not only this potential pitfall, but several other pitfalls as well. I wish I had a nickel for every hour that some CS student somewhere has spent struggling to get scanf to behave the way their intuition tells them it should. I'd be retired on my own private island by now. But I digress.
One way around this particular pitfall is to check if scanf failed, and if so, to purposely consume and discard all input from stdin up to and including the next newline character or EOF, whichever comes first.
First let's look at some unfixed code that causes an infinite loop if you enter a non-integer as input:
// Typing the letter 'n' and hitting <Enter> here causes an infinite loop:
int num, status;
while (1) {
printf("Enter a number: ");
status = scanf("%d", &num);
if (status == 1)
printf("OK\n");
else
printf("Invalid number\n");
}
The above code will (after you type n and hit <Enter>), will enter an infinite loop, and just start spewing "Invalid number" over and over. Again, this is because the n you entered never gets cleared out of the input buffer.
There are a few possible ways to get around this problem, but the consensus seems to be that the most portable and reliable way to do so is as follows:
// Fixed. No more infinite loop.
int num, status;
while (1) {
printf("Enter a number: ");
status = scanf("%d", &num);
if (status == 1)
printf("OK\n");
else {
printf("Invalid number\n");
// Consume the bad input, so it doesn't keep getting re-read by scanf
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) ;
if (ch == EOF) break;
}
}
The function scanf() will returns the number of elements read, so in this case it will return 1 every time it reads an int and 0 when it reads a char, so you just need to verify that return value.
Keep in mind that after reading a character it will remain in the buffer so if you use the scanf() command again it will read the character again and repeat the error. To avoid that you need to consume the character with while(getchar() != '\n');
With that in mind I modified your code so that it works properly printing an error message if a character is introduced and asking for a new int.
for (int i = 1; i <= size; i++) {
printf("Introduce the value #%d of the list: ", i);
while (!scanf("%d", &list[i])) { //verifies the return of scanf
while(getchar() != '\n'); //consumes the character in case of error
printf("What you tried to introduce is a char\n");
printf("please introduce the value #%d of the list: ", i);
}
}

How do scanf and getchar work in C?

Here is something that confused me.
# include <stdio.h>
# include <limits.h>
int main()
{
int a;
int b;
printf("Enter two integers: ");
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
printf("sum is %d, difference is %d, product is %lf, divid is %.2f, remainder is %d", a+b, a-b, (double)a*b, (float)a/b, a%b);
return 0;
}
With above code, if I enter "a 1" press ENTER:
Invalid entry, please re-enter:
pops up, then I enter "2 B" press ENTER, the last printf will execute.
However, if I change while(getchar()=='\n'); to while(getchar()!='\n');, and with the same entry (I enter "a 1" press ENTER)
Invalid entry, please re-enter:
pops up, then I enter "2 B" press ENTER), the last printf will not execute, and
Invalid entry, please re-enter:
pops up again.
What causes the difference here? How exactly do scanf and getchar work?
In the first case (while (getchar() == '\n');), the getchar() reads the a, but it isn't a newline, so the loop exits, leaving the space and the 1 in the input buffer. The repeated call to scanf() skips white space, reads 1, skips white space (newline included) and reads 2, leaving space and B in the input. Since the loop condition is now terminated (scanf() returned 2), the printf() is executed.
In the second case (while (getchar() != '\n');), this loop reads the a, the blank, the 1, and the newline before stopping. When you type 2 B, there aren't two numbers, so scanf() returns 1 and the main loop continues.
Note that your code will go into an infinite loop if you indicate EOF (usually Control-D on Unix, Control-Z on Windows) — at least, on most systems. You should always consider EOF. In context, you probably need something like:
int rc;
while (((rc = scanf(…)) != 2 && rc != EOF) || …)
You'd test rc against EOF before printing, too.
How do scanf and getchar work in C?
Sadly, they often do not work together well.
Code is a poor example of attempting to consume the rest of the input line when the input text is a problem.
If scanf("%d %d", &a, &b) failed to scan in 2 int, a prompt occurs and input is read with getchar until an Enter or '\n' happens.
If 2 int were scanned, various faulty tests are performed on a,b
// poor code
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
The problem is that the code certainly intends to read a line of user input and then validate it. Unfortunately, scanf("%d %d" can consume multiple '\n' and leaves stdin with unclear contents when 2 int are not scanned. Code is an infinite loop on end-of-file.
Better to read a line of input with fgets(). Flushing stdout insures the prompt is seen before input is read.
char buf[80];
const char *prompt = "Enter two integers: ";
for (;;) {
fputs(prompt, stdout);
fflush(stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EndOfFile_or_Error();
prompt = "Invalid entry, please re-enter: ";
int n;
if (sscanf(buf, "%d%d %n", &a, &b, &n) != 2) continue; // not 2 ints
if (buf[n]) continue; // extra text
if ((a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a)) continue; // + overflow
... // other tests
else break;
}
other tests
scanf() and getchar() read what is in the input buffer (stdin for standard input). When stdin is empty, the program will wait for the user to write something with the keyboard. When you press ENTER, the text you just wrote is stored in stdin. Then scanf() or getchar() can read something in stdin.
Notice that pressing ENTER will store a '\n' character (newline) in stdin.
A code like while( getchar() != '\n' ); is asking to getchar() to read one character from stdin while the character is not '\n'. It compares the return of getchar() with '\n'. So this is a way to "clean" the input buffer otherwise your program can go crazy.
EDIT
With the code you posted :
scanf() is called, you write "a 1", it tries to read a first integer but it is a character ('a') so it stops reading. printf() ask you to re-enter, then getchar() is called and reads the 'a'. Now scanf() is called a second time, reads the 1, then you have to enter something, you enter "2 B" so the second %d in scanf() can read the 2. Now the return of scanf() is 2, b is not 0 and the others conditions are false so the loop is ending. Notice that the 'B' character is still in stdin :)
I try to summarize what you need to know.
First, about your question. You do know the function of scanf is to read what the input (number) we give right? getchar on the other hand, is like scanf except that it is used for character/sentence only. You cannot use getchar to input number.
Second, there are no problem in your code except that it is okay not to use some line like that getchar line. It is also okay not to use while. Unless you want to make some condition, you may combine while with if / else function.
Third, you cannot input the number like you did: "1 a", "2 b". Those are considered invalid. This is because you are using %d in your scanf which refer to decimal number only. It means, you can input number 1-9 only and not the letters. So when the program asked to enter the 2 integers, you just type for example: 4 5. That's 4, space, 5. That is the correct way.

Why doesn't scanf() wait for the next input if I previously entered a certain input

below is my simple code to enter a number and print it. it is inside a while(1) loop so i need to "Enter the number infinite number of time- each time it will print the number and again wait for the input".
#include<stdio.h>
int main()
{
int i;
while(1){
printf("\nenter i \n");
scanf("%d", &i);
if(i==1)
{
printf("%d \n", i);
}
}
return 0;
}
it was working fine. but suddenly i noticed that IF i ENTER a character(eg: "w") instead of number , from there it won't ask for input!!!**
it continuesly prints,
enter i
1
enter i
1
......
when i debug using GDB, i noticed that after i enter "w", that value of character "w" is not stored in &i . before i enter "w" it had 0x00000001 so that "1" is printed through out the process.
Why it doesn't ask for another input? According to my knowledge, when I enter "w" the ascii value of "w" should be stored in &i. But it doesn't happen.
If I put, "int i; " inside while loop it works fine! Why?
Please test my code in following way:
Copy and paste and run it
When "enter i" prompt will come enter 1
Second time enter "w". See what happens...
scanf with %d format specifier will read everything that "looks like a number", i.e. what satisfies the strictly defined format for a decimal representation of an integer: some optional whitespace followed by an optional sign followed by a sequence of digits. Once it encounters a character that cannot possibly be a part of a decimal representation, scanf stops reading and leaves the rest of the input data in the input stream untouched (to wait for the next scanf). If you enter just w, your scanf will find nothing that "looks like a number". It will read nothing. Instead it will report failure through its return value. Meanwhile your w will remain in the input stream, unread. The next time you try your scanf, exactly the same thing will happen again. And again, and again, and again... That w will sit in the input stream forever, causing each of your scanf calls to fail immediately and your loop to run forever (unless your uninitialized variable i by pure chance happens to start its life with the value of 1 in it).
Your assumption that entering w should make scanf to read ASCII code of w is completely incorrect. This sounds close to what %c format specifier would do, but this is not even close to what %d format specifier does. %d does not read arbitrary characters as ASCII codes.
Note also that every time you attempt to call that scanf with w sitting in the input stream, your scanf fails and leaves the value of i unchanged. If you declare your i inside the loop, the value of i will remain uninitialized and unpredictable after each unsuccessful scanf attempt. In that case the behavior of your program is undefined. It might even produce an illusion of "working fine" (whatever you might understand under that in this case).
You need to check the return value of scanf as well, as it will return the number of successfully scanned and parsed values. If it returns zero (or EOF) then you should exit the loop.
What happens when you enter e.g. the character 'w' instead of a number is that the scanf function will fail with the scanning and parsing, and return zero. But the input will not be removed from the input buffer (because it was not read), so in the next loop scanf will again read the non-numeric input and fail, and it will do this infinitely.
You can try this workaround:
int main()
{
int i;
char c;
while (1)
{
printf("enter i: ");
if (scanf("%d",&i) == 0)
scanf("%c",&c); // catch an erroneous input
else
printf("%d\n",i);
}
return 0;
}
BTW, when were you planning to break out of that (currently infinite) loop?
You need to read up on scanf(), since you seem to be basing your program around some assumptions which are wrong.
It won't parse the character since the conversion format specifier %d means "decimal integer".
Also, note that you must check the return value since I/O can fail. When you enter something which doesn't match the conversion specifier, scanf() fails to parse it.
You would probably be better of reading whole lines using fgets(), then using e.g. sscanf() to parse the line. It's much easier to get robust input-reading that way.
scanf return type can be checked and based on that inputs can be consumed using getchar to solve your problem.
Example code
int main()
{
int i;
int ch;
while(1){
printf("\nenter i \n");
if ( scanf("%d", &i) !=1 )
{
/*consume the non-numeric characters*/
for (; (ch = getchar()) != EOF && ch != '\n'; ) { }
}
if(i==1)
{
printf("%d \n", i);
}
}
return 0;
}
Description:
When scanf("%d", &i) encounters the character, it will not read it. The character will still remains in the input stream. So to consume those characters, getchar() can used. Then scanf will wait for the next input in further iteration.

Resources