While loops duplicates printf two times before getting to getchar()? [duplicate] - c

This question already has answers here:
Using getchar() in a while loop
(3 answers)
Closed 9 years ago.
I'm currently learning C and C++ on my own. In this little "program practice" I ask the user to enter either 'i' or 'd' to know whether they want to work with integers or decimal (float) numbers. I have a while loop that makes sure the user enter 'i' or 'd' by telling them if they entered the wrong char. For some reason, the prompt inside the while loop prints two times before going to the getchar(). I'm having a bit of hard time understanding what's happening under the hood in this situation. Any help is super appreciated. I'm using Xcode (don't know if it's relevant).
#include <stdio.h>
int main()
{
char action;
printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n");
scanf("%c", &action);
while (action != 'i' || action != 'd')
{
printf("You didn't entered the right command. Please try again (i/d)\n");
action = getchar()
}
}
So what I'm getting as an output is this:
You didn't entered the right command. Please try again (i/d)
You didn't entered the right command. Please try again (i/d)

What is happening is that when you enter a character and hit a return, you are actually entering two characters - the character and the return character ('\n'). The loop executes once for each character. Which is why you see it go through twice.
The trick is to filter out the return character explicitly, like so:
#include <stdio.h>
int main()
{
char action;
printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n");
scanf("%c", &action);
while (action != 'i' || action != 'd')
{
if (action != '\n')
{
printf("You didn't entered the right command. Please try again (i/d)\n");
}
action = getchar();
}
}

As correctly diagnosed by Ziffusion in his answer, you get the double prompt because you get the newline after the user's incorrect input as a separate character, and that too is neither i nor d.
Here is a rewrite with some improvements:
#include <stdio.h>
int main(void)
{
char action = '\0';
printf("Please enter 'i' to work with integers or 'd' to work with decimals: ");
while (scanf(" %c", &action) == 1 && action != 'i' && action != 'd')
printf("You didn't enter the right command. Please try again (i/d): ");
printf("Action selected: %d\n", action);
}
What's changed?
The prompt doesn't end with a newline, so the user's response appears immediately after it. Standard I/O normally synchronizes standard output and standard input so that the prompt will be flushed, despite not ending with a newline. If the prompt doesn't appear, you can add a fflush(stdout); or fflush(0); after each of the prompting printf() statements.
The result of scanf() is checked to deal with EOF.
The format of scanf() includes a leading space. This will skip white space before the character that's returned, so you get a non-blank, non-newline character.
The original condition action != 'i' || action != 'd' is always true; you need the && instead.
Nitpick: improve grammar of error message.
Note that after the loop, action might not be either i or d if the user triggered EOF (typed Control-D or equivalent). If you get EOF (for example, the user ran the program with standard input from /dev/null), you would not have a deterministic value in action except for the initialization to '\0'.

Here I fixed you code:
#include <stdio.h>
int main()
{
char action;
printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n");
scanf("%c", &action);
while (action != 'i' && action != 'd') // here the loop will stop if action is 'i' or 'd'
{
printf("You didn't entered the right command. Please try again (i/d)\n");
scanf("\n%c", &action);// here to deal with '\n'
}
}

Related

Having trouble with do...while loop

So basically I'm trying to create a simple buffer for input.
If the user inputs something other than the letter 'R' or 'S', then the do while loop will return the code back to where the user inputs the letter.
However, when I tried entering 'Z' for example, the loop repeats itself twice, asking for input on the second loop.
I don't understand why, please help me understand.
I tried... using a while loop? That doesn't work. I don't want to use goto.
<stdio.h>
<stdlib.h>
int main(void)
{
char r_or_s;
printf("Number Reverser/Shuffler v0.1\t");
printf("Written by REN\n");
printf("This program reverses and shuffles the order of numbers.\n\n");
do
{
printf("Would you like to reverse or shuffle numbers? (Press R/S):");
r_or_s = getchar();
printf("\n");
if (r_or_s == 'R')
{
reverseno();
}
else if (r_or_s == 'S')
{
shuffleno();
}
} while (r_or_s != 'R' || r_or_s != 'S');
return 0;
}
Expected output of
Would you like to reverse or shuffle numbers? (Press R/S):
after rejection of input, but the actual output is:
Would you like to reverse or shuffle numbers? (Press R/S):
Would you like to reverse or shuffle numbers? (Press R/S):
This happens because you input 'Z' for example, then you also pressed the Enter!
So, how many characters did you input? Two!
Then getchar() consumes 'Z' from the standard input buffer, goes back to read again from user, but the newline character (Enter) awaits in the Standard input buffer.
As a result, getchar() consumes the newline character now, resulting in "the loop repeating itself twice".
You have to take into account the newlines as well. For instance, you could do this:
if(r_or_s == '\n')
r_or_s = getchar(); // we read the trailing newline character before, read again
Moreover, you want to stop looping when the user input 'R' or 'S, thus you need to change this:
while (r_or_s != 'R' || r_or_s != 'S');
to this:
while (r_or_s != 'R' && r_or_s != 'S');

In C - scanf() in a for loop is causing printf() to run multiple times

I'm completing an assignment and after completing it, I have 1 bug, and 1 bug fix I made that I don't fully understand. Currently, as long as the user does what is asked, everything works fine. But I know that doesn't happen often, so I'd love to know how to stop these issues.
Would love any advice - I am a complete beginner with C.
I found many different pieces of advice here: C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf
I added a space to my scanf() statements which solved some of the bugs - and I understand that \n is added onto the end of the entered strings / chars, I'm just not sure how to check for it / handle it, and I tried using getchar() in place of the scanf() but I still get double print / loop problems.
Bug Issue
When the user is running through the game loop, if they enter more than 1 character (for example: 'oo', when prompted with the scanf() to enter 'y' or 'n') my printf statements run 1x per character entered, and connect to each other:
Example would be:
Welcome to Two doors.
Would you like to play? (y/n):Welcome to Two doors.
Would you like to play? (y/n):
This issue also shows up if the user enters 'y' to play the game but then enters a character other than 1,2 or 3 in the second section.
How can I limit the length of their response? Or is the best way to monitor the length of the play and choice variables prior to entering the if statements? Maybe checking to see if they are longer than 1 character and if so, only taking the first character?
Second issue - bug fix that I don't understand
In the scanf() functions I ran into a very similar problem to what I described above, but it happened when the user entered any character. The solution I found was to add a space before the character ->
scanf(" %c", &play);
vs
scanf("%c", &play);
Is this issue only a problem when using loops? Since I never found these bugs prior to looping back through the code.
Updated Code with 'while (getchar() != '\n');' suggestion from Sourav Ghosh
#include <stdio.h>
int main(void) {
char play;
int choice;
char answer[] = "No matter which one you choose the guards both tell you which door leads to death, and therefore you can pick the other door.\n";
int gameLoop = 1;
int timesPlayed = 0;
while (gameLoop == 1){
if (timesPlayed == 0) {
printf("Welcome to Two doors.\n");
printf("Would you like to play? (y/n):");
} else {
printf("Would you like to play again? (y/n):");
}
scanf(" %c", &play);
while (getchar() != '\n');
if (play == 'y') {
// == instead of =
printf("\nYou are a prisoner in a room with 2 doors and 2 guards.\n");
printf("One of the doors will guide you to freedom and behind the other is a hangman --you don't know which is which.\n");
printf("One of the guards always tells the truth and the other always lies. You don't know which one is the truth-teller or the liar either.\n");
printf("You have to choose and open one of these doors, but you can only ask a single question to one of the guards.\n");
printf("What do you ask so you can pick the door to freedom?\n\n");
printf("\t1.Ask the truth-guard to point to the door of doom.\n");
printf("\t2.Ask the liar-guard to point to the door of doom.\n");
printf("\t3.Doesn't matter which one you pick.\n");
scanf(" %d", &choice);
while (getchar() != '\n');
switch (choice) {
case 1:
printf("%s", answer);
timesPlayed++;
break;
case 2:
printf("%s", answer);
timesPlayed++;
break;
case 3:
printf("%s", answer);
timesPlayed++;
break;
default:
printf("The Troll Smasher comes out from the shadows and squeezes the stupid out of you until you pop. GAME OVER!\n");
break;
}
} else if(play == 'n') {
printf("Sorry to hear that, we at Two Doors hope you have a super duper day!\n");
gameLoop = 0;
break;
} else {
printf("That is not a valid input, please try again by entering either 'y' to start the game or 'n' to quit the game.\n");
}
}
return 0;
}
The problem with %c format specifier is that, it will read only one byte from the input buffer and if the input buffer has more in store and the call in encountered next time, it will not ask for user input, it will simply read the next byte from the available input stream.
So, to answer
How can I limit the length of their response?
well, there's no straightway approach that you can stop the user from entering only X characters/ digits, instead, swipe off the excess, (if any) and for the next call, start with an empty buffer is an easy approach.
So, the quick way out of this would be, to clean off the standard input of remaining inputs. You can do something like
int retval = scanf(" %c", &play);
//some code
while (getchar() != '\n'); //eat up the input buffer
//next call to scanf(), input buffer is empty now....
to stop scanf() from reading already existing unwanted inputs and force it to ask the input from user.
Also, don't forget to check the return value of scanf() to ensure the success of the call.
For the first issue the problem is caused because the execution of the program enters the loop again for example if the user types oo that means that after reading with scanf it is going all the way to the last else.
Inside that else none of the variables is modified so when it reenters the loop gameLoop is still 1 and timesPlayed is still 0 so it will print the statements in the first if, then scanf will read the second o and repeat the process. The problem is that scanf reads one character at the time.
Actually for entering one character you can use getchar() but in any case after char input you should clean standard input stream. Consider the following example, that forces the user to the correct input:
char name[11];
char answer = 0;
printf("Would you like to play again? (y/n): ");
while ((answer = getchar()) != 'y' && answer != 'n')
{
printf("You should answer 'y' or 'n'\n");
// clean the buffer from mess
while (getchar() != '\n');
}
// clean the buffer from mess
while (getchar() != '\n');
// next input
printf("Enter your name: ");
scanf("%10s", name);
// clean the buffer from mess
while (getchar() != '\n');
UPDATE:
Just for clarification, the code
while ((answer = getchar()) != 'y' && answer != 'n')
{
printf("You should answer 'y' or 'n'\n");
// clean the buffer from mess
while (getchar() != '\n');
}
can be be easier to understand while rewritten as
char name[11];
char answer = 0;
printf("Would you like to play again? (y/n): ");
while (1) // infinit loop
{
answer = getchar();
// clean the buffer from mess (immideatly after reading)
while (getchar() != '\n');
if (answer == 'y' || answer == 'n') // check the input
break; // stop the loop if condition is true
// or ask again
printf("You should answer 'y' or 'n'\n");
}
// next input
printf("Enter your name: ");
scanf("%10s", name);
// clean the buffer from mess
while (getchar() != '\n');
in my first example I just optimize the code combining reading and checking the data in parentheses after while: (answer = getchar()) != 'y' is like two actions - answer = getchar() and then answer != 'y'
In the last snippet condition answer != 'y' && answer != 'n' was intentionally replaced with answer == 'y' || answer == 'n' to show difference between "do while data is incorrect" and "stop when correct data get"

Beginning C and I have a bug that is killing me [duplicate]

This question already has answers here:
Problems with C scanf("%c") function to read characters one by one
(4 answers)
Closed 6 years ago.
I am writing some code and I have a prompt in the program driven by a while loop where you make a choice. However, it prints the prompt twice every time it goes through the loop and I just can't figure it out.
while (choice != 'x');
{
printf("\nChoice (a)dd (v)iew e(X)it [ ]\b\b");
scanf("%c",&choice);
if (choice == 'a') add_record();
if (choice == 'v') view_record();
}
The printf line is the one that prints twice. Thanks in advance for any help.
When you enter a character (i.e. type 'a' and press 'Enter'), the newline character ('\n') is also being read in from stdin. You can add a leading space to the format specifier to avoid this:
scanf(" %c", &choice);
The space indicates to scanf to ignore whitespace characters (such as '\n').
There are few things to notice in the question posted.
The outer while loop behavior depends on the variables initialization at first then the values being entered subsequently.
It then manipulates into print the prompt to enter choice, repeatedly (not just twice) depending on how many characters entered as input before 'enter' key is pressed.
The char i/o driver buffers the input entered and each of the characters entered is read by scarf() one at a time in this case, from the buffer. So it is needed to rewrite the code to work as following (expected from my understanding)
char choice = '!', ws = ' ';
int attempts = 0;
while (choice != 'x')
{
printf("\nAttempt:%d Choice (a)dd (v)iew e(X)it [ ]\b\b", ++attempts);
// Eat up the '\n', if one exist and Wait for valid input
while ((scanf("%c", &choice) > 0) && (choice == '\n'));
// Eat up all white space and other chars entered so far, except the last '\n'
while ((scanf("%c", &ws) > 0) && (ws != '\n'));
if (choice == 'a') add_record();
if (choice == 'v') view_record();
}

How can I read only one character and ignore the others if the users types more?

I have a project that must be made only in C (I'm not allowed to use C++).
Right now I'm working on the UI (a little menu showed in the console, each option has a number from 0 to 6 assigned to it, the user typed the number, hits enter and so on).
I'm having a problem with the reading option function.
At first I tried
int option;
scanf("%d", &option);
but this caused problems when I typed in characters.
I tried reading a char:
char option;
scanf("%s", &option);
option -= '0';
This allowed me to treat it like a number and worked nice for the first tests, allowing me to verify if the option is valid (it's not a letter, it's a number between 0 and 6).
The problem is that I can type more than one character and all of them will be stored somewhere in memory. And that's obviously bad.
I tried reading with "%c", but that will display the error message for every character in the string I entered.
To make it a bit more clear, this is the function
int readOption(int maxOp)
{
char option = -1;
while(option < 0 || option > maxOp)
{
scanf("%c", &option);
option -= '0';
if(option < 0 || option > maxOp)
printf("Invalid option!\nTry again: \n");
}
return option;
}
If I type "abc", the error message will be printed 3 times.
So how can I make sure that any extra characters entered are ignored?
Try this
int ch;
scanf(" %c", &option);
while((ch = getchar()) != '\n');
Untested, buy you may try something like this:
scanf(" %[0-6]1d*[^\n]", &option);
The call to scanf will only be valid if the input is a single number between 0 and 6, ignoring leading spaces. * suppresses any character after that isn't in this range and that is not a newline.
You can use getc() to do the job like this:
int main(){
char choice = getc(stdin);
fflush(stdin);
}
Now choice is the first entered character, everything entered after the first character is deleted so it won't interrupt any other user inputs.
In general, when the user enters input it's stored in a special buffer called stdin, if you don't delete that buffer after reading the first character using fflush(stdin) it will interrupt any future user inputs.

How Does Char Variable Work in C

What I am trying to accomplish is prompting the user with the question of do they want to run the program again. They either type y or n. If y, it reruns the program. If no, it stops the program. Anything other than those two will prompt an error and ask the question again. I'm used to C# where strings are not complicated, but in C, I guess there technically isn't strings, so we have to use either char arrays or char pointers. I've tried both, none that work that way I want, but I'm probably the problem. This is what I have.
char answer[1] = "a";
while (strcmp(answer, "y") != 0 || strcmp(answer, "n") != 0)
{
printf ("\n\nWould you like to run the program again? Type y or n. Then, hit Enter.");
scanf ("%c", answer);
if (strcmp(answer, "y") == 0)
{
main();
}
else if (strcmp(answer, "n") == 0)
{
continue;
}
else
{
printf ("\nERROR: Invalid input was provided. Your answer must be either y or n. Hit Enter to continue.");
F = getchar();
while ((getchar()) != F && EOF != '\n');
}
}
I have other while loops similar to this that work as expected, but use a float. So I'm assuming the problem is me using char here. What happens right now is that it doesn't even prompt the user for the question. It just asks the question and shows the error right afterwards. I'm sure there are other things wrong with this code, but since I can't get the prompt to work, I cannot test the rest of it yet.
I suggest using a light weight getchar() instead of the heavy scanf.
#include <stdio.h>
int c; /* Note getchar returns int because it must handle EOF as well. */
for (;;) {
printf ("Enter y or n\n");
c = getchar();
switch (c) {
case 'y': ...
break;
case 'n': ...
break:
case EOF:
exit(0);
}
}
"a" is a string literal == char id[2]={'a','\0'} //Strings are
char arrays terminated by zero, in C
'a' is a char literal
strcmp is just "compare each char in two strings, until you hit '\0'"
scanf ("%c", ___); expect an address to write to as the second
argument. Functions in C cannot modify their arguments (they don't
have access to them--they get their own local copy) unless they have
a memory address. You need to put &answer in there.
Jens has already basically answered the question, you most likely want to use getchar so that you can detect EOF easily. Unlike scanf("%c",...), getchar will not skip spaces, and I believe both versions will leave you with the unprocessed rest of the input line (a newline character ('\n') at least) after each getchar. You might want to something like
int dump;
while((dump=getchar())!='\n' && dump!=EOF) {};
So that you discard the rest of the line once you've read your first character of it.
Otherwise, the next getchar will get the next unprocessed character of the same line. ('\n' if the line was a single letter).
Here is one way to do it. It is by no means the only way to do it, but I think it accomplishes what you want. You should not call the main function recursively.
#include <stdio.h>
#include <stdlib.h>
void run_program()
{
printf("program was run.");
}
int main() {
char answer[2] = "y\0";
int dump;
do {
if (answer[0] == 'y')
{
run_program(); /* Not main, don't call main recursively. */
}
printf ("\n\nWould you like to run the program again? Type y or n. Then, hit Enter.\n");
scanf ("%1s", answer);
/* Dump all other characters on the input buffer to
prevent continuous reading old characters if a user
types more than one, as suggested by ThorX89. */
while((dump=getchar())!='\n' && dump!=EOF);
if (answer[0] != 'n' && answer[0] != 'y')
{
printf ("Please enter either y or n\n");
}
} while (answer[0] != 'n');
return 0;
}
Using %s instead of %c, reads in the new line so that the new line character is not in the stdin buffer which would become answer then next time scanf was called.
The run_program function is just a function where you would put your program's logic. You can call it whatever you want. I did this to separate out the menu logic from the logic of the actual program.
Well, you are comparing two strings instead of characters.
If you want to compare two character you have to follow this syntax:
char c;
scanf("%c",&c);
if(c == 'y')
//do something
else
//do nothing

Resources