While Loop doesn't break when error occurrs - c

The while loop below breaks when a letter is added. I would like it to continue to loop even if a letter is added, as well as if a negative number is added.
Here's my current code:
float monthpay;
printf("Please enter your monthly wage:\t");
scanf("%f", &monthpay);
while (monthpay <= 0)
{
printf("\nThat was invalid");
printf("\n Please try again: ");
scanf("%f", &monthpay);
}
printf("%.2f", monthpay);
I was trying to make a loop that would loop if a letter was added by mistake.

scanf() returns number of input items that were successfully matched and assigned. If you don't check the return value (rv) your variable (monthpay) may be uninitialized, and it's undefined behavior to use it.
void flush() {
for(;;) {
char ch;
int rv = scanf("%c", &ch);
if(rv == EOF || rv == 1 && ch == '\n') return;
}
}
printf("Please enter your monthly wage:\t");
float monthpay;
for(;;) {
int rv = scanf("%f", &monthpay);
if(rv == EOF)
return;
if(rv == 1)
break;
printf("\nThat was invalid");
printf("\n Please try again: ");
flush();
}
printf("%.2f", monthpay);

After trying to scan a float, scan and discard whitespace except for newline, scan discard and count any remaining characters that are not a newline, scan a newline.
The %n specifier will provide a count of the characters processed by the scan up to the specifier.
The asterisk in the scanset %*[ \t\f\v] tells scanf to discard the matching characters. The carat in the scanset %*[^\n] tells scanf to process the non-matching characters so everything that is not a newline will be discarded. %1[\n] tells scanf to scan one character and it must be a newline.
If a float is entered followed only by whitespace, the loop will exit as scanned will be 2 and extra will be 0.
#include <stdio.h>
int main ( void) {
char newline[2] = "";
int extra = 0;
int scanned = 0;
float monthpay = 0.0;
do {
printf ( "enter monthly pay\n");
scanned = scanf ( "%f", &monthpay);
if ( scanned == EOF) {
return 1;
}
extra = 0;
scanf ( "%*[ \f\t\v]"); // scan and discard whitespace except newline
scanf ( "%*[^\n]%n", &extra); // scan discard and count non-whitespace
scanned += scanf ( "%1[\n]", newline);
} while ( monthpay < 0 || scanned != 2 || extra != 0);
return 0;
}

You should always check the return value of scanf to determine whether the input was successfully converted, before you attempt to use the result.
However, for line-based user input, using the function scanf is generally not advisable, because its behavior is not intuitive. It usually does not consume an entire line of input, which can cause all kinds of trouble. For example, scanf leaving the newline character on the input stream can cause this problem. If the user enters 6abc\n, then the situation is even worse: In that case, scanf will match the 6 as valid input, but leave abc\n on the input stream, which will most likely cause the next input operation to not behave as intended, unless you explicitly discard the remainder of the line from the input stream beforehand.
For the reasons stated above, it is generally better to always read an entire line of input at once as a string, for example using the function fgets. You can then use the function strtof to attempt to convert the string to a number.
Here is an example, which performs extensive input validation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
float get_float_from_user( const char *prompt );
int main( void )
{
float monthpay;
//loop forever until user enters a valid number
for (;;) //infinite loop, equivalent to while(1)
{
monthpay = get_float_from_user( "Please enter your monthly wage: ");
if ( monthpay > 0 )
{
//input is ok, so we can break out of the loop
break;
}
printf( "Please enter a positive number!\n" );
}
printf( "Input was valid. You entered: %.2f\n", monthpay );
return 0;
}
float get_float_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
float f;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
f = strtof( buffer, &p );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as a "float"
if ( errno == ERANGE )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return f;
continue_outer_loop:
continue;
}
}
This program has the following behavior:
Please enter your monthly wage: abc
Error converting string to number!
Please enter your monthly wage: 6abc
Unexpected input encountered!
Please enter your monthly wage: 6e+2000
Number out of range error!
Please enter your monthly wage: -5
Please enter a positive number!
Please enter your monthly wage: 0
Please enter a positive number!
Please enter your monthly wage: 6.3
Input was valid. You entered: 6.30
The function get_float_from_user that I am using in the code above is based on the function get_int_from_user from this answer of mine to another question. See that answer for a further explanation on how that function works.

Related

c scanf only integers and check if they are not s [duplicate]

Basically, I need to ensure that input is an integer, like so:
do {
printf("Enter > ");
scanf("%d", &integer);
} while (/* user entered a char instead of an int */);
I have tried various methods, but it always end up with run-time error or infinite loop when I tried to enter a char. I have knew that fflush(stdin) is an undefined behavior, which is better not to involve it in my code in order to prevent any error plus it no longer works in VS2015 due to some reasons.
The codes below are the method that I have tried:
typedef enum {false, true} bool;
int ipt;
char c;
bool wrong_ipt;
do {
c = '\0';
printf("Enter > ");
scanf("%d%c", &ipt, &c); //infinite loop occurs while a char has been entered
} while (c != '\n');
do {
c = '\0';
printf("Enter > ");
} while (scanf("%d", &ipt) != EOF);
do {
wrong_ipt = false;
do {
ipt = NULL;
printf("Enter > ");
scanf("%d", &ipt);
if (ipt == NULL) {
wrong_ipt = true;
break;
}
} while (ipt == NULL);
} while (wrong_ipt);
Is there anyway other than fflush(stdin) which can be used to prevent the infinite loop when user entered a char in C?
Thank you
The problem is that "scanf()" can leave unread data in your input buffer. Hence the "infinite loop".
Another issue is that you should validate the return value from scanf(). If you expect one integer value ... and scanf returns "0" items read ... then you know something went wrong.
Here is an example:
#include <stdio.h>
void discard_junk ()
{
int c;
while((c = getchar()) != '\n' && c != EOF)
;
}
int main (int argc, char *argv[])
{
int integer, i;
do {
printf("Enter > ");
i = scanf("%d", &integer);
if (i == 1) {
printf ("Good value: %d\n", integer);
}
else {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
}
} while (i != 1);
return 0;
}
Sample output:
Enter > A
BAD VALUE, i=0!
Enter > B
BAD VALUE, i=0!
Enter > 1
Good value: 1
'Hope that helps!
This is a very good example of why scanf should generally not be used for user input.
Since user input is line-based, one would expect that an input function would always read one line of input at a time. However, that is not the way that the function scanf behaves. Instead, it consumes only as many characters as are required to match the %d conversion format specifier. If scanf is unable to match anything, then it does not consume any characters at all, so that the next call to scanf will fail for exactly the same reason (assuming that the same conversion specifier is used and that the invalid input is not explicitly discarded by you). This is what is happening in your code.
At the time of this writing, three of the other answers solve this problem by checking the return value of scanf and explicitly discarding the invalid input. However, all three (!) of these answers have the problem that they for example accept "6sdfj23jlj" as valid input for the number 6, although the whole line of input should obviously be rejected in this case. This is because scanf, as previously mentioned, does not read one line of input at a time.
Therefore, the best solution to your problem would probably be to use line-based input using fgets instead. That way, you will always read exactly one line of input at a time (assuming that the input buffer is large enough to store an entire line of input). After reading the line, you can then attempt to convert it to a number using strtol. Even if the conversion fails, the line of input will have been consumed from the input stream, so you will not have most of the problems described above.
A simple solution using fgets could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main( void )
{
char line[100];
long number;
//retry until user enters valid input
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
printf( "Please enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert input to number
number = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Invalid input!\n" );
continue;
}
//verify that remainder of line only contains
//whitespace, so that input such as "6sdfj23jlj"
//gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Encountered invalid character!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was valid, so break out of infinite loop
break;
//label for breaking out of nested loop
continue_outer_loop:
continue;
}
printf( "Input was valid.\n" );
printf( "The number is: %ld\n", number );
return 0;
}
Note that the goto statement should generally not be used. However, in this case, it is necessary, in order to break out of a nested loop.
This program has the following output:
Please enter a number: 94hjj
Encountered invalid character!
Please enter a number: 5455g
Encountered invalid character!
Please enter a number: hkh7
Invalid input!
Please enter a number: 6sdfj23jlj
Encountered invalid character!
Please enter a number: 67
Input was valid.
The number is: 67
However, this code is still not perfect. It still has the following problems:
If the user enters 100 characters of input in a single line, then the entire line won't fit into the input buffer. In that case, two calls to fgets will be required to read the entire line, and the program will incorrectly treat that line as two separate lines of input.
The code does not check if the number the user entered is representable as a long (e.g. whether the number is excessively large). The function strtol reports this by setting errno accordingly (which is a feature that scanf lacks).
These two problems can be fixed too, by performing additional checks and error handling. However, the code is now becoming so complex that it makes sense to put it all into its own function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Please enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
Your fundamental mistake is that you never tell your program to consume the invalid input. In words, you told the program:
Read an integer if there is one. (Otherwise read nothing)
If you didn't get an integer, go back to step 1.
I assume what you thought you were doing was
Read the input, and if it was an integer, store it.
If it wasn't an integer, go back to step 1.
So what you need to do is to rewrite your code so it does what you meant to do (or come up with some other approach, as in the other answer). That is, write your program to:
Read some amount of input. (e.g. a line)
Scan the input to see if it is an integer, and store it.
If it wasn't an integer, go back to step 1.
Some relevant functions you may find useful are fgets, sscanf, and atoi. (also, try to resist the temptation to write buggy code; e.g. if you intend to read a line of input, make sure you actually do so, and correctly. Many people are lazy and will do the wrong thing if the line is long; e.g. just read part of the line, or cause a buffer overflow)
The format specifier %d tells to scanf that an integer value is expected in the command line. When the user enters a line of data, it's read as a string, and then scanf attempts to understand if the entered string can be interpreted as the decimal digits of an integer number.
If this interpretation succeds, then the value thus found is stored in the integer variable you passed as argument.
The number of rigth replacements done by scanf are retrieved by that function in the form of an int value. Since you expect only one input, the value 1 will indicates that everything was fine.
So, if there was an error, as for example, the user entered a non-valid integer number, the number returnd by scanf is less than the number of format specifiers. In this case, a value less than 1 informs that an error happened:
int ipt, succeded;
do {
printf("ipt? ");
succeded = scanf("%d", &ipt);
if (succeded < 1) { // Clean the input
while (getchar() != '\n')
;
}
} while(succeded < 1);
I know I'm a little late to answer this but you could reduce the use of loops and use jump statements instead and then just use one if statement to check for bad input and still achieve the same result
enter: printf("Enter > ");
i = scanf("%d", &integer);
if (i != 1) {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
goto enter:
}
printf ("Good value: %d\n", integer);

Why isn't my last else statement printing "invalid characters" for anything besides numbers? [duplicate]

Basically, I need to ensure that input is an integer, like so:
do {
printf("Enter > ");
scanf("%d", &integer);
} while (/* user entered a char instead of an int */);
I have tried various methods, but it always end up with run-time error or infinite loop when I tried to enter a char. I have knew that fflush(stdin) is an undefined behavior, which is better not to involve it in my code in order to prevent any error plus it no longer works in VS2015 due to some reasons.
The codes below are the method that I have tried:
typedef enum {false, true} bool;
int ipt;
char c;
bool wrong_ipt;
do {
c = '\0';
printf("Enter > ");
scanf("%d%c", &ipt, &c); //infinite loop occurs while a char has been entered
} while (c != '\n');
do {
c = '\0';
printf("Enter > ");
} while (scanf("%d", &ipt) != EOF);
do {
wrong_ipt = false;
do {
ipt = NULL;
printf("Enter > ");
scanf("%d", &ipt);
if (ipt == NULL) {
wrong_ipt = true;
break;
}
} while (ipt == NULL);
} while (wrong_ipt);
Is there anyway other than fflush(stdin) which can be used to prevent the infinite loop when user entered a char in C?
Thank you
The problem is that "scanf()" can leave unread data in your input buffer. Hence the "infinite loop".
Another issue is that you should validate the return value from scanf(). If you expect one integer value ... and scanf returns "0" items read ... then you know something went wrong.
Here is an example:
#include <stdio.h>
void discard_junk ()
{
int c;
while((c = getchar()) != '\n' && c != EOF)
;
}
int main (int argc, char *argv[])
{
int integer, i;
do {
printf("Enter > ");
i = scanf("%d", &integer);
if (i == 1) {
printf ("Good value: %d\n", integer);
}
else {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
}
} while (i != 1);
return 0;
}
Sample output:
Enter > A
BAD VALUE, i=0!
Enter > B
BAD VALUE, i=0!
Enter > 1
Good value: 1
'Hope that helps!
This is a very good example of why scanf should generally not be used for user input.
Since user input is line-based, one would expect that an input function would always read one line of input at a time. However, that is not the way that the function scanf behaves. Instead, it consumes only as many characters as are required to match the %d conversion format specifier. If scanf is unable to match anything, then it does not consume any characters at all, so that the next call to scanf will fail for exactly the same reason (assuming that the same conversion specifier is used and that the invalid input is not explicitly discarded by you). This is what is happening in your code.
At the time of this writing, three of the other answers solve this problem by checking the return value of scanf and explicitly discarding the invalid input. However, all three (!) of these answers have the problem that they for example accept "6sdfj23jlj" as valid input for the number 6, although the whole line of input should obviously be rejected in this case. This is because scanf, as previously mentioned, does not read one line of input at a time.
Therefore, the best solution to your problem would probably be to use line-based input using fgets instead. That way, you will always read exactly one line of input at a time (assuming that the input buffer is large enough to store an entire line of input). After reading the line, you can then attempt to convert it to a number using strtol. Even if the conversion fails, the line of input will have been consumed from the input stream, so you will not have most of the problems described above.
A simple solution using fgets could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main( void )
{
char line[100];
long number;
//retry until user enters valid input
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
printf( "Please enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert input to number
number = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Invalid input!\n" );
continue;
}
//verify that remainder of line only contains
//whitespace, so that input such as "6sdfj23jlj"
//gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Encountered invalid character!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was valid, so break out of infinite loop
break;
//label for breaking out of nested loop
continue_outer_loop:
continue;
}
printf( "Input was valid.\n" );
printf( "The number is: %ld\n", number );
return 0;
}
Note that the goto statement should generally not be used. However, in this case, it is necessary, in order to break out of a nested loop.
This program has the following output:
Please enter a number: 94hjj
Encountered invalid character!
Please enter a number: 5455g
Encountered invalid character!
Please enter a number: hkh7
Invalid input!
Please enter a number: 6sdfj23jlj
Encountered invalid character!
Please enter a number: 67
Input was valid.
The number is: 67
However, this code is still not perfect. It still has the following problems:
If the user enters 100 characters of input in a single line, then the entire line won't fit into the input buffer. In that case, two calls to fgets will be required to read the entire line, and the program will incorrectly treat that line as two separate lines of input.
The code does not check if the number the user entered is representable as a long (e.g. whether the number is excessively large). The function strtol reports this by setting errno accordingly (which is a feature that scanf lacks).
These two problems can be fixed too, by performing additional checks and error handling. However, the code is now becoming so complex that it makes sense to put it all into its own function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Please enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
Your fundamental mistake is that you never tell your program to consume the invalid input. In words, you told the program:
Read an integer if there is one. (Otherwise read nothing)
If you didn't get an integer, go back to step 1.
I assume what you thought you were doing was
Read the input, and if it was an integer, store it.
If it wasn't an integer, go back to step 1.
So what you need to do is to rewrite your code so it does what you meant to do (or come up with some other approach, as in the other answer). That is, write your program to:
Read some amount of input. (e.g. a line)
Scan the input to see if it is an integer, and store it.
If it wasn't an integer, go back to step 1.
Some relevant functions you may find useful are fgets, sscanf, and atoi. (also, try to resist the temptation to write buggy code; e.g. if you intend to read a line of input, make sure you actually do so, and correctly. Many people are lazy and will do the wrong thing if the line is long; e.g. just read part of the line, or cause a buffer overflow)
The format specifier %d tells to scanf that an integer value is expected in the command line. When the user enters a line of data, it's read as a string, and then scanf attempts to understand if the entered string can be interpreted as the decimal digits of an integer number.
If this interpretation succeds, then the value thus found is stored in the integer variable you passed as argument.
The number of rigth replacements done by scanf are retrieved by that function in the form of an int value. Since you expect only one input, the value 1 will indicates that everything was fine.
So, if there was an error, as for example, the user entered a non-valid integer number, the number returnd by scanf is less than the number of format specifiers. In this case, a value less than 1 informs that an error happened:
int ipt, succeded;
do {
printf("ipt? ");
succeded = scanf("%d", &ipt);
if (succeded < 1) { // Clean the input
while (getchar() != '\n')
;
}
} while(succeded < 1);
I know I'm a little late to answer this but you could reduce the use of loops and use jump statements instead and then just use one if statement to check for bad input and still achieve the same result
enter: printf("Enter > ");
i = scanf("%d", &integer);
if (i != 1) {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
goto enter:
}
printf ("Good value: %d\n", integer);

How to check user's input data type in C? [duplicate]

Basically, I need to ensure that input is an integer, like so:
do {
printf("Enter > ");
scanf("%d", &integer);
} while (/* user entered a char instead of an int */);
I have tried various methods, but it always end up with run-time error or infinite loop when I tried to enter a char. I have knew that fflush(stdin) is an undefined behavior, which is better not to involve it in my code in order to prevent any error plus it no longer works in VS2015 due to some reasons.
The codes below are the method that I have tried:
typedef enum {false, true} bool;
int ipt;
char c;
bool wrong_ipt;
do {
c = '\0';
printf("Enter > ");
scanf("%d%c", &ipt, &c); //infinite loop occurs while a char has been entered
} while (c != '\n');
do {
c = '\0';
printf("Enter > ");
} while (scanf("%d", &ipt) != EOF);
do {
wrong_ipt = false;
do {
ipt = NULL;
printf("Enter > ");
scanf("%d", &ipt);
if (ipt == NULL) {
wrong_ipt = true;
break;
}
} while (ipt == NULL);
} while (wrong_ipt);
Is there anyway other than fflush(stdin) which can be used to prevent the infinite loop when user entered a char in C?
Thank you
The problem is that "scanf()" can leave unread data in your input buffer. Hence the "infinite loop".
Another issue is that you should validate the return value from scanf(). If you expect one integer value ... and scanf returns "0" items read ... then you know something went wrong.
Here is an example:
#include <stdio.h>
void discard_junk ()
{
int c;
while((c = getchar()) != '\n' && c != EOF)
;
}
int main (int argc, char *argv[])
{
int integer, i;
do {
printf("Enter > ");
i = scanf("%d", &integer);
if (i == 1) {
printf ("Good value: %d\n", integer);
}
else {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
}
} while (i != 1);
return 0;
}
Sample output:
Enter > A
BAD VALUE, i=0!
Enter > B
BAD VALUE, i=0!
Enter > 1
Good value: 1
'Hope that helps!
This is a very good example of why scanf should generally not be used for user input.
Since user input is line-based, one would expect that an input function would always read one line of input at a time. However, that is not the way that the function scanf behaves. Instead, it consumes only as many characters as are required to match the %d conversion format specifier. If scanf is unable to match anything, then it does not consume any characters at all, so that the next call to scanf will fail for exactly the same reason (assuming that the same conversion specifier is used and that the invalid input is not explicitly discarded by you). This is what is happening in your code.
At the time of this writing, three of the other answers solve this problem by checking the return value of scanf and explicitly discarding the invalid input. However, all three (!) of these answers have the problem that they for example accept "6sdfj23jlj" as valid input for the number 6, although the whole line of input should obviously be rejected in this case. This is because scanf, as previously mentioned, does not read one line of input at a time.
Therefore, the best solution to your problem would probably be to use line-based input using fgets instead. That way, you will always read exactly one line of input at a time (assuming that the input buffer is large enough to store an entire line of input). After reading the line, you can then attempt to convert it to a number using strtol. Even if the conversion fails, the line of input will have been consumed from the input stream, so you will not have most of the problems described above.
A simple solution using fgets could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main( void )
{
char line[100];
long number;
//retry until user enters valid input
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
printf( "Please enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert input to number
number = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Invalid input!\n" );
continue;
}
//verify that remainder of line only contains
//whitespace, so that input such as "6sdfj23jlj"
//gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Encountered invalid character!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was valid, so break out of infinite loop
break;
//label for breaking out of nested loop
continue_outer_loop:
continue;
}
printf( "Input was valid.\n" );
printf( "The number is: %ld\n", number );
return 0;
}
Note that the goto statement should generally not be used. However, in this case, it is necessary, in order to break out of a nested loop.
This program has the following output:
Please enter a number: 94hjj
Encountered invalid character!
Please enter a number: 5455g
Encountered invalid character!
Please enter a number: hkh7
Invalid input!
Please enter a number: 6sdfj23jlj
Encountered invalid character!
Please enter a number: 67
Input was valid.
The number is: 67
However, this code is still not perfect. It still has the following problems:
If the user enters 100 characters of input in a single line, then the entire line won't fit into the input buffer. In that case, two calls to fgets will be required to read the entire line, and the program will incorrectly treat that line as two separate lines of input.
The code does not check if the number the user entered is representable as a long (e.g. whether the number is excessively large). The function strtol reports this by setting errno accordingly (which is a feature that scanf lacks).
These two problems can be fixed too, by performing additional checks and error handling. However, the code is now becoming so complex that it makes sense to put it all into its own function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Please enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
Your fundamental mistake is that you never tell your program to consume the invalid input. In words, you told the program:
Read an integer if there is one. (Otherwise read nothing)
If you didn't get an integer, go back to step 1.
I assume what you thought you were doing was
Read the input, and if it was an integer, store it.
If it wasn't an integer, go back to step 1.
So what you need to do is to rewrite your code so it does what you meant to do (or come up with some other approach, as in the other answer). That is, write your program to:
Read some amount of input. (e.g. a line)
Scan the input to see if it is an integer, and store it.
If it wasn't an integer, go back to step 1.
Some relevant functions you may find useful are fgets, sscanf, and atoi. (also, try to resist the temptation to write buggy code; e.g. if you intend to read a line of input, make sure you actually do so, and correctly. Many people are lazy and will do the wrong thing if the line is long; e.g. just read part of the line, or cause a buffer overflow)
The format specifier %d tells to scanf that an integer value is expected in the command line. When the user enters a line of data, it's read as a string, and then scanf attempts to understand if the entered string can be interpreted as the decimal digits of an integer number.
If this interpretation succeds, then the value thus found is stored in the integer variable you passed as argument.
The number of rigth replacements done by scanf are retrieved by that function in the form of an int value. Since you expect only one input, the value 1 will indicates that everything was fine.
So, if there was an error, as for example, the user entered a non-valid integer number, the number returnd by scanf is less than the number of format specifiers. In this case, a value less than 1 informs that an error happened:
int ipt, succeded;
do {
printf("ipt? ");
succeded = scanf("%d", &ipt);
if (succeded < 1) { // Clean the input
while (getchar() != '\n')
;
}
} while(succeded < 1);
I know I'm a little late to answer this but you could reduce the use of loops and use jump statements instead and then just use one if statement to check for bad input and still achieve the same result
enter: printf("Enter > ");
i = scanf("%d", &integer);
if (i != 1) {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
goto enter:
}
printf ("Good value: %d\n", integer);

Program which will find the parity of given number and loop if number isn't an integer in C [duplicate]

Basically, I need to ensure that input is an integer, like so:
do {
printf("Enter > ");
scanf("%d", &integer);
} while (/* user entered a char instead of an int */);
I have tried various methods, but it always end up with run-time error or infinite loop when I tried to enter a char. I have knew that fflush(stdin) is an undefined behavior, which is better not to involve it in my code in order to prevent any error plus it no longer works in VS2015 due to some reasons.
The codes below are the method that I have tried:
typedef enum {false, true} bool;
int ipt;
char c;
bool wrong_ipt;
do {
c = '\0';
printf("Enter > ");
scanf("%d%c", &ipt, &c); //infinite loop occurs while a char has been entered
} while (c != '\n');
do {
c = '\0';
printf("Enter > ");
} while (scanf("%d", &ipt) != EOF);
do {
wrong_ipt = false;
do {
ipt = NULL;
printf("Enter > ");
scanf("%d", &ipt);
if (ipt == NULL) {
wrong_ipt = true;
break;
}
} while (ipt == NULL);
} while (wrong_ipt);
Is there anyway other than fflush(stdin) which can be used to prevent the infinite loop when user entered a char in C?
Thank you
The problem is that "scanf()" can leave unread data in your input buffer. Hence the "infinite loop".
Another issue is that you should validate the return value from scanf(). If you expect one integer value ... and scanf returns "0" items read ... then you know something went wrong.
Here is an example:
#include <stdio.h>
void discard_junk ()
{
int c;
while((c = getchar()) != '\n' && c != EOF)
;
}
int main (int argc, char *argv[])
{
int integer, i;
do {
printf("Enter > ");
i = scanf("%d", &integer);
if (i == 1) {
printf ("Good value: %d\n", integer);
}
else {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
}
} while (i != 1);
return 0;
}
Sample output:
Enter > A
BAD VALUE, i=0!
Enter > B
BAD VALUE, i=0!
Enter > 1
Good value: 1
'Hope that helps!
This is a very good example of why scanf should generally not be used for user input.
Since user input is line-based, one would expect that an input function would always read one line of input at a time. However, that is not the way that the function scanf behaves. Instead, it consumes only as many characters as are required to match the %d conversion format specifier. If scanf is unable to match anything, then it does not consume any characters at all, so that the next call to scanf will fail for exactly the same reason (assuming that the same conversion specifier is used and that the invalid input is not explicitly discarded by you). This is what is happening in your code.
At the time of this writing, three of the other answers solve this problem by checking the return value of scanf and explicitly discarding the invalid input. However, all three (!) of these answers have the problem that they for example accept "6sdfj23jlj" as valid input for the number 6, although the whole line of input should obviously be rejected in this case. This is because scanf, as previously mentioned, does not read one line of input at a time.
Therefore, the best solution to your problem would probably be to use line-based input using fgets instead. That way, you will always read exactly one line of input at a time (assuming that the input buffer is large enough to store an entire line of input). After reading the line, you can then attempt to convert it to a number using strtol. Even if the conversion fails, the line of input will have been consumed from the input stream, so you will not have most of the problems described above.
A simple solution using fgets could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main( void )
{
char line[100];
long number;
//retry until user enters valid input
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
printf( "Please enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert input to number
number = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Invalid input!\n" );
continue;
}
//verify that remainder of line only contains
//whitespace, so that input such as "6sdfj23jlj"
//gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Encountered invalid character!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was valid, so break out of infinite loop
break;
//label for breaking out of nested loop
continue_outer_loop:
continue;
}
printf( "Input was valid.\n" );
printf( "The number is: %ld\n", number );
return 0;
}
Note that the goto statement should generally not be used. However, in this case, it is necessary, in order to break out of a nested loop.
This program has the following output:
Please enter a number: 94hjj
Encountered invalid character!
Please enter a number: 5455g
Encountered invalid character!
Please enter a number: hkh7
Invalid input!
Please enter a number: 6sdfj23jlj
Encountered invalid character!
Please enter a number: 67
Input was valid.
The number is: 67
However, this code is still not perfect. It still has the following problems:
If the user enters 100 characters of input in a single line, then the entire line won't fit into the input buffer. In that case, two calls to fgets will be required to read the entire line, and the program will incorrectly treat that line as two separate lines of input.
The code does not check if the number the user entered is representable as a long (e.g. whether the number is excessively large). The function strtol reports this by setting errno accordingly (which is a feature that scanf lacks).
These two problems can be fixed too, by performing additional checks and error handling. However, the code is now becoming so complex that it makes sense to put it all into its own function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Please enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
Your fundamental mistake is that you never tell your program to consume the invalid input. In words, you told the program:
Read an integer if there is one. (Otherwise read nothing)
If you didn't get an integer, go back to step 1.
I assume what you thought you were doing was
Read the input, and if it was an integer, store it.
If it wasn't an integer, go back to step 1.
So what you need to do is to rewrite your code so it does what you meant to do (or come up with some other approach, as in the other answer). That is, write your program to:
Read some amount of input. (e.g. a line)
Scan the input to see if it is an integer, and store it.
If it wasn't an integer, go back to step 1.
Some relevant functions you may find useful are fgets, sscanf, and atoi. (also, try to resist the temptation to write buggy code; e.g. if you intend to read a line of input, make sure you actually do so, and correctly. Many people are lazy and will do the wrong thing if the line is long; e.g. just read part of the line, or cause a buffer overflow)
The format specifier %d tells to scanf that an integer value is expected in the command line. When the user enters a line of data, it's read as a string, and then scanf attempts to understand if the entered string can be interpreted as the decimal digits of an integer number.
If this interpretation succeds, then the value thus found is stored in the integer variable you passed as argument.
The number of rigth replacements done by scanf are retrieved by that function in the form of an int value. Since you expect only one input, the value 1 will indicates that everything was fine.
So, if there was an error, as for example, the user entered a non-valid integer number, the number returnd by scanf is less than the number of format specifiers. In this case, a value less than 1 informs that an error happened:
int ipt, succeded;
do {
printf("ipt? ");
succeded = scanf("%d", &ipt);
if (succeded < 1) { // Clean the input
while (getchar() != '\n')
;
}
} while(succeded < 1);
I know I'm a little late to answer this but you could reduce the use of loops and use jump statements instead and then just use one if statement to check for bad input and still achieve the same result
enter: printf("Enter > ");
i = scanf("%d", &integer);
if (i != 1) {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
goto enter:
}
printf ("Good value: %d\n", integer);

Validate the type of input in a do-while loop

Basically, I need to ensure that input is an integer, like so:
do {
printf("Enter > ");
scanf("%d", &integer);
} while (/* user entered a char instead of an int */);
I have tried various methods, but it always end up with run-time error or infinite loop when I tried to enter a char. I have knew that fflush(stdin) is an undefined behavior, which is better not to involve it in my code in order to prevent any error plus it no longer works in VS2015 due to some reasons.
The codes below are the method that I have tried:
typedef enum {false, true} bool;
int ipt;
char c;
bool wrong_ipt;
do {
c = '\0';
printf("Enter > ");
scanf("%d%c", &ipt, &c); //infinite loop occurs while a char has been entered
} while (c != '\n');
do {
c = '\0';
printf("Enter > ");
} while (scanf("%d", &ipt) != EOF);
do {
wrong_ipt = false;
do {
ipt = NULL;
printf("Enter > ");
scanf("%d", &ipt);
if (ipt == NULL) {
wrong_ipt = true;
break;
}
} while (ipt == NULL);
} while (wrong_ipt);
Is there anyway other than fflush(stdin) which can be used to prevent the infinite loop when user entered a char in C?
Thank you
The problem is that "scanf()" can leave unread data in your input buffer. Hence the "infinite loop".
Another issue is that you should validate the return value from scanf(). If you expect one integer value ... and scanf returns "0" items read ... then you know something went wrong.
Here is an example:
#include <stdio.h>
void discard_junk ()
{
int c;
while((c = getchar()) != '\n' && c != EOF)
;
}
int main (int argc, char *argv[])
{
int integer, i;
do {
printf("Enter > ");
i = scanf("%d", &integer);
if (i == 1) {
printf ("Good value: %d\n", integer);
}
else {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
}
} while (i != 1);
return 0;
}
Sample output:
Enter > A
BAD VALUE, i=0!
Enter > B
BAD VALUE, i=0!
Enter > 1
Good value: 1
'Hope that helps!
This is a very good example of why scanf should generally not be used for user input.
Since user input is line-based, one would expect that an input function would always read one line of input at a time. However, that is not the way that the function scanf behaves. Instead, it consumes only as many characters as are required to match the %d conversion format specifier. If scanf is unable to match anything, then it does not consume any characters at all, so that the next call to scanf will fail for exactly the same reason (assuming that the same conversion specifier is used and that the invalid input is not explicitly discarded by you). This is what is happening in your code.
At the time of this writing, three of the other answers solve this problem by checking the return value of scanf and explicitly discarding the invalid input. However, all three (!) of these answers have the problem that they for example accept "6sdfj23jlj" as valid input for the number 6, although the whole line of input should obviously be rejected in this case. This is because scanf, as previously mentioned, does not read one line of input at a time.
Therefore, the best solution to your problem would probably be to use line-based input using fgets instead. That way, you will always read exactly one line of input at a time (assuming that the input buffer is large enough to store an entire line of input). After reading the line, you can then attempt to convert it to a number using strtol. Even if the conversion fails, the line of input will have been consumed from the input stream, so you will not have most of the problems described above.
A simple solution using fgets could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main( void )
{
char line[100];
long number;
//retry until user enters valid input
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
printf( "Please enter a number: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert input to number
number = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Invalid input!\n" );
continue;
}
//verify that remainder of line only contains
//whitespace, so that input such as "6sdfj23jlj"
//gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Encountered invalid character!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was valid, so break out of infinite loop
break;
//label for breaking out of nested loop
continue_outer_loop:
continue;
}
printf( "Input was valid.\n" );
printf( "The number is: %ld\n", number );
return 0;
}
Note that the goto statement should generally not be used. However, in this case, it is necessary, in order to break out of a nested loop.
This program has the following output:
Please enter a number: 94hjj
Encountered invalid character!
Please enter a number: 5455g
Encountered invalid character!
Please enter a number: hkh7
Invalid input!
Please enter a number: 6sdfj23jlj
Encountered invalid character!
Please enter a number: 67
Input was valid.
The number is: 67
However, this code is still not perfect. It still has the following problems:
If the user enters 100 characters of input in a single line, then the entire line won't fit into the input buffer. In that case, two calls to fgets will be required to read the entire line, and the program will incorrectly treat that line as two separate lines of input.
The code does not check if the number the user entered is representable as a long (e.g. whether the number is excessively large). The function strtol reports this by setting errno accordingly (which is a feature that scanf lacks).
These two problems can be fixed too, by performing additional checks and error handling. However, the code is now becoming so complex that it makes sense to put it all into its own function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfj23jlj" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
int main( void )
{
int number;
number = get_int_from_user( "Please enter a number: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
Your fundamental mistake is that you never tell your program to consume the invalid input. In words, you told the program:
Read an integer if there is one. (Otherwise read nothing)
If you didn't get an integer, go back to step 1.
I assume what you thought you were doing was
Read the input, and if it was an integer, store it.
If it wasn't an integer, go back to step 1.
So what you need to do is to rewrite your code so it does what you meant to do (or come up with some other approach, as in the other answer). That is, write your program to:
Read some amount of input. (e.g. a line)
Scan the input to see if it is an integer, and store it.
If it wasn't an integer, go back to step 1.
Some relevant functions you may find useful are fgets, sscanf, and atoi. (also, try to resist the temptation to write buggy code; e.g. if you intend to read a line of input, make sure you actually do so, and correctly. Many people are lazy and will do the wrong thing if the line is long; e.g. just read part of the line, or cause a buffer overflow)
The format specifier %d tells to scanf that an integer value is expected in the command line. When the user enters a line of data, it's read as a string, and then scanf attempts to understand if the entered string can be interpreted as the decimal digits of an integer number.
If this interpretation succeds, then the value thus found is stored in the integer variable you passed as argument.
The number of rigth replacements done by scanf are retrieved by that function in the form of an int value. Since you expect only one input, the value 1 will indicates that everything was fine.
So, if there was an error, as for example, the user entered a non-valid integer number, the number returnd by scanf is less than the number of format specifiers. In this case, a value less than 1 informs that an error happened:
int ipt, succeded;
do {
printf("ipt? ");
succeded = scanf("%d", &ipt);
if (succeded < 1) { // Clean the input
while (getchar() != '\n')
;
}
} while(succeded < 1);
I know I'm a little late to answer this but you could reduce the use of loops and use jump statements instead and then just use one if statement to check for bad input and still achieve the same result
enter: printf("Enter > ");
i = scanf("%d", &integer);
if (i != 1) {
printf ("BAD VALUE, i=%i!\n", i);
discard_junk ();
goto enter:
}
printf ("Good value: %d\n", integer);

Resources