While loop misbehaving, - c

i am pretty new to c, i m trying to make the user input a number, but if they input a letter or word it shows a warning and asks for input again, my code works fine if the user puts in a number but it goes into an infinite loop if the user inputs something invalid, here is my code
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
}
printf("%.2f\n", salary);
return 0;
}
i thought that i was something to do with the buffer left over from the first scanf , but adding a space " %f" didnt work, i tried using fflush(stdin) after then scanf also didnt work. i m not sure what else i can try.
thanks in advance for any help.

You need to clear the buffer or it will keep evaluating it and cause the endless loop. Add one line after your invalid input: scanf("%*[^\n]")
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
scanf("%*[^\n]");
}
printf("%.2f\n", salary);
return 0;
}
This will work. You can see a better explanation here: Scanf and loops

The problem is that scanf won't advance the file stream. You ask it to read a floating point value and it isn't able to, so it doesn't consume the input.
For example, let's say your input is "foo", which isn't a number. Your scanf call isn't able to successfully read anything and returns 0. Then, in the next iteration, "foo" is still waiting to be read from stdin.
Try changing your if condition to something like
if (status == 0) {
char foo[256];
fgets(foo, sizeof(foo), stdin);
printf("Invalid input! Expected a nmuber, got: %s", foo);
}
Notice how the entire input is read from stdin by the gets call.

Related

Why this code is not re-prompting correctly?

I am totally new to C.
I want to re-prompt when the input value is not a number and when it's a number it should be less than 1. when I give any sort of string it works correctly. But when I give any number it goes to the next line without printing "Number: ".Then in the next line, it prints "Number: "again if the input value is less than 1.
int x;
printf("Number: ");
while (scanf("%d", &x) != 1 || x < 1 )
{
printf("Number: ");
scanf("%*s");
}
and the result it gives me is this
result
It would be wise to use fgets to read the line, then use sscanf to parse the input. That way, you can get the line, then check if sscanf succeeds!
Simple example:
int target_number; // The number you will have at the end of this.
while (1) { // Loop for rechecking number
char line[16]; // See notes on how to read the whole line.
fgets(line, sizeof(line), stdin);
// We use 1 here because sscanf returns the number of format specifiers that are matched. Since you only need one number, we use 1.
if (sscanf(line, "%d", &target_number) != 1) {
fprintf(stderr, "Invalid Input! Please enter in a valid number.");
continue;
}
}
// Do whatever you will with target_number
Notes
You can see how to read the whole line here.
This code is not safe!
It does not protect against buffer overflow attacks and the like. Please see this on the right way to do this. If this is just for learning, you don't need to worry.
/*This is how it will work the way you want.
If I understand your goal correctly, of course?
If your goal was different,
please specify and I will try to solve it.*/
#include<stdio.h>
int main(void)
{
int x;
printf("Number: ");
while (scanf("%d.%*d", &x)!=1 || x<0)
{
if(x<0)
{
printf("Number: ");
continue;
}
else
printf("Number: ");
scanf("%*s");
}
printf("Hello world!");
return 0;
}

C Program - How to deny any non-numerical input

I've just started learning the language of C, and would love your help in cleaning up / simplifying my code if you know a better way to reach the following.
I want a program to ask for a number, and if that is found then proceed to print and end, however if anything else is put in (e.g. a letter key), then I want the program to loop asking for a number until one is given.
I started off by using a simple scanf input command, but this seemed to go into an infinite loop when I tried to check if a valid number (as we define them) was put in.
So instead I have ended up with this, from playing around / looking online, but I would love to know if there is any more efficient way!
//
// Name & Age Program
// Created by Ben Warren on 1/3/18.
//
#include <stdio.h>
int main (void)
{
//Setting up variables
int num;
char line[10]; /* this is for input */
//Collecting input
printf("Please enter any number? \t");
scanf("%d", &num);
//If Invalid input
while (num==0)
{
printf("\nTry again:\t");
fgets(line, 10, stdin); //turning input into line array
sscanf(line, "%d",&num); //scaning for number inside line and storing it as 'num'
if (num==0) printf("\nThat's not an number!");
}
//If Valid input
{
printf("\n%d is nice number, thank you! \n\n", num);
*}*
return 0;
}
Instead of checking if the value is different to 0, check the return value of
sscanf. It returns the number of conversions it made. In your case it should be 1. Unless the return value is 1, keep asking for a number.
#include <stdio.h>
int main(void)
{
int ret, num;
char line[1024];
do {
printf("Enter a number: ");
fflush(stdout);
if(fgets(line, sizeof line, stdin) == NULL)
{
fprintf(stderr, "Cannot read from stdin anymore\n");
return 1;
}
ret = sscanf(line, "%d", &num);
if(ret != 1)
fprintf(stderr, "That was not a number! Try again.\n");
} while(ret != 1);
printf("The number you entered is: %d\n", num);
return 0;
}
That is not a bad approach for someone new to C. One small improvement would be to actually check the return value of scanf(), since it returns the number of arguments successfully retrieved. Then you could get away from relying on num being 0 to indicate the input was valid. Unless you do want to specifically flag 0 as invalid input.
int ret = scanf("%d", &num);
ret == 1 would mean an integer was succesffully read into num, ret == 0 would mean it was not.
Consider using strtol to parse a string for a long int. This also allows you to detect trailing characters. In this example if the trailing character is not a newline, the input can be rejected. strtol can also detect overflow values. Read the documentation to see how that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
//Setting up variables
long int num = 0;
char line[40] = ""; /* this is for input */
char *parsed = NULL;
printf("Please enter any number? \t");
fflush ( stdout);
while ( fgets(line, 40, stdin))
{
parsed = line;//set parsed to point to start of line
num = strtol ( line, &parsed, 10);
if ( parsed == line) {//if parsed equals start of line there was no integer
printf("Please enter a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
continue;
}
if ( '\n' != *parsed) {//if the last character is not a newline reject the input
printf("Please enter only a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
}
else {
break;
}
}
if ( !parsed || '\n' != *parsed) {
fprintf ( stderr, "problem fgets\n");
return 0;
}
printf("\n%ld is nice number, thank you! \n\n", num);
return 0;
}
0 (zero) is a number...
But I see what you want to do...
You can check for a valid number, using isdigit or a combination of similar functions
I think its also important to follow the advice of other answers to use the return value from scanf using code such as:
int ret = scanf("%d", &num);
and examining ret for success or failure of scanf.

Repeating an Input till it is answered Correct

The concept if very simple. The computer must repeat the question till it recieves a valid response. Here is my current code:
#include <stdio.h>
int main(int argc, const char * argv[]) {
int age;
do{
printf("How old are you?\n");
scanf("%d", &age);
if (age == 32767)
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
break;
}
}
while(age!=3267);
return (0);
}
The if else statement is to catch the exception incase the user types something that is not an integer.
I tried using a do-while loop but it ended up as an infinite loop
I used the do-while loop because I needed to go through that procedure until I get a valid age value.
My output with the current code is:
How old are you?
g
Error, retry:
How old are you?
Error, retry:
How old are you?
Error, retry:
How old are you?
Error, retry:
It goes like this indefinitely.
It would be great if you could help me out.
The computer must repeat the question till it recieves a valid response.
It (output) goes like this indefinitely.
Reason :
The problem is that you are receiving input only once in your code and then entering into loop to check for the age.
since age value is not re-assigned after every iteration, if the first intput is !=32767 it's always wrong and enters into an infinite loop or also known as the odd loop.
scanf("%d", &age); //scans only once
do //enters loop
{
if (age == 32767)
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
}
} while(age!=32767);
The if else statement is to catch the exception incase the user types something that is not an integer.
No, if (age == 32767) would only check if the entered response was equal to 32767 or not.
From #davmac 's comment , you can never check for an input value greater than the maximum value of the int variable.
Instead it'd be better if you would assign a range this way
`if (age > 100 || age <0 )`
Solution :
to avoid this scan age for every iteration and also see the changes I've done :
do{
printf("How old are you?\n");
if(scanf("%d", &age)==1) //checking if scanf is successful or not
{
if (age > 100 || age <0 )
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
break; //break loop when correct value is entered
}
}
else //if scanf is unsuccessful
{
char c;
printf("enter only integers\n");
do
{
scanf("%c",&c);
}while( c !='\n' && c!= EOF ); //consuming characters
}
}while(1); //always true
Some important points:
First, Using scanf to read an int from user input usually allows for whitespace to be entered first:
scanf(" %d", &age);
In particular this skips over previous new line characters that were input previously and are still buffered.
Second, scanf returns a value indicating whether it succeeded or failed, and how many items it matched. You need to check this return value:
int r = scanf(" %d", &age);
if (r == EOF) {
break;
}
if (r == 0) {
printf("Error, retry: \n");
}
Third, if scanf can't match input it is left in the input buffer. If you don't retrieve it from the buffer, it will simply fail to match again the next time you call scanf, ad infinitum. For this reason, scanf is not great for handling user input at all. It is better, if possible, to read a single line of input into a buffer (you can use fgets for this, if you are careful), and then process the buffer. As a weak alternative, you can force some of the input buffer to be consumed by scanning for a string before you try to read the input value again:
int r = scanf(" %d", &age);
if (r == EOF) {
break;
}
if (r == 0) {
printf("Error, retry: \n");
scanf("%*s"); // match string but suppress assignment
}
else {
printf("Cool.\n");
break;
}
This modification gets your code to at least halfway-working state.
Use do while Loop. Like:
Do{
// your code
Age = // asign value
}while(age>100 && age < 1);
So it will repeat until age is entered between 100 and 1. It will stop if it will get age b/w 1 - 100.
Thanks. Hope it will help.

While input is not a number, goes into Infinite loop

I'm just a beginner and am trying to make a a program that asks for a number and if a letter is input, it says "that's not a number" and asks for a number again, until a number is input.
However, my program keeps going into an infinite loop with the current code. Any help would be appreciated to fix this. Also, I would also like the program to say "please input something" if nothing is input, but don't know how to do this. Thanks.
#include <stdio.h>
int main()
{
float i;
printf("enter a number");
while(scanf("%f", &i) != 1)
{
puts("That is not a number.");
scanf("%f", &i);
}
}
You need to clear the bad input from stdin after your scanf fails:
#include <stdio.h>
int main()
{
float i;
char trash[1024];
while (1)
{
printf("Please enter a number: ");
fflush(stdout);
if (1 == scanf("%f", &i))
break;
/* scanf failed: clear the bad input from stdin */
if (NULL == fgets(trash, sizeof(trash), stdin)) /* NOTE: assumes 1 entry per line and no line longer than 1023 characters */
exit((fprintf(stderr, "Unexpected EOF or error!\n"), 1));
puts("That is not a number.");
}
printf("You entered: %f!\n", i);
return 0;
}
As an alternative to the fgets() to clear the line, you could call scanf("%1023s", trash), which would only suck in the next whitespace delimited series of characters. This would allow you to handle multiple entries on a single line with mistakes intermixed, for example.
Your program goes into infinite loop because after the invalid input, (scanf("%d", &i) != 1)condition being TRUE, the invalid input which is left in the input buffer is not consumed, it's still in the buffer. So the same invalid input is read over and over again.
To avoid, once scanf() fails, you need to flush out all the input buffer contains before calling next scanf().
Maybe inside the while loop, calling getchar() until a newline or EOF will help. Also, the second scanf() can be removed, IMHO.
After your non numeric[More precisely input which doesn't match the formating of scanf()] input you need to clear the stdin. If not the same input will be read till stdin get cleaned or you terminate the program. A reference answer can be found on this question
Quoted
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.
Reason for infinite loop : Since you don't clear stdin, same values will be read by scanf() and always full fill while condition resulting in a infinite loop.
Use following edited code :
#include <stdio.h>
int main()
{
float i;
char c;
printf("enter a number");
while(scanf("%f", &i) != 1)
{
puts("That is not a number.");
scanf("%f", &i);
while ((c = getchar()) != '\n' && c != EOF); // Flush stdin
}
}
Your code is taking input of a number. Thats why if you even give input a letter, it will take the ASCII value of the letter, which is a valid number. And Further more please take a character as an input. Here I have modified your code which should work
#include <stdio.h>
int main()
{
char i;
printf("enter a number");
while(1)
{
scanf("%c",&i);
if (c >=48 && c <= 57) // here ascii value of numbers between 0-9 is 48-57 respectively
{
puts("That is a number.");
break;
}
else
{
puts("That is not a number.");
scanf("%c",&i);
}
}
}

Letter guessing game weird output

So here is my code:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#define MAX_GUESSES 4
int PlayGame(char guess);
int WinOrLose(char userguess, char solution);
int main()
{
FILE* infile;
char correctlet;
int games,
igame,
result;
infile = fopen("inputLet.txt", "r");
printf ("Welcome to the letter guessing game!\n");
printf ("Your job is to guess a random letter.\n");
printf("You can guess each letter a maximum of 4 times,\n");
printf ("and you will get a hint after every guess.\n");
printf ("LET'S DO THIS!\n\n>");
printf ("\nHow many games would you like to play (1-3)?\n>");
scanf ("%d",&games);
for(igame=0;igame<games;igame++)
{
fscanf(infile," %c",&correctlet);
printf("This is game %d\n", igame+1);
result = PlayGame (correctlet);
if (result == 0)
{
printf ("\nCongratulations, you guessed the right letter!\n");
}
else
{
printf ("\nUnfortunately, you did not guess the right letter. Better luck next time!\n");
}
}
return 0;
}
int PlayGame(char solution)
{
int guessnumber,
result;
char userguess;
guessnumber = 0;
while(guessnumber < MAX_GUESSES)
{
printf("Please enter your guess\n>");
scanf("%c", &userguess);
if (sizeof userguess == 0)
{
continue;
}
else if (sizeof userguess >=1)
{
printf ("Your guess was %c\n",userguess);
result = WinOrLose (userguess, solution);
if (result == 0)
{
return 0;
break;
}
else if (result == 1)
{
if (solution < userguess)
{
printf("The correct letter comes before %c alphabetically\n", userguess);
}
else if (solution > userguess)
{
printf("The correct letter comes after %c alphabetically\n", userguess);
}
guessnumber ++;
}
}
}
}
int WinOrLose (char userguess, char solution)
{
if(solution==userguess)
{
return 0;
}
else if (solution != userguess)
{
return 1;
}
}
The output asks for the number of games, and then it outputs please enter your guess your guess was (blank) The correct letter comes after (blank) Please enter your guess and THEN it allows for user input. So why is it going through one iteration of PlayGame without asking for user input? I have tried everything I can think of and can't fix the problem. I am compiling on VC++ 2010, if that helps.
Thanks in advance!
The simple answer is to flush your buffers.
The stdin buffer, the buffer that takes instructions from the keyboard (or a pipe) and submits it to the program occasionally gets some characters "stuck" in it. Junk characters that never quite get submitted, extra returns, etc. that will cause scanf() to think it reached the proper end, but actually hasn't.
fflush(stdin);
The function fflush "flushes" a buffer. The effect of this is to consume data from a buffer until the data received is the character '\0' (NULL). This means that it's reached the last of the data that is currently in the buffer.
Calling this before calling scanf() means that when scanf() is called, you reasonably know that the program will block on scanf() until you've submitted, and not just consume some junk from the buffer.

Resources