Do-While loop in C - error at printing - c

I am making a little program that takes as input the answer to the question "Are you an adult?" as a character like that:
bool adult() {
char answer;
do {
printf("Are you an adult? [y/n]\n");
answer = getchar();
} while (!(answer == 'y' || answer == 'n'));
return (answer == 'y');
}
My aim was that the question should repeat itself if the answer is neither y or n. But this seems to have a bug:
When I answer something else (neither y or n), the question gets printed twice:
Are you an adult?
u
Are you an adult?
Are you an adult?
...
Why is this happening?
Also, I've tried the same method with scanf instead of getchar but there is the same bug. For this kind of program, should I use scanf or getchar and why?
Thanks!

Actually the extra '\n' in the answer with (yes) y or (no) n gets counted and it's printed twice. You just remember to get that dummy '\n'. Use another extra getchar(). The dummy getchar() is a solution to this problem.
bool adult() {
char answer;
do {
printf("Are you an adult? [y/n]\n");
answer = getchar();
getchar(); //~~~~~~~~~~~~~~~~~~~~> this is what gets the extra '\n'
} while (!(answer == 'y' || answer == 'n'));
return (answer == 'y');
}
You can check my other answer here.You will get a clear idea.
the input buffer in getchar() and scanf
EDIT: As pointed out by Random832 in case of yes\n the ye is consumed but not the s\n. so a better solution is to store the first character and consume every other character until \n using a do..while or while loop. Then check the first character. Or you can store the whole string as per your need and use the first character to get the answer.
EDIT 2: flushing is not a solution to this problem. Previously I mentioned it. iharob pointed out to me that. You can check this two answers to get a clear idea.
Flushing buffers in C
How to clear input buffer in C?

To make the code robuts, i.e. for it to work with any input, you might need to read all the characters that you are not going to consider as valid, including the '\n' that is sent when you press enter and flush the input buffer, which you can't do by using fflush(), because it's only defined for output buffers, you should also consider the case of an empty line, i.e. when the user presses Enter immediately, the following code does all what I describe
#include <stdio.h>
#include <stdbool.h>
bool
adult()
{
char answer;
do {
int chr;
printf("Are you an adult? [y/n] ");
answer = getchar();
if (answer == '\n')
continue;
while (((chr = getchar()) != EOF) && (chr != '\n'));
} while (!(answer == 'y' || answer == 'n'));
return (answer == 'y');
}

Related

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"

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

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

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

Do-While loop in C

I recently started working with C programming language, about two or three days ago, but I encountered some problem when working with the do-while loop, This is part of my program that would not run.
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
int main(void){
char another_game = 'Y';
scanf("%c", &another_game);
do{
printf("\nWould you like to continue(Y/N)?");
scanf("%c", &another_game);
}while(toupper(another_game) == 'Y');
return 0;
}
The loop is suppose to continue running as long as the user types 'Y' or 'y' when prompt to do so, but I noticed that after the program executes the loop the first time it just displays the question again and then the loop breaks. I tried using integers, for the user to type 1 when he wishes to continue or 0 when he wishes to quit, it worked, so I do not understand why this one would not. I would appreciate all help on solving this issue, thanks
Because when you press <enter>, there's the trailing newline character in the stdin buffer. Better use fgets() instead:
char buf[0x10];
fgets(buf, sizeof(buf), stdin);
if (toupper(buf[0]) == 'Y') {
// etc.
}
I would use getchar as it would be more deterministic for your purposes. Also be sure to add one more getchar to check for newline character.
do {
printf("enter Y/N\n");
} while( ( (toupper(getchar()) == 'Y') + (getchar() == '\n') ) == 2);

scan a variable and use it in do while loop

#include <stdio.h>
void main()
{
char ans='n';
do
{
printf("\n Enter yes or no:");
scanf("%c",ans);
printf("\n entered %c",ans);
}while(ans == 'y');
}
As do while the loop is getting exccuted and that scanf is working and prnting my answer (say my answer is y) , its coming for 2nd time but not doing the scan and getting exited . May i know the reason for this ? why it is happening and what is the correct way to handle the infinite loop.
First up, you're missing a & in the scanf:
scanf("%c", &ans);
^
Second, you're not handling the newline, and the %c format specifier doesn't ignore blanks. So you read a character, press return, and the next scanf is immediately satisfied by that \n. To ignore blanks in scanf try:
scanf(" %c", &ans);
^
Not only are you missing the &address-of operator as indicated in other answers, but you're also missing the return value checks. Consider if a user presses CTRL+Z in Windows, or CTRL+d in Linux, to close stdin. Your loop would run infinitely and freeze your app ;)
if (scanf("%c", &ans) != 1) {
break;
}
Alternatively, I would suggest using getchar because it's far cleaner:
int main(void) { /* NOTE: There is no "void main()" entrance point in C. main should always return 'int'. */
int c;
do {
c = getchar();
} while (c == 'y');
return 0;
}
Use fflush(stdin) to flush those return feeds.
But when you are inputting a single character, then why not use getchar()?
EDIT:
As correctly pointed out by cnicutar here, fflush(stdin) has undefined behaviour. There doesn't seem to be any inbuilt function to take care of that and hence must be taken care of in the code itself.
One example could be:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
Thanks for pointing that out there!

Resources