A simple while loop to check input stuck in infinite loop - c

I am pretty sure this was asked before but I could not find any answers, so here I go. This is a simple line of code and I cannot get it to exit the while loop. If I change the || to && the loop just exit no matter what I press. Thank you for the answers.
#include <stdio.h>
int main()
{
int answer;
printf("Are you sure you want to exit the program? Type in 1 for yes and 2 for no.\n");
scanf("%d", answer);
//This is to check that the user inputs the right number if not error message is displayed
while(answer <1 || answer > 2)
{
printf("Please type in 1 to exit the program and yes and 0 to keep playing. \n");
scanf("%d", answer);
flushall();
}
return 0;
}

If You want to exit on 1, then You just need to check if input is equal to it, that is why I want to scan for more answers when it is not equal to 1. If it is then it will omit while loop and go directly to return 0.
Also I changed the way of usage of scanf - when you declare a variable (in Your case answer), system gives it an address in the memory. Then you use scanf to take an input from the user, and after you take the input, you write it on the address of that variable so that when you refer to it later, the system goes to the address and retrieve the value.
int main()
{
int answer;
printf("Are you sure you want to exit the program? Type in 1 for yes and 2 for no.\n");
scanf("%d", &answer);
//This is to check that the user inputs the right number if not error message is displayed
while(answer != 1)
{
printf("Please type in 1 to exit the program and yes and 0 to keep playing. \n");
scanf("%d", &answer);
}
return 0;
}

This is one the frequent cases of misunderstanding/forgetting how scanf works.
int scanf ( const char * format, ... );
reads formatted data from stdin.
It reads data from stdin and stores data according to the parameter format into the locations pointed by the additional arguments.
The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.
It means that arguments should be pointers.
In your case:
int answer;
scanf("%d", answer);
answer is not a pointer but the variable (object) of type int.
To satisfy the scanf you have to use a pointer to the answer.
You can do it using the unary or monadic operator & which gives the address of a variable.
scanf("%d", &answer);
or you could use a pointer pointing to the answer:
int answer;
int answer_ptr = & answer;
scanf("%d", answer_ptr);
which is also correct but typically there is no need to go for this construction.
Secondly the line:
while(answer <1 || answer > 2)
You may want to modify it to
while (answer != 1 && answer != 2)
if you are interested in breaking the while loop when answer is being equal to 1 or 2.

Related

While using scanf("%i",var) if the user enters a letter or just presses enter i get a problem

I want for my program to just ask again if the user entered a letter or just pressed enter.
I know that if the input is not a number scanf() will return 0, so i have been doing this:
int variable;
printf("Please write an integer and then press enter: \n");
if (scanf("%i",&variable)!= 1) { /* ERROR CODE */; return 1;}
return 0;
But i dont want for my program just to stop if the input is not correct. So i tried this:
int variable;
do
{
printf("Please write an integer and then press enter: \n");
} while (scanf("%i",&variable) != 1);
But the program will just start printing "Please write an integer and then press enter:" without stoping. Is there a way of doing this?
edit: Forgot the &
edit2: Thanks to everybody.
edit3: I have been looking into the functions. Will this code be correct?
char variable[10]; int var;
do
{
printf("Please write an integer: ");
fgets(variable,sizeof(variable),stdint);
} while( sscanf(variable,"%i",&var) != 1 );
I have tried it and it works but i post it here because i know im probably missing something.
int variable;
do {
printf("Please write an integer and then press enter: \n");
} while (scanf("%i", &variable) != 1 && scanf("%*[^\n]") == 0);
The second scanf discards characters till the '\n' character. The '\n' character remains, though it will be skipped by the first scanf on the next iteration of the loop.
The code has some defects but it will work in most cases. One defect is that, if scanf returns EOF without reading a character then the loop will exit but the value of variable will be indeterminate, which can cause undefined behaviour when used. This one is not difficult to cure. Another one is that, the behaviour is undefined if the user enter a number outside of range for int. So a way better approach, is to use fgets and strtol library functions.

Generating a dice game - C Programming

I'm following a tutorial on youtube and was doing a dice generator.
It basically print out 3 dice result and sum out the dice result.
After which, the user will look at the sum, and based on the sum, the user going to guess whether the next roll is going to be higher,lower, or the same.
Below is my code, suppose, when I typed 'yes', it should be doing the code inside the if statement. However, it went straight to the else statement. Can someone please tell me what's wrong?
int answer;
int guess;
int diceRoll4 = 0;
printf("Would you like to guess your next dice? Y/N \n");
scanf(" %c", &answer);
if (answer == 'yes' ){
printf("What is your guess?\n");
printf("please key in your number \n");
scanf(" %d", &guess);
if (guess > diceRoll4 ){
printf(" You got it wrong, too high!");
}
else if (guess < diceRoll4){
printf(" You got it wrong, too low!");
}
else {
printf("You got it right");
}
}
else{
printf("Thanks for playing");
}
First of all, answer should be an array of chars in order to hold a string. Change
int answer;
to
char answer[10]; //Or any other reasonable size
Secondly, since you want to scan a string and not a character, change
scanf(" %c", &answer);
to
scanf("%9s", answer);
The 9 will scan a maximum of 9 characters (+1 for the NUL-terminator at the end), thus preventing buffer overflows.
I've removed & as %s expects a char* while &answer will give a char(*)[10]. Name of an array gets converted into a pointer to its first element char*, exactly what %s expects. The above scanf is thus equivalent to
scanf("%9s", &answer[0]);
Thirdly, comparing two strings using == compares pointers and not the actual content in them. Use strcmp from string.h instead. It returns 0 when both its arguments hold the same content. Change
if (answer == 'yes' ){
to
if (strcmp(answer, "yes") == 0){
Double quotes are used to denote a NUL-terminated string(char*), which is exactly what strcmp expects, while single quotes, as in your code, is a multi-character literal whose value is implementation-defined.
'yes' is a multi-byte character whose behaviour is implementation-defined.
What you probably want is to read and compare a single char:
if (answer == 'y' ){
or read a whole string and compare:
char answer[128];
scanf("%s", answer);
if ( strcmp(answer,"yes") == 0 ){
...
}
Notice that I changed the type of answer and used %s to read a string.
If you do not want to read in a string, but only a single char where the user can answer either Y or N, you should change int answer; to char answer;. You can then go on using your original scanf()-call. You will still need to change
if (answer == 'yes')
to
if (answer == 'Y')
If you want the user to either type in y or Y you could user toupper() from ctype.h and change your if-condition to if (toupper(answer) == 'Y').
To test the equality you have to use strcmp. If the returning value is 0 it means that they are equal.
if (strcmp(answer, "yes") == 0) {
// ...
} else {
// ...
}
Notes:
Using just answer == 'yes' it test the equality of pointers not value. This is the reason why enters only in else.
Because answer is int you have to change to an array
char answer[15]
As #Sathya mentioned you are reading just a char %c for reading a string you have to use %s
scanf("%s", answer);
Instead of 'yes' which is multi-character character constant change to "yes" that is an array of char with \0 at the end, more informations here.
this line:
if (answer == 'yes' ){
has several problems.
1) the definition of 'answer' is 'int' but the scanf is inputting a single character
2) answer could be compared with 'y' or 'n' but not to a array of char.
3) since the scanf only input a single char
and you/the user input 'yes',
only the first character was consumed,
so the 'es' are still in the input buffer
4) note the the single character could be anything, except white space.
the leading space in the format string would consume any white space.
so the user could input say 'y' or 'Y'
these are different characters
however, using the toupper() macro from ctypes.h
would mean only a 'Y' would need to be compared
5) if you decide to read a string,
then 'answer' needs to be a character array,
say: char answer[10];
and the scanf needs to have a max length modifier
on the associated "%s" input/conversion parameter
so as to avoid the user overflowing the input buffer
and the comparison would be via the strcmp() function
6) always check the returned value (not the parameter value)
from scanf to assure the operation was successful
7) diceRoll4 and guess can never be a negative number
so the variable definitions should be unsigned
and the associated scanf() for guess should use
something like "%u"
8) on the printf() format strings, always end them with '\n'
so the sting will be immediately displayed to the user,
otherwise, they will only be displayed
when a input statement is executed or the program exits

How to enter a letter to quit a program in C

I am new to C programming. I have been writing this code to add numbers and I just need help with this one thing. When I type the letter 'q', the program should quit and give me the sum. How am I supposed to do that? It is currently the number 0 to close the program.
#include <stdio.h>
int main()
{
printf("Sum Calculator\n");
printf("==============\n");
printf("Enter the numbers you would like to calculate the sum of.\n");
printf("When done, type '0' to output the results and quit.\n");
float sum,num;
do
{
printf("Enter a number:");
scanf("%f",&num);
sum+=num;
}
while (num!=0);
printf("The sum of the numbers is %.6f\n",sum);
return 0;
}
One approach would be to change your scanf line to:
if ( 1 != scanf("%f",&num) )
break;
This will exit the loop if they enter anything which is not recognizable as a number.
Whether or not you take this approach, it is still a good idea to check the return value of scanf and take appropriate action if failed. As you have it now, if they enter some text instead of a number then your program goes into an infinite loop since the scanf continually fails without consuming input.
It's actually not as straightforward as you'd think it would be. One approach is to check the value returned by scanf, which returns the number of arguments correctly read, and if the number wasn't successfully read, try another scanf to look for the quit character:
bool quit = false;
do
{
printf("Enter a number:");
int numArgsRead = scanf("%f",&num);
if(numArgsRead == 1)
{
sum+=num;
}
else // scan for number failed
{
char c;
scanf("%c",&c);
if(c == 'q') quit = true;
}
}
while (!quit);
If you want your program to ignore other inputs (like another letter wouldn't quit) it gets more complicated.
The first solution would be to read the input as a character string, compare it to your character and then convert it to a number later. However, it has many issues such as buffer overflows and the like. So I'm not recommending it.
There is however a better solution for this:
char quit;
do
{
printf("Enter a number:");
quit=getchar();
ungetc(quit, stdin);
if(scanf("%f", &num))
sum+=num;
}
while (quit!='q')
ungetc pushes back the character on the input so it allows you to "peek" at the console input and check for a specific value.
You can replace it with a different character but in this case it is probably the easiest solution that fits exactly what you asked. It won't try to add numbers when the input is incorrect and will quit only with q.
#Shura
scan the user input as a string.
check string[0] for the exit condition. q in your case
If exit condition is met, break
If exit condition is not met, use atof() to convert the string to double
atof() reference http://www.cplusplus.com/reference/cstdlib/atof/

printf after scanf always displays 1 (same unexpected value)

Okay so I'm trying to do a basic program in VS. Enter a number then it gets printed out. 1 is always printed.
int main(){
printf("Enter an integer: ");
int n = scanf_s("%d", &n);
printf("%d", n);
}
You are assigning the returned value from scanf_s() to the variable n, that means that the program will print 1 in case a successful read happened.
What you should do is
int numberOfItemsMatched;
int readValue;
numberOfItemsMatched = scanf_s("%d", &readValue);
if (numberOfItemsMatched == 1)
printf("%d\n", readValue);
I hope the variable names are self explanatory, and it's always a good idea to use this kind of names.
return type of scanf is number of items read. so if scanf is succesful in reading an item, it returns one which is assigned to n here. hence the output is 1. So separate declaration of n and scanf.

Why is & used before a variable?

Why is & used here before decks (scanf("%i", &decks))?
And if my input is any letter like 'k' then it shows an output like "1929597720". Why?
#include <stdio.h>
int main(){
int decks;
puts("enter a number of decks:");
scanf("%i", &decks);
if (decks<1) {puts("Please enter a valid deck number");
return 1;
}
printf("there are %i cards\n", (decks*52));
return 0;
}
& before a variable name means "use the address of this variable". Basically, you're passing a pointer to decks to scanf()
As for what happens when you enter "k" (or other invalid input) - scanf() is failing, and you're seeing whatever random data was already in decks (which was never initialized).
To avoid this, check the return value of scanf(), and initialize decks.
int decks = 0, scanned;
puts("enter a number of decks:");
int scanned = scanf("%i", &decks);
if ((scanned < 1) || (decks < 1)) {
puts("Please enter a valid deck number");
return 1;
}
When passing stuff to scanf(), you need to pass in a pointer to the variable, not the variable itself. The & means "Don't take the variable, take the place in memory where this variable is stored." It's a little complicated, but it's necessary so that C can change the value of the variable.
Also, change your format string to
scanf("%d", &decks);
The garbage is because you don't initialize decks. If you put in int decks = 0, you would always get 0.
As every good C tutorial will teach you, the & sign is for getting a variable's address.
In the case of scanf(), this is necessary in order to tell scanf() where to put the requested data.
If you input a letter like k, or any non-number, scanf() will be disturbed by that, and if you would check scanf()'s return value, it would tell you that 0 items are read instead of 1.
In that case, the content of the given variable is unchanged and contains random garbage. And this is as well what you output.

Resources