Basic while loop to scanf an integer - c

I'm trying to create a C program to allow the user to input an integer number greater than 0, but if any other type is entered make the user try again until they enter an integer.
int minBet;
printf("Enter integer"\n);
while(scanf("%d",&minBet)!=1)
{
printf("Must be an integer value greater than 0\n");
scanf(" %d",&minBet);
}
When a non integer value is entered the printf statements loops infinitely. How can I solve this?
can only use stdio.h and NO global varables

If the input character doesn’t match the coversion, it’s left in the input stream to foul up the next read - you’ll have to get rid of it using getchar or fgetc.
while ( scanf( “%d”, &minBet ) < 1 )
{
getchar();
printf( “You entered a non-numeric value, try again: );
}

When you type let's say e, you type e and then press the ENTER key. So there are now 2 characters in the input buffer. scanf("%d") reads the e , but the newline character is still in the input buffer.
A simpler solution to your immediate problem is to add a getchar() after each scanf("%d"). This code will work .
#include <stdio.h>
#include <string.h>
int main(void)
{
int minBet;
printf("Enter integer \n");
while(scanf("%d",&minBet)!=1)
{
getchar();
printf("Must be an integer value greater than 0\n");
}
}
Additionally your code printf("Enter integer"\n); is wrong.It should be
printf("Enter integer \n");

Related

C Program -- While loop with scanf function condition runs even if condition is not met. How to fix this?

I am attempting to create a program where you input 2 numbers and then print out the first number to the power of the second number.
I tried using a while loop to say that if the numbers you input are two, then you keep repeating the program, otherwise if you input more than 2, you end the loop and print out that you input too many numbers.
However, the code still works if I input more than two, and I assume this is because the scanf function ignores anything other than the first two numbers I input.
How do I fix this program so that it works as I had intended?
#include <stdio.h>
#include <math.h>
int main(void)
{
float x, exp;
printf("Please enter a number followed by the power ");
printf("you want to raise it to: ");
while(scanf("%f%f", &x, &exp) == 2)
{
printf("%f\n", pow(x, exp));
printf("Enter the next pair of numbers:\n");
}
printf("You entered too many numbers!\n");
return 0;
}
User input is tricky. Get input as a string, and loop on that. Just keep in mind that the user may enter each input one at a time. Either require it to be correct (user types two numbers followed by Enter) or take effort to handle multiple correct inputs (user types one number followed by Enter and then another number followed by Enter). Here we will require both inputs on the same line:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float x, exp;
printf("Please enter a number followed by the power ");
printf("you want to raise it to: ");
char s[1000];
while (fgets(s, sizeof(s), stdin))
{
if (sscanf(s, "%f %f", &x, &exp) != 2)
{
puts("Invalid input, my dude.");
break; // Stop running if user supplies fewer than two valid inputs
}
else
{
printf("%f\n", pow(x, exp));
}
printf("Enter the next pair of numbers:\n");
}
return 0;
}
This requires the user to terminate the stream to quit, BTW, by pressing ^Z,Enter on Windows or ^D on Linux. You could easily add additional methods to terminate in the loop (for example, terminate if s is empty or sscanf returns 0), but this is not necessary.
EDIT: There are other issues too. For example, what if the user enters more than two inputs on a line. Should I detect that? Again, for programs like this, it is ok to assume that inputs will be valid unless your assignment specifically requires you to detect error conditions.
EDIT 2: If you wish to catch a more than two items entered error, you must make sure that sscanf() consumed the entire line. Fortunately there is an easy way to do that. Change line 15 to:
int n;
if ((sscanf(s, "%f %f %n", &x, &exp, &n) != 2) || (s[n] != '\0'))
What that does is skip all whitespace after the second float to either end of string or the next available item in the string and returns the index of that position in n.
After that we only need to verify that the end of string condition is what was found.
If the user types more than two numbers this will not be an error. They will be stored in the input buffer and read in the next call of scanf.
Pay attention to that the user can type two numbers on the same line or in different lines.
In fact you can not prevent the user to enter on one line numerous numbers. But you can check that at most two lines there are entered two numbers.
So you need to split the input.
The first number will be read using scanf and the second number will be read using fgtes.
Here is a demonstration program.
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("Please enter a number followed by the power ");
printf("you want to raise it to: ");
while ( 1 )
{
float x, exp;
if ( scanf( "%f ", &x ) != 1 ) break;
char s[20];
if ( !fgets( s, sizeof( s ), stdin ) ) break;
int n;
if ( sscanf( s, "%f %n", &exp, &n ) != 1 || s[n] != '\0' ) break;
printf("%f\n", pow(x, exp));
printf("Enter the next pair of numbers: ");
}
puts( "You entered too many or too few numbers!" );
return 0;
}
Its output might look like
Please enter a number followed by the power you want to raise it to: 1 2
1.000000
Enter the next pair of numbers: 2
3
8.000000
Enter the next pair of numbers: 4
5 6
You entered too many or too few numbers!
Simply put, your code will always continue. This is just because of how scanf works:
Scanf scans input from stdin. When scanf reaches the end of stdin and still hasn't scanned everything it expected to scan, it waits until the user sends a newline (presses enter). In other words, so long as you enter valid floats, your scanf will never return a value lower than the expected float count.
On the other end, once scanf is finished with scanning stdin, it immediately evaluates the variables and returns. This means that there is still some input left in stdin that has not yet been read. In fact, when scanf next runs, it will resume scanning exactly where it left off. Take this sample code:
int main()
{
int x,y;
int ct = scanf("%d%d",&x,&y);
printf("%d (%d,%d)\n",ct,x,y);
scanf("%d",&x);
printf("%d\n",x);
}
If you compile and run this, try inputting three ints at once. The second scanf will immediately terminate because it is reading the third integer that was inputted.
If you are trying to get a specific number of inputs, I would suggest scanning the user's input as a string and then using sscanf (scanf for strings). You could also check for the number of spaces in the string, then, to determine if there are too many inputs. If you want to get a little tricky, you could continue to use scanf but then check whether bytes are remaining in stdin before you continue. Here is a good answer that will help if you want to keep using scanf as is, but checking whether stdin is empty.
There is another issue with your code though; what happens when a user inputs something other than a float? But that is a different question entirely (and one where my personal suggestion would be to analyze the entire scanned string).
The problem with using scanf is that it treats all whitespace characters (e.g. spaces and newline characters) as equal. For example, scanf won't care whether the numbers you entered are on the same line or not.
If scanf is asked to read two numbers, but the user instead enters three numbers on the same line, then your first call to scanf will only read the first two numbers and leave the third number on the input stream, so that the next scanf call in the next loop iteration will read it as the next first number. This is not what you want.
Therefore, for line-based user input, it is probably better not to use scanf. Instead, it makes more sense to always read exactly one line per loop iteration. You can do this with the function fgets.
After using fgets to read a line of input, two of the other answers use sscanf to convert both numbers at once. However, you can also convert one number at a time using strtof:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
int main(void)
{
//we want to provide the user with a different prompt the first time,
//so we must remember whether it is the first time
bool first = true;
//infinite loop
while ( true )
{
float x, exp;
char line[100];
char *p, *q;
//prompt user for input
if ( first )
{
printf(
"Please enter a number followed by the power "
"you want to raise it to: "
);
//remember to use a different prompt next time
first = false;
}
else
{
printf("Enter the next pair of numbers: ");
}
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
//break out of infinite loop
break;
}
//attempt to find newline character
p = strchr( line, '\n' );
//make sure entire line was read in
if ( p == NULL && !feof(stdin) )
{
//only accept missing newline character on end-of-file
if ( !feof(stdin) )
{
int c;
printf( "Line too long for input buffer!\n" );
//discard remainder of line
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
continue;
}
}
else
{
//remove newline character by overwriting it with null character
*p = '\0';
}
//start parsing at start of line
p = line;
//attempt to convert first number
x = strtof( p, &q );
//determine whether conversion of first number succeeded
if ( p == q )
{
printf( "Conversion of first number failed!\n" );
continue;
}
//continue parsing at end of first number
p = q;
//attempt to convert second number
exp = strtof( p, &q );
//determine whether conversion of second number succeeded
if ( p == q )
{
printf( "Conversion of second number failed!\n" );
continue;
}
//verify that remainder of line is either empty or only
//consists of whitespace characters
for ( p = q; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected character found after second number!\n" );
//we cannot use the "continue" keyword here, because
//we want to continue to the next iteration of the
//outer loop, not the inner loop
goto continue_outer_loop;
}
}
//print result
printf( "Input accepted, the result is: %f\n", pow(x, exp) );
continue_outer_loop:
continue;
}
return 0;
}
This program has the following behavior:
Please enter a number followed by the power you want to raise it to: abc
Conversion of first number failed!
Enter the next pair of numbers: 10
Conversion of second number failed!
Enter the next pair of numbers: 10 abc
Conversion of second number failed!
Enter the next pair of numbers: 10 20
Input accepted, the result is: 100000000000000000000.000000
Enter the next pair of numbers: 10 20 30
Unexpected character found after second number!
As you can see, the program correctly rejects the input if it contains a third number.

While loop not waiting for input with scanf("%d")

I have a while loop that prints a prompt for an integer. I want to error check for when the user enters a char, like 'a'. However, when I type 'a', it prints "Enter the seed: Seed must be an integer value, please try again" forever.
int getSeed() {
int scanned, seed;
while (scanned == 0) {
printf("Enter the seed: ");
scanned = scanf("%d", &seed);
if (scanned == 0) {
printf("Seed must be an integer, try again\n");
}
}
return seed;
}
How do I get this to print
Enter the seed: a
Seed must be an integer, try again
Enter the seed:
Thanks.
EDIT: Solved it, I added getchar(); after the scanf.
scanf checks your input character and finds out that it does not match the conversion specifier, so it puts it back in the input stream.
Then in your while loop in your code reaches to scanf again, and the above process occurs again (since the a you've written in input stream is still there)
So a better solution would be reading it as a character (or string) and then converting that into an integer.

Validating input with isdigit for a factorial program

I wrote the following code in C to make a program which calculate the factorial of any number.
I want to add to my program some validation/error handling, such as preventing random characters, floats or negative values from being entered, so I used the isdigit function.
Unfortunately there is a hidden problem which I don't know how to solve. When I enter any input it considers it to be false (i.e. not a digit) even if it's a positive digit.
#include <stdio.h>
#include <ctype.h>
int main()
{
char choice;
unsigned long long int factorial=1;
int counter,number;
for(;;)
{
printf("Please , enter a positive integer number only : ");
scanf("%d",&number);
fflush(stdin);
if(isdigit(number))
{
for(counter=number;counter>1;counter--)
factorial*=counter;
printf("The factorial of number %d is %llu",number,factorial);
}
else
{
printf("\a\aError\n");
continue;
}
printf("\n1-Press c or C if you want to calculate the factorial of a new number\n2-Press any key if you want to exit the program\n ");
scanf("%c",&choice);
if(choice=='c'||choice=='C')
{
factorial=1;
system("cls");
continue;
}
else
return 0;
}
}
You are using isdigit wrong. Read its documentation to find out what it actually does.
You probably meant:
if ( number >= 0 && number <= 9 )
However you also need to check whether scanf succeeded or not. If they type in some words, then scanf("%d" fails and does not update number, so trying to access number in that case accesses an uninitialized variable. To deal with that you could either check the return value of scanf, or do:
int number = -1;
scanf("%d",&number);
because the value will be left unchanged if the input failed.
NB. Don't use fflush(stdin)
isdigit checks a single character if that's a decimal digit character.
But, your input could be say 25, multiple characters. So, I changed a portion:L
char input[30];
for(;;)
{
printf("Please , enter a positive integer number only : ");
scanf("%s",input);
if(isdigit(input[0]))
{
number = atoi(input);
for(counter=number;counter>1;counter--)
Keeping rest of your program snippet same.
Here, isdigit is used to check if the first character in input is a digit and therefore a valid candidate to be converted by atoi into an integer value number.

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.

Inputting float into a program that only deals with ints

I have a program, but when I input float numbers whenever the program asks for inputs, the program abruptly skips a step and moves onto the end output. The program is below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a,b,c;
int i;
printf("Please enter a number: ");
scanf("%d", &a);
printf("Please enter a number: ");
scanf("%d", &b);
c = 0;
for(i=0; i < b; i++)
{
c = c + a;
}
printf("%d x %d = %d\n", a, b, c);
return 0;
}
When I input an int for a, and a float for b, the program will output the product as expected if the numbers after the decimal point for b is truncated. However when I input a float for a, the program doesn't take the value for the second number b and instead skips that step and outputs the integer version of a x -858993460 = 0.
For example:
a = int, b = float
Please enter a number: 3
Please enter a number: 5.6
3 x 5 = 15
a = float, b = skipped
Please enter a number 3.9
Please enter a number: 3 x -858993460 = 0
All the flaws in the code are deliberate, but I just wanted to know why it behaves the way I explained above. I know it's because of something to do with trying to input a float into a signed integer but I'm not sure what exactly is causing it to skip the second scanf("%d", &b). Can anyone explain why this happens?
Thanks.
It looks like scanf() is reading your "3" in the second case, and ignoring the "9".
Then when the second scanf() is called, there is already text in the input buffer (the ".9").
I can't tell exactly what it's doing with the ".9". It may have found the dot and just aborted there with b uninitialized. It should be a simple matter to determine what is happening by stepping through with the debugger.
But, basically, not all the input is being processed by the first call to scanf() and so that's what the second call is trying to read. And that's why it's not waiting for you to input any data for the second call.
Console input is line buffered; when you enter 3.9 into a %d format specifier, only the 3 is consumed, the remaining data remains buffered, so the second scanf() call attempts to convert it according to its specifier, it finds a '.' and aborts the conversion leaving b undefined.
scanf() will continue to "fall-through" until the '\n' at the end of the input data is consumed. You can do this thus:
printf("Please enter a number: ");
scanf("%d", &a);
while( getchar() != '\n' ) { /* do nothing */ }
printf("Please enter a number: ");
scanf("%d", &b);
while( getchar() != '\n' ) { /* do nothing */ }
Note that if the format specifier is %c, a modification of the "flush" code is required, because the converted character may already be '\n' :
scanf("%c", &c);
while( c != '\n' && getchar() != '\n' ) { /* do nothing */ }
If the next character that is to be read cannot be converted under the current format as specified by the Format Specifier, scanf stops scanning and storing the current field and it moves to the next input field (if any).
And that particular character is treated as unread and used as the first character of next input field or any subsequent read operation.
In the example given above, it is scanning 3 and then cannot resolve . to the format specifier "%d". Hence it stores 3 in variable a leaving .9 as unread. The control when passes to the next scanf statement, it scans ., but again as it cannot resolve . to format specifier "%d", it skips the input scanning for that field.
Now as variable b was not assigned, it contains some garbage value. And any arithmetic operation with garbage values result into garbage values.

Resources