Exiting scanf loop with numbers in one line with one EOF - c

I have a litte problem with EOF. I need to write numbers in one line with spaces between them and sum them together. Scanf must be ended with one EOF (Ctrl+D)
I have this little program
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
double numbers=0, sum=0;
printf("Enter numbers: ");
while(scanf("%lf", &numbers) != EOF){
sum=sum+numbers;
}
printf("\n %.2lf", sum);
}
Problem with this program is that I need to press Ctrl+d two times until it prints sum.
Example input/output:
Enter numbers: 1 3 5 6 <'Ctrl+d'>
15.00

EOF must be preceded with a newline else it won't work. However it depends on the OS. The EOF you enter at the end of of the line containing the input is not recognized. From the man page of scanf -
scanf returns the number of 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.
Therefore you should check the return value of scanf for 1, not EOF.
#include <stdio.h>
int main(void) {
double numbers = 0, sum = 0;
printf("Enter numbers: ");
while(scanf("%lf", &numbers) == 1) {
sum += numbers;
}
printf("\n %.2lf", sum);
}

scanf returns the number of values it assigned; so if you want to use that, you want
while (scanf("%lf", &numbers) == 1)
Alternatively, you could use more of a C++ idiom (assuming you meant to tag the question with that language as well as C):
while (std::cin >> numbers)

The program is showing this behavior because, when you give input
4 4 4 scanf() will not start reading input. scanf() starts reading input when you press [enter]. so if you give input as
4
4
4
then the result will come on first
otherwise you will need 2 's since first one starts reading input and it wont be read as EOF as it just makes scanf() start reading input. therefore one more will be read by scanf() as EOF.

The stdin EOF flag won't be turned on until the second ctrl+d in succession, the first ctrl+d pushes whatever is on your screen to the stdin buffer, the second ctrl+d sets the EOF flag.
In another case, when you enter some numbers and press enter, the numbers on your screen is pushed to the stdin input buffer, and ctrl+d soon after will also set the EOF flag.
On your system this is normal behaviour, the EOF only occurs on the second ctrl+d.

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;
}

C scanf() function, how to terminate on EOF/EOT?

I wrote a simple program to test the scanf() function in C. It basically reads from the terminal, char by char, reprinting the return value and the char read; and to terminate if EOF/EOT is met or if a \n newline is read.
#include <stdio.h>
#include <stdbool.h>
int main(void) {
char c; int ret;
printf("Enter the chars to test: ");
//LOOP (scan & print) only when return is not EOF and char is not newline
while ( ((ret = scanf("%c", &c)) != EOF) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
return 0;
}
It terminates correctly, if newline (Enter) is pressed. But the it won't just terminate with a single Ctrl-D. A single Ctrl-D will flush the typed 'chars' and printing them. Then after that it will wait again for input, although an EOF has been sent with the Ctrl-D. If we press Ctrl-D again the 2nd time directly after the 1st (2x) or just Enter it will terminate. So you will need two consecutive Ctrl-D to terminate the program (or the loop in this case).
Example:
If you input 987 on the terminal, then press Enter; then 1 9, 1 8, 1 7 will be printed on newline each.
If you input 987 on the terminal, then press Ctrl-D; then 1 9 will be printed on the same line (because there is no Enter typed after inputing the 987 input), 1 8, 1 7 will be printed on newline. Then it will still wait for more inputs, unless it is terminated by directly entering a 2nd consecutive Ctrl-D or with a newline (Enter). So it (the program) will only stop (exit the loop) after a newline or 2nd consecutive Ctrl-D.
I am confused. Shouldn't a single Ctrl-D sent stop the loop here? What should I do to stop the program (scanf loop) after receiving just a single Ctrl-D?
I tested the code on Lubuntu 19.10 with gcc 9.2.1.
The issue is scanf() does not return EOF until there is no more input waiting and EOF is encountered. (your "%c" conversion specifier will otherwise accept any character, including the '\n' character, as valid and consider it a successful conversion)
When you type a line of characters, e.g. "abcdefg" and attempt to press Ctrl+d (indicating end-of-input), the input ("abcdefg") is processed and when 'g' is reached, then scanf() blocks waiting on your next input. (because a successful conversion took place and no matching or input failure occurred)
Once Ctrl+d is typed a 2nd time (indicating end-of-input), when there is no input to process, EOF is reached before the first successful conversion and an input-failure occurs,scanf() then returns EOF.
See: man 3 scanf -- RETURN VALUE section and C11 Standard - 7.21.6.2 The fscanf function(p16)
Test the returned value for one, not EOF. When eof is reached first time, zero is returned. The next scanf after zero returns EOF.
while ( ((ret = scanf("%c", &c)) == 1) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
This behavior is specified for the standard C library.
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror).
You can add if (feof(stdin) != 0) break; into the loop body, if you use more complex input format.
If you read chars only, is it not better use fgetc?

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.

scanf ignoring, infinite loop

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;
}

Resources