Unclear about stdin input issue - c

I write a piece of code to help myself understand how things work when stdin and stdout involved.
Here is my code:
#include<stdio.h>
#include<stdlib.h>
void prompt(){
int i=0;
printf("please select:\n"); //string1
printf("1.input\n2.print\n3.Exit\n"); //string2
scanf("%d",&i);
switch(i){
case 1:
printf("Data input!\n");
break;
case 2:
printf("data printed!\n");
break;
case 3:
exit(0);
case 10:
printf("Newline detected!"); //string3
default:
printf("Please input a valid number!(1-3)"); //string4
}
}
int main()
{
while(1)
prompt();
return 0;
}
What I expect this code to do is:
prompt me for input;
then I enter a number 4,which is out of the cases;
so the default case will be matched and the string 'Please input a valid...'(string 4) will be printed.
as there is still a newline character left in the stdin buffer, in the next loop,
the variable 'i' will automatically get a newline character, which is 10 in ACSII
So after printing out 'please select..1.input\n2.print....',, a string 'Newline detected!'(string 3) will be immediately printed out.
And then the code goes into the third loop, and prompt me for input....
But that never happen. I cannot see any 'Newline detected!" in the output even if I enter a number 4, which is out of the cases.
Anyone can elaborate how this snippet work exactly?
By the way: I originally assume that when there is something printed in the stdout, the stdin buffer will be flushed automatically. But some fact proved me wrong. Is my assumption true or false?
Also, when I enter a character(for example, a g) rather than a number, I got string 1, string 2, sring 4 printed in the screen infinitly. Why is that?
#######################################################################3
Edit: After viewing the answer, I make another snippet, to help understand.
#include<stdio.h>
#include<stdlib.h>
void output();
int main()
{
int i;
printf("Enter a number here:\n");
scanf("%d",&i);
output();
return 0;
}
void output(){
char a;
if (scanf("%c",&a)!=1){
printf("scanf error!!");
exit(1);
}
switch(a){
case 'a':
printf("an char a is entered");
break;
case 'b':
printf("an char b is entered");
break;
default:
printf("%c",a);
printf("other thing is entered");
}
}
whatever you enter the first time the program prompt you, you will never get your second prompt. For example, when the program prompt you for the first time, if you enter a number 4, then you will get a newline and a string "other thing is entered" printed on you screen. Why is that?

as there is still a newline character left in the stdin buffer, in the next loop, the variable 'i' will automatically get a newline character, which is 10 in ACSII
So after printing out 'please select..1.input\n2.print....',, a string 'Newline detected!'(string 3) will be immediately printed out.
That is not correct. When you use
scanf("%d",&i);
all white spaces are ignored, which includes the newline.
And then the code goes into the third loop, and prompt me for input....
Now you know it stays in the second loop, waiting for a number to be entered.
I originally assume that when there is something printed in the stdout, the stdin buffer will be flushed automatically. But some fact proved me wrong. Is my assumption true or false?
That assumption is false. stdout is flushed when you wait for input from stdin.
Also, when I enter a character(for example, a g) rather than a number, I got string 1, string 2, sring 4 printed in the screen infinitly. Why is that?
That's because the program is not able to read the character when it executes the line:
scanf("%d",&i);
The character stays in the input stream. You don't have any code to remove that character from the input stream. That makes the program stay in an infinite loop.

as there is still a newline character left in the stdin buffer, in the
next loop, the variable 'i' will automatically get a newline
character, which is 10 in ACSII
Wrong. %d will get a integer until a newline or a space is encountered and the newline character in the buffer will not be consumed by the next scanf()
So always check the return value of scanf()
if(scanf("%d",&i) != 1)
{
printf("scanf failed\n");
return 1;
}
As a side note:
case 10:
printf("Newline detected!");
There is a a break missing in this case.

Addressing the second program in the question, here's a mildly revised version. It prints more information, and uses strict prototypes.
#include <stdio.h>
#include <stdlib.h>
void output(void);
int main(void)
{
int i;
printf("Enter a number here:\n");
if (scanf("%d", &i) == 1)
printf("Read %d OK\n", i);
output();
return 0;
}
void output(void)
{
char a;
if (scanf("%c", &a) != 1)
{
printf("scanf error!!");
exit(1);
}
printf("Character %d (%c) entered\n", a, a);
switch (a)
{
case 'a':
printf("an char a is entered\n");
break;
case 'b':
printf("an char b is entered\n");
break;
default:
printf("%c", a);
printf("other thing is entered\n");
break;
}
}
Example runs:
$ ./stdin
Enter a number here:
23499911
Read 23499911 OK
Character 10 (
) entered
other thing is entered
$ ./stdin
Enter a number here:
2A
Read 2 OK
Character 65 (A) entered
Aother thing is entered
$ ./stdin
Enter a number here:
19b
Read 19 OK
Character 98 (b) entered
an char b is entered
$ ./stdin
Enter a number here:
999a
Read 999 OK
Character 97 (a) entered
an char a is entered
$
Note that in the first run, the stray character is the newline after the second 1 digit, character code 10. This is what you should get.
Do make sure your output print operations end with a newline (so that it appears in a timely manner). If you don't, your output may be held up indefinitely.
Do you mean that the scanf() function will not strip the newline character in the stdin buffer?
The scanf("%d", &i) certainly doesn't. The scanf("%c", &a) does. When scanf() completes a conversion, it puts the character that is not part of the conversion back into the input stream ready for the next input operation. So, it doesn't matter whether there's a space, a letter or a newline after the number, that character is left ready for the next input operation to read it. Most scanf() operations skip leading white space. There are three exceptions: %c, %n and %[…] (scansets). They do not skip leading white space.

Related

What is the purpose of this dummy variable variable and why program exits without it in c? [duplicate]

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed last month.
int main ()
{
char c;
int choice,dummy;
do{
printf("1. Print Hello\n2. Print World\n3. Exit\n");
scanf("%d",&choice);
switch(choice)
{
case 1 :
printf("Hello\n");
break;
case 2:
printf("World\n");
break;
case 3:
exit(0);
break;
default:
printf("please enter valid choice\n5");
}
printf("do you want to enter more?");
scanf("%d",&dummy);
scanf("%c",&c);
}while(c=='y');
}
tried removing int dummy variable and dummy input, program exits without taking any character input. how is this helping the code to not to exit ?
Whoever wrote this doesn't understand how scanf format specifiers work.
The first call to scanf uses the %d format specifier. This reads and discards any leading whitespace, then reads a decimal integer. Assuming you pressed ENTER after typing in this integer, a newline character will be left in the input buffer.
The %c format specifier reads the first character in the input buffer but does not strip off trailing whitespace. So without the prior call reading dummy, this will read the newline that was stuck in the input buffer previously into c. That causes the comparison c=='y' to be false so the loop exits..
The extra call to scanf for dummy reads and discards the newline left in the input buffer and wait for an integer to be read. Presumably, the user will enter y or n given the prompt, so that call to scanf will not read anything more and will return 0, indicating that nothing matched. The following scanf then reads the y or n.
The proper way to handle this is to add a space before the %c format specifier to absorb leading whitespace instead of adding a "dummy" call:
printf("do you want to enter more?");
scanf(" %c",&c);
The scanf("%d",&dummy) removes a newline so the subsequent scanf("%c",&c); works. Otherwise, it will take \n as its character.
The "extra" newline comes from the fact that it is left in the input stream by the original: scanf("%d",&choice);
To fix, remove the dummy related code and do:
scanf(" %c",&c);
Note the preceding space in the format. This tells scanf to skip over whitespace (which includes newlines).
The fully corrected code is:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
char c;
int choice;
do {
printf("1. Print Hello\n2. Print World\n3. Exit\n");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Hello\n");
break;
case 2:
printf("World\n");
break;
case 3:
exit(0);
break;
default:
printf("please enter valid choice\n5");
}
printf("do you want to enter more?");
scanf(" %c", &c);
} while (c == 'y');
return 0;
}

What is the difference between scanf("%s", &str) and scanf("%s\n", &str)?

Input
There will be several lines in the input terminated with a line containing a single *. This last line
should not be processed. Each of the lines will contain either Hajj or Umrah.
Output
For each line of the input, output either Hajj-e-Akbar or Hajj-e-Asghar in separate lines without
quotations. For the exact format refer to the sample.
Here's my code for this problem.
#include <stdio.h>
int main()
{
char str[100];
int i = 1;
while (scanf("%s", &str))
{
if (str[0] == '*')
break;
else if (str[0] == 'H')
printf("Case %d: Hajj-e-Akbar\n", i);
else
printf("Case %d: Hajj-e-Asghar\n", i);
i++;
}
}
For the input
Hajj
Umrah
*
When I gave this input at a time, the program provides the expected output by printing
Hajj
Case 1: Hajj-e-Akbar
Umrah
Case 2: Hajj-e-Asghar
*
But after getting * as input, the program is waiting for an Enter. After hitting Enter, the program terminates. But I want my program to terminate, whenever it gets * as input, not by pressing Enter. Please help me here. But this is not my question. My question is for the same input-
Hajj
Umrah
*
When I take input by scanf("%s\n", &str). The program does not print the output Case 1: Hajj-e-Akbar after the first input Hajj but it prints the output for first input after taking the second input Umrah. Then the program is waiting for an Enter for the input *.
The output is like this
Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Then I press Enter, it prints the output Case 2: Hajj-e-Asghar for the second input Umrah
and then waits for another input. This the output looks like after pressing Enter.
Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Case 2: Hajj-e-Asghar
I don't understand how \n is making a difference in scanf.
Thank you.
I'm sorry if I can't explain my question correctly. I am new to programming.
scanf reads formated input, so when you use %s\n”, &str the string will consumed and stored in str as will the newline character , which will be present in the buffer when you press enter, the string will be stored and the newline character will be discarded.
Note that the correct usage is “%s\n”, str, str is already a pointer you shouldn't use &.
When you use “%s”, &str the newline character will be left in the buffer and will be consumed in the next loop, so str will be stored in the first iteration, and "\n" will be stored in str in the next iteration, only then you will be asked for input again, in the third iteration.
For completion, as stated in the comments bellow, as per the definition of scanf:
...any single whitespace character in the format string consumes all available consecutive whitespace characters from the input (determined as if by calling isspace in a loop). Note that there is no difference between "\n", " ", "\t\t", or other whitespace in the format string.
I would also advise you to limit the size of the string expected by scanf to avoid container overflow, something like %99s for a 100 charaters container like you have, and also check scanf return, in this case, it must be = 1 for each cycle.
To do what you want, which I gather is to get a character from stdin without pressing return you will need a SO specific method, here is a small example for Windows using <conio.h> library, and getch():
#include <stdio.h>
#include <conio.h>
int main()
{
int i = 1, c;
while (1)
{
if ((c = getch()) == '*')
return 0;
else if (c == 'H')
printf("Case %d: Hajj-e-Akbar\n", i);
else
printf("Case %d: Hajj-e-Asghar\n", i);
i++;
}
}
For Linux one option is to use also getch() from <ncurses.h> library, which you might need to install.
PS: Don't worry, your question is well built, specially being only the second in the site.
The trailing \n in the scanf is a bad idea: any whitespace character in the format string causes any sequence of whitespace characters to be discarded from the input stream. If reading from a file, you will not necessary have a problem but if you read from the terminal, scanf() will not return until you have typed the next item, and this will create major confusion as you experience, because the program's output will correspond to the previous item, not the one that was just typed... Never add trailing spaces or newlines in a scanf() format string.
You should test if scanf() returns 1 to avoid an infinite loop when it returns EOF at the end of file.
Note also that it is incorrect to pass &str: str is an array, passing it as str will effectively pass a pointer to its first element, which is correct.
Furthermore, you should tell scanf() the maximum number of characters that can be stored into the destination array to avoid undefined behavior on overlong input. Since the array is defined with a size of 100, the format string should be "%99s" to leave space for the null terminator.
Finally, you need to hit Enter after the final * for 3 combined reasons, each of which would force this behavior:
the terminal device driver is line buffered by default, so the input is not made available to the program until you type Enter.
the standard input stream (stdin) is line buffered by default, so it will read data from the system handle until it gets a newline, and only then does scanf() get a chance to see the first character of the entered line.
scanf("%s", str) will keep its input stream until it gets the end of the word, a whitespace character or the end of file, so it does not return when you type just *.
Here is a modified version:
#include <stdio.h>
int main() {
char str[100];
int i = 1;
while (scanf("%99s", str) == 1 && str[0] != '*') {
if (str[0] == 'H') {
printf("Case %d: Hajj-e-Akbar\n", i);
} else {
printf("Case %d: Hajj-e-Asghar\n", i);
}
i++;
}
return 0;
}

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.

Infinite loop code in C

In the below program I try to input a number between 1 to 100 but if I enter a 'character' or "string" ( like s or sova ) during the execution time of scanf() statement it creates a infinite loop. so I try to do .... when I input a string or a character it shown me a message like "wrong value entered. enter again" and it will enter again...
Thanx;
#include<stdio.h>
int main()
{
int a;
scanf("%d",&a);
while(!(a>=1&&a<=100))
{
printf("wrong value entered. enter again\n");
scanf("%d",&a);
}
printf("you enter %d. Thanxz",a);
return 0;
}
You need to check the return value of scanf
If the user has not entered a integer, you need to eat the input. The scanf function will continually say not a integer, try again. So if scanf returns 0 you need to deal with it
When you use scanf you are working with buffered input, this means that when you enter a value say "123" and press ENTER then "123" plus the ending character (ENTER) will all be added to the buffer. scanf then removes 123 since %d specifies that an integer should be read but if a user enters something invalid like a string instead then the buffer will not be emptied.
A better way to read input from the keyboard is to use fgets() where you specify a max length to read. Once you have the input you can use sscanf() to retrieve the numeric value from it. The ENTER till then not irritate your input.
char buffer[128];
fgets( buffer, 128, stdin );
sscanf( buffer, "%d", &a );
Also always check return values from functions as a rule of thumb so that you can do appropriate action if the function fails.
If the return value from scanf is not equal to the number of item you like the user to input, read all characters of the input buffer until there is a '\n'. But instead of copying a whole loop over and over again to the places in your code where the user should input something, you could wrap the loop in a function like this:
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
void input(const char *format,...)
{
va_list ap;
int r;
/* number of items [to read] */
int noi=0;
for(r=0;r<strlen(format)-1;r++)
{
if(format[r]=='%')
{
if(format[r+1]!='%')
noi++;
else
r++;
}
}
do
{
va_start(ap,format);
r=vscanf(format,ap);
va_end(ap);
if(r!=noi)
{
switch(r)
{
case EOF:
case 0:
printf("All wrong, try again!\n");
break;
default:
printf("Unexpected value after item no %d!\n",r);
}
while(getc(stdin)!='\n');
}
else
break;
} while(1);
}
Hope that helps,
Jan
Try this.
#include <stdio.h>
#define FLUSH while (getchar() != '\n') // macro to eat invalid input
int main (void) {
int a = 0;
printf ("Enter an integer: ");
scanf("%d", &a);
while (a < 1 || a > 100) {
FLUSH;
printf("Invalid input. Please try again: ");
scanf("%d",&a);
}
printf("You entered %d.\nThanks!\n", a);
return 0;
}
Your code shows several coding habits that need to be changed:
Include (void) in the parameter list of main().
Leave spaces on either side of binary operators: while(!(a>=1&&a<=100)) is needlessly ugly and hard to read.
Simplify your logical expressions. Why use (! (a>=1 && a<=100)) when it means the same thing as (a < 1 || a > 100), and the latter is so much easier to read?
Prompt for user input when needed. Don't have the cursor just sit at a blank line with no indication to the user about what to do.
Use proper grammar and capitalization in your prompts. There's no reason to be lazy in your programming.

unable to compare more than one character

I have written two programs. In the first one I'm not using getchar to take a character from keyboard, in this case, the compilation is completely missing the second scanf. So to overcome this I have used getchar. In this case I'm successfully able to give input but comparison is not happening. Though I have given input as "d" and "d" output is "bye" only.
#include<stdio.h>
main(){
char c,f;
printf("e");
scanf("%c",&c);
printf("one more");
scanf("%c",&f);
if(c=='d'&&f=='d')
printf("hi");
else
printf("bye");
}
with getchar
#include<stdio.h>
main(){
char c,f;
printf("e");
scanf("%c",&c);
printf("one more");
scanf("%c",&f);
getchar();
if(c=='d'&&f=='d')
printf("hi");
else
printf("bye");
}
The new line character will remain in standard input as it will not be consumed by the scanf("%c"). This means the second scanf() reads the newline charcacter, and not the next input. Changing to scanf(" %c") would be a solution, which will skip leading white space.

Resources