I want the code to run until the user enters an integer value.
The code works for char and char arrays.
I have done the following:
#include<stdio.h>
int main()
{
int n;
printf("Please enter an integer: ");
while(scanf("%d",&n) != 1)
{
printf("Please enter an integer: ");
while(getchar() != '\n');
}
printf("You entered: %d\n",n);
return 0;
}
The problem is if the user inputs a float value scanf
will accept it.
Please enter an integer: abcd
Please enter an integer: a
Please enter an integer: 5.9
You entered: 5
How can that be avoided?
If you're set on using scanf
, you can do something like the following:
int val;
char follow;
int read = scanf( "%d%c", &val, &follow );
if ( read == 2 )
{
if ( isspace( follow ) )
{
// input is an integer followed by whitespace, accept
}
else
{
// input is an integer followed by non-whitespace, reject
}
}
else if ( read == 1 )
{
// input is an integer followed by EOF, accept
}
else
{
// input is not an integer, reject
}
I know how this can be done using
fgets
andstrtol
, I would like to know how this can be done usingscanf()
(if possible).
As the other answers say, scanf
isn't really suitable for this, fgets
and strtol
is an alternative (though fgets
has the drawback that it's hard to detect a 0-byte in the input and impossible to tell what has been input after a 0-byte, if any).
For sake of completeness (and assuming valid input is an integer followed by a newline):
while(scanf("%d%1[\n]", &n, (char [2]){ 0 }) < 2)
Alternatively, use %n
before and after %*1[\n]
with assignment-suppression. Note, however (from the Debian manpage):
This is not a conversion, although it can be suppressed with the
*
assignment-suppression character. The C standard says: "Execution of a%n
directive does not increment the assignment count returned at the completion of execution" but the Corrigendum seems to contradict this. Probably it is wise not to make any assumptions on the effect of%n
conversions on the return value.
Try using the following pattern in scanf
. It will read until the end of the line:
scanf("%d\n", &n)
You won't need the getchar()
inside the loop since scanf
will read the whole line. The floats won't match the scanf
pattern and the prompt will ask for an integer again.
A possible solution is to think about it backwards: Accept a float as input and reject the input if the float is not an integer:
int n;
float f;
printf("Please enter an integer: ");
while(scanf("%f",&f)!=1 || (int)f != f)
{
...
}
n = f;
Though this does allow the user to enter something like 12.0, or 12e0, etc.
Use fgets
and strtol
,
A pointer to the first character following the integer representation in s
is stored in the object pointed by p
, if *p
is different to \n
then you have a bad input.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *p, s[100];
long n;
while (fgets(s, sizeof(s), stdin)) {
n = strtol(s, &p, 10);
if (p == s || *p != '\n') {
printf("Please enter an integer: ");
} else break;
}
printf("You entered: %ld\n", n);
return 0;
}
Using fgets()
is better.
To solve only using scanf()
for input, scan for an int
and the following char
.
int ReadUntilEOL(void) {
char ch;
int count;
while ((count = scanf("%c", &ch)) == 1 && ch != '\n')
; // Consume char until \n or EOF or IO error
return count;
}
#include<stdio.h>
int main(void) {
int n;
for (;;) {
printf("Please enter an integer: ");
char NextChar = '\n';
int count = scanf("%d%c", &n, &NextChar);
if (count >= 1 && NextChar == '\n')
break;
if (ReadUntilEOL() == EOF)
return 1; // No valid input ever found
}
printf("You entered: %d\n", n);
return 0;
}
This approach does not re-prompt if user only enters white-space such as only Enter.
scanf()
.fgets()
to get an entire line.strtol()
to parse the line as an integer, checking if it consumed the entire line.char *end;
char buf[LINE_MAX];
do {
if (!fgets(buf, sizeof buf, stdin))
break;
// remove \n
buf[strlen(buf) - 1] = 0;
int n = strtol(buf, &end, 10);
} while (end != buf + strlen(buf));
Source: Stackoverflow.com