int validation using scanf and isdigit - c

I want to validate the input is int.
Ideally, I want it to prompt to the user if the validation failed.
I tried this:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i;
printf("enter a number: ");
scanf("%i", &i);
(isdigit(i)) ? printf("%i is a digit\n", i) : printf("%i is NOT a digit\n", i);
}
it does not do what i want.
here is the result:
> enter a number: 1
> 1 is NOT a digit
but magically:
> enter a number: 54
> 54 is a digit
why? How can I do the validation in the right way?
== UPDATE ==
I tried some suggestion to not using isdigit but checking the scanf result, it works, as follow:
int i, checker;
printf("enter a number: ");
checker = scanf("%i", &i);
(checker) ? printf("%d Is digit\n", i) : printf("%d Is NOT digit\n", i);
here is the result
enter a number: 12
12 Is digit
enter a number: asdf
220151845 Is NOT digit
but it failed the while loop validation,
int i, checker;
do
{
printf("enter a number: ");
checker = scanf("%i", &i);
} while (!checker);
printf("number : %i\n", i);
especially when it is not a digit, then it become infinity looping the printf but not prompt to user at all.
Thanks.

Don't use isdigit() — it is for checking whether a character is a digit or not. You've read a number. You must check the return value from scanf() — if it is not 1, you've got a problem. Depending on your requirements, the fact that there may be all sorts of stuff on the line after the number may or may not be a problem. I'm assuming when you say "validate the input is an integer", you want to allow for multiple-digit numbers, and negative numbers, and since you used %i rather than %d, you're fine with octal values (leading 0) or hexadecimal values (leading 0x or 0X) being entered too.
Note that if you have:
int checker = scanf("%i", &i);
then the result could be 1, 0, or EOF. If the result is 1, then you got an integer after possible leading white space, including possibly multiple newlines. There could be all sorts of 'garbage' after the number and before the next newline. If the result is 0, then after skipping possible white space, including possibly multiple newlines, the first character that wasn't white space also wasn't part of an integer (or it might have been a sign not immediately followed by a digit). If the result is EOF, then end-of-file was detected after possibly reading white space, possibly including multiple newlines, but before anything other than white space was read.
To continue sensibly, you need to check that the value returned was 1. Even then, there could be problems if the value is out of the valid range for the int type.
The full requirement isn't completely clear yet. However, I'm going to assume that the user is required to enter a number on the first line of input, with possibly a sign (- or +), and possibly in octal (leading 0) or hexadecimal (leading 0x or 0X), and with at most white space after the number and before the newline. And that the value must be in the range INT_MIN .. INT_MAX? (The behaviour of scanf() on overflow is undefined — just to add to your woes.)
The correct tools to use for this are fgets() or POSIX
getline() to read the line, and
strtol() to convert to a number, and isspace() to validate the tail end of the line.
Note that using strtol() properly is quite tricky.
In the code below, note the cast to unsigned char in the call to isspace(). That ensures that a valid value is passed to the function, even if the plain char type is signed and the character entered by the user has the high bit set so the value would convert to a negative integer. The valid inputs for any of the ispqrst() or topqrst() functions are EOF or the range of unsigned char.
C11 §7.4 Character handling <ctype.h> ¶1
… In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.
The GNU C library tends to protect the careless, but you should not rely on being nannied by your standard C library.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char line[4096]; /* Make it bigger if you like */
printf("Enter a number: ");
if (fgets(line, sizeof(line), stdin) == 0)
{
fprintf(stderr, "Unexpected EOF\n");
exit(EXIT_FAILURE);
}
errno = 0;
char *eon; /* End of number */
long result = strtol(line, &eon, 0);
if (eon == line)
{
fprintf(stderr, "What you entered is not a number: %s\n", line);
exit(EXIT_FAILURE);
}
if (sizeof(int) == sizeof(long))
{
if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE)
{
fprintf(stderr, "What you entered is not a number in the range %ld..%+ld: %s\n",
LONG_MIN, LONG_MAX, line);
exit(EXIT_FAILURE);
}
}
else
{
if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE)
{
fprintf(stderr, "What you entered is not a number in the range %ld..%+ld,\n"
"let alone in the range %d..%+d: %s\n",
LONG_MIN, LONG_MAX, INT_MIN, INT_MAX, line);
exit(EXIT_FAILURE);
}
}
char c;
while ((c = *eon++) != '\0')
{
if (!isspace((unsigned char)c))
{
fprintf(stderr, "There is trailing information (%c) after the number: %s\n",
c, line);
exit(EXIT_FAILURE);
}
}
if (result < INT_MIN || result > INT_MAX)
{
fprintf(stderr, "What you entered is outside the range %d..%+d: %s\n",
INT_MIN, INT_MAX, line);
exit(EXIT_FAILURE);
}
int i = result; /* No truncation given prior tests */
printf("%d is a valid int\n", i);
return(EXIT_SUCCESS);
}
That seems to work correctly for a fairly large collection of weird numeric and non-numeric inputs. The code handles both 32-bit systems where sizeof(long) == sizeof(int) and LP64 64-bit systems where sizeof(long) > sizeof(int) — you probably don't need that. You can legitimately decide not to detect all the separate conditions but to aggregate some of the errors into a smaller number of error messages.

isdigit() can only test one char if it's digit or not.
in order to test a multi-digit number, you must read this number char by char;
here is an example showing that:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i=0;
char s[100];
printf("enter a number: ");
scanf("%99s", &s);
while(s[i]!='\0'){
if(!isdigit(s[i]))break;
i++;
}
if(s[i]=='\0') printf("%s is a number\n",s);
else printf("%s is NOT a number\n",s);
}

isdigit is a function to check a single char only.
It is not designed to check whether a string is a valid integer or not.
The argument "%i" reads input line and convert it to an integer, so the data stored in i is an integer number, not the ASCII code that isdigit expected.
If you want to validate a single character, you can use "%c" instead of "%i"
#include
#include
int main(){
char c;
int n = scanf("%c",&c);
if(isdigit(c)){
printf("%c is digit\n",c);
}else{
printf("%c is not digit\n",c);
}
return 0;
}
If you want to validate a line, you can check this:
[Check if input is integer type in C] (Check if input is integer type in C)
In short, use "%i%c" instead of "%i", check the result of "%c" to validate if input is purely in digits.

About a while loop with scanf not working, read this from the scanf Linux man page:
The format string consists of a sequence of
directives which describe how to process the sequence of input
characters.
If processing of a directive fails, no further input is read, and scanf() returns. A "failure" can be either of the
following: input failure, meaning that input characters were unavailable, or matching failure, meaning that the input
was inappropriate (see below).
Especially note "If processing of a directive fails, no further input is read"
So if your scanf fails to read an integer you need to do something to read and discard the bad input.

Related

scanf issue: input of integer followed by character, ex: 1p, for a single input is treated as 2 inputs

NB: to avoid misunderstanding, the code is aimed to handle input errors .. i'm asking for integers (no characters) but the user might enter characters by mistake, so how to avoid the following:
I know that scanf sucks but I have to use it for some reasons.
So, the problem I'm facing right now is that if I'm scanning a single integer from the user as follow:
scanf("%d",&c);
if the user enters a digit followed by a character, such as: 1k, it's treated as double input not a single one, and checking the return value for the scanf and using flushinput concept doesn't work here.
To make my question clearer:
The user is prompted to enter a choice, and in case of invalid choice he'd be asked again (through a loop), so, if he enters for ex:
k, gives the message (it's an invalid input) once, and rescans
k2, gives the message (it's an invalid input) once, and rescans
2k, gives the message (it's an invalid input) TWICE then rescans.
Any hints to solve that issue?
Thanks in advance !!
NB: I check the returned value of scanf as follow:
if (scanf("%d",&confirm)!=1)
{
flushInput(); confirm=0;
}
where:
void flushInput()///prevents infinite loops resulted due to character input instead of integer
{
int c; //c ->absorbs the infinite characters resulted due to the entry of chars, using getchar()
while((c = getchar()) != EOF && c != '\n');
}
The following addresses the question with OP's given constraint of using scanf. The preferred choice, however, would be to read entire lines, then parse the strings with safer functions like strtol which perform proper range checking. More about that at atoi vs atol vs strtol vs strtoul vs sscanf.
Using scanf, the sample code below reads one integer per line of input, while rejecting lines that contain any non-whitespace other than the integer itself.
#include <stdio.h>
#include <string.h>
int scanf_solo_int(int *p)
{
// read integer
int ret = scanf("%d", p);
if(ret == EOF) return -1;
// read rest of line
char s[132 + 1];
if(scanf("%132[^\n]", s) != 1) s[0] = '\0';
scanf("%*1[\n]");
if(ret == 1)
{
// check for extra non-whitespace
if(s[strspn(s, " \t\n")] != '\0') ret = 2;
}
return ret;
}
int main()
{
for(;;)
{
int n;
switch(scanf_solo_int(&n))
{
case 1: printf("ok: %d\n", n); continue;
case 0: printf("error: not a number\n"); continue;
case 2: printf("error: extra characters past %d\n", n); continue;
case -1: printf("error: EOF\n"); break;
default: printf("error: unexpected\n"); break;
}
break;
}
return 0;
}
Sample run:
input output
----------- ------------------------------
12 ok: 12
-34 ok: -34
5 6 error: extra characters past 5
x y z error: not a number
7x error: extra characters past 7
8 x error: extra characters past 8
9.0 error: extra characters past 9
2147483647 ok: 2147483647
-2147483648 ok: -2147483648
9876543210 ok: 1286608618
error: EOF
The last line is an example of uncaught integer overflow where scanf accepts the 9876543210 string as %d input, but truncates it mod 2^32 to 1286608618 without warning.

How to check when you scanf that you get only integer (like 2) and not integer followed by char (like 2c)

I'm trying to scanf an integer to see if it's legal in my program. However, if I input a number followed by a char it still treats it as legal number (my guess is that it only refers to the integer while saving the char in the buffer). Assume I can only use scanf and not something else (since that's what we've leraned). Also, if I input only a char it automatically casts it to an integer. This is what I have tried so far, with the help of what I saw here -
int number_of_numbers;
char number='\n';
printf("Enter size of input:");
if (scanf("%d%c",&number_of_numbers, &number)>=1 && number!='\n')
{
printf("Invalid size");
return 0;
}
How can I identify when I scanf only an integer or an integer followed by a char or just a char?
Thanks!
If you enter "only a character" it does not "automatically cast it to an integer". It does not accept any input at all, as shown by scanf returning 0, but that situation escapes your test.
But the answer to your question is: with difficulty when using scanf.
Here is a way to do it getting the input with fgets. It will tolerate any amount of whitespace before or after the number, but not any letters.
The reason for the space before %c is to instruct it to filter any leading whitespace. This is automatic anyway for %d, but not for %c. Then if there are no readable characters, nothing will be read into extra. If there is at least one character (apart from whitespace) then the sscanf conversion count will be incorrect.
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
int number_of_numbers = 0;
while(number_of_numbers >= 0) {
bool success = false;
char str[100];
if(fgets(str, sizeof str, stdin) != NULL) {
char extra;
if(sscanf(str, "%d %c", &number_of_numbers, &extra) == 1) {
success = true;
}
}
if(success) {
printf("Success: %d\n\n", number_of_numbers);
} else {
printf("Invalid size\n\n");
}
}
return 0;
}
Program session:
123
Success: 123
123a
Invalid size
123 a
Invalid size
123 9
Invalid size
a
Invalid size
-1
Success: -1
The reasons for using fgets are
it doesn't "stall" if there is invalid input: it has already been read.
if there is a mistake, the string can easily be dumped and another one requested.

Having Difficulty with isdigit() in C

I have been trying to add some experience in C to my experience with Python and started with a basic addition program. One thing that I'm trying to do is check if the input is a number or a character as seen here:
#include <stdio.h>
#include <ctype.h>
int main()
{
int n, sum=0,c,value;
printf("Enter the Number of Integers You Want to Add\n");
scanf("%d", &n);
if(isdigit(n))
{
printf("Enter %d Integers\n", n);
for(c=1; c<=n; c++)
{
scanf("%d", &value);
if(isalpha(value))
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
else
{
sum = sum + value;
}
}
printf("Sum of Entered Integers = %d\n",sum);
}
else
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
return 0;
}
Initially I had tried this using isalpha(), and the program worked fine when adding numbers but interpreted characters as zeros instead of printing the "not an integer" statement. However, now that I reworked it to use isdigit(), it does not recognize ANY input as an integer, whether or not it is. Is there something that I'm just doing wrong?
When you use scanf to read an integer, you get just that, an integer. (To read a single character, you need %c and a pointer-to-char).
When you use isdigit(), you need to supply the representation of that character (e.g. in ASCII, the character '0' has the representation 48, which is indeed its value as an integer). To recap:
isdigit(0) is false
isdigit(48) is true (for ASCII, ISO8859, UTF-8)
isdigit('0') is true (no matter the character set)
isdigit('0' + n) is true for integers n = 0 ... 9
PS: Not testing the return value from scanf is asking for trouble...
Neither isdigit nor isalpha work as you think they do. The intent of those library functions is to check whether a given code point, represented as an int, is within a subset of points defined by the standard to be digit characters or alpha characters.
You should be checking the results of your scanf calls rather than assuming they just work, and acting on those results accordingly. If you request an integer and one is successfully scanned, then it will tell you so. If that fails, your course of action is probably to consume the rest of the line (through newline or EOF) and possibly try again:
#include <stdio.h>
int main()
{
int n,value,sum=0;
printf("Enter the Number of Integers You Want to Add\n");
if (scanf("%d", &n) == 1 && n > 0)
{
printf("Enter %d Integers\n", n);
while (n--)
{
if (scanf("%d", &value) == 1)
{
sum = sum + value;
}
else
{
// consume the rest of the line. if not EOF, we
// loop around and try again, otherwise break.
while ((value = fgetc(stdin)) != EOF && value != '\n');
if (value == EOF)
break;
++n;
}
}
printf("Sum of Entered Integers = %d\n", sum);
}
return 0;
}
Properly done you should be able to enter valid integers beyond single digits (i.e. values > 10 or < 0), which the above allows.
The %d marker to scanf tells it to interpret the input as a number (more accurately, it indicates that the pointer in the arguments points to an integer type). It can't do anything but put an integer into that argument. If it can't interpret the input as a number, scanf stops scanning the input and returns immediately.
isdigit() evaluates its argument as a character code, as Jens points out above. However, scanf already turned the character code into a pure number.
From the scanf man page:
On success, the function returns the number of items of the argument list
successfully filled.
In your program, you are trying to read just one item from stdin, so scanf should return 1. So check for that and you'll know that it all worked out ok:
printf("Enter the Number of Integers You Want to Add\n");
while(scanf("%d", &n) != 1) {
printf("That's not a valid integer. Please try again.\n");
}
You cannot use isdigit() the way you are using it because you're already using scanf to convert the user input to an integer. If the user had not input an integer, scanf would have already failed.
Look at the man pages for all the C functions you are using, they will show you what the function expects and what the return values will be under different circumstances.
In the case of isdigit(), the input is expected to be an unsigned char representing an ASCII character. This can be a bit confusing because ASCII characters are in fact represented as a type of integer, and a string is an array of those. Unlike languages like Python which hide all that from you. But there is a big difference between the STRING of a number (array of characters that contain the characters of the digits of the number) and the INTEGER itself which is in a form the processor actually uses to do math with... (simplified explanation, but you get the idea).

scanf test failing inside a function in C

I'm trying to do a program with a simple game for a user to guess the number. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 30
#define TRYING 5
void guessnumber(int, int, int *);
int main(void) {
int mytry = 1;
guessnumber(MAX, TRYING, &mytry);
if (mytry <= TRYING)
printf("Congratulations! You got it right in %d tries\n", mytry);
else
printf("Unfortunately you could not guess the number in the number of tries predefined\n");
printf("End\n");
return EXIT_SUCCESS;
}
void guessnumber(int _n, int _m, int *_mytry) {
srandom(time(NULL));
int generated = 0, mynum = 0, test = 0;
generated = rand() % (_n + 1);
printf("Welcome to \"Guess the number\" \n");
printf("A number between 0 and %d was generated\n", _n);
printf("Guess the number:\n");
while (*_mytry <= TRYING) {
test = scanf(" %d", &mynum);
if (test != 1 || mynum < 0 || mynum > MAX)
printf("ERROR: please enter a valid number \n");
else
if (mynum > generated)
printf("Wrong! The number your trying to guess is smaller\n");
else
if (mynum < generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry = *_mytry + 1;
}
}
Okay, now the program is working pretty ok except for one thing: the scanf test.
It works if I try to enter a number out of my range (negative or above my upper limit) but it fails if I for example try to enter a letter. What it does is that it prints the message of error _m times and then it prints "Unfortunately you could not guess the number in the number of tries predefined" and "End".
What am I doing wrong and how can I fix this?
In case, a character is entered, you're trying to detect it correctly
if(test!=1 ......
but you took no action to correct it.
To elaborate, once a character is inputted, it causes a matching failure. So the input is not consumed and the loop falls back to the genesis position, only the loop counter is increased. Now, the previous input being unconsumed, is fed again to the scanf() causing failure once again.
This way, the loop continues, until the loop condition is false. Also, for every hit to scanf(), as unconsumed data is already present in the input buffer, no new prompt is given.
Solution: You need to clean the input buffer of existing contents when you face a failure. You can do something like
while ((c = getchar()) != '\n' && c != EOF);
to clean the buffer off existing contents.
When you enter a letter, scanf() leaves the letter in the input stream since it does not match the %d conversion specifier. The simplest thing to do is use getchar() to remove the unwanted character:
if (test != 1) {
getchar();
}
A better solution would be to use fgets() to get a line of input, and sscanf() to parse the input:
char buffer[100];
while (*_mytry<=TRYING)
{
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()");
exit(EXIT_FAILURE);
}
test=sscanf(buffer, "%d", &mynum);
if(test!=1 || mynum<0 || mynum>MAX)
printf ("ERROR: please enter a valid number \n");
else if(mynum>generated)
printf("Wrong! The number your trying to guess is smaller\n");
else if(mynum<generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry=*_mytry+1;
}
In the above code, note that the leading space has been removed from the format string. A leading space in a format string causes scanf() to skip leading whitespaces, including newlines. This is useful when the first conversion specifier is %c, for example, because any previous input may have left a newline behind. But, the %d conversion specifier (and most other conversion specifiers) already skips leading whitespace, so it is not needed here.
Additionally, your code has srandom() instead of srand(); and the call to srand() should be made only once, and probably should be at the beginning of main(). And, identifiers with leading underscores are reserved in C, so you should change the names _m, _n, and _mytry.

How validate user input when the expected value is of type int and the entered value is not of type int?

I have the following code:
#include <stdio.h>
#define MIN 0
#define MAX 9
int main()
{
int n;
while (1) {
printf("Enter a number (%d-%d) :", MIN, MAX);
scanf("%d", &n);
if (n >= MIN && n <= MAX) {
printf("Good\n");
} else {
printf("Damn you!\n");
break;
}
}
return 0;
}
The above code works as expected as long as the user inputs an integer value. For example,
$ ./a.out
Enter a number (0-9) :15
Damn you!
$ ./a.out
Enter a number (0-9) :5
Good
Enter a number (0-9) :3
Good
Enter a number (0-9) :-1
Damn you!
$ ./a.out
But, when the user enters any unexpected input (like <up-arrow> - which is ^[[A, or any string like abc or abc def, etc), it fails and goes in to an infinite loop.
$ ./a.out
Enter a number (0-9) :2
Good
Enter a number (0-9) :^[[A
Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
Enter a number (0-9) :Good
^C
One thing to note: when the use enters <up-arrow> for the first time, it works as expected! For example,
$ ./a.out
Enter a number (0-9) :^[[A
Damn you!
$
Why is this odd behavior? How should we handle the case where user enters something that is unappropriate?
My advice would be to check the return value of scanf(). If it is zero, there has been a matching failure (ie the user didn't input an integer).
The reason it is succeeding is because n is not altered by scanf() when the match fails, so the check is performed on an uninitialised 'n'. My advice -there- would be to always initialise everything so that you don't end up getting weird logic results like you have there.
For example:
if (scanf("%d",&n) != 1))
{
fprintf(stderr,"Input not recognised as an integer, please try again.");
// anything else you want to do when it fails goes here
}
Personally, I advise ditching scanf altogether for interactive user input, especially for numeric input. It just isn't robust enough to handle certain bad cases.
The %d conversion specifier tells scanf to read up to the next non-numeric character (ignoring any leading whitespace). Assume the call
scanf("%d", &val);
If your input stream looks like {'\n', '\t', ' ', '1', '2', '3', '\n'}, scanf will skip over the leading whitespace characters, read and convert "123", and stop at the trailing newline character. The value 123 will be assigned to val, and scanf will return a value of 1, indicating the number of successful assignments.
If your input stream looks like {'a', 'b', 'c', '\n'}, scanf will stop reading at the a, not assign anything to val, and return 0 (indicating no successful assignments).
So far, so good, right? Well, here's an ugly case: suppose your user types in "12w4". You'd probably like to reject this entire input as invalid. Unfortunately, scanf will happily convert and assign the "12" and leave the "w4" in the input stream, fouling up the next read. It will return a 1, indicating a successful assignment.
Here's another ugly case: suppose your user types in an obnoxiously long number, like "1234567890123456789012345678901234567890". Again, you'd probably like to reject this input outright, but scanf will go ahead and convert and assign it, regardless of whether the target data type can represent that value or not.
To properly handle those cases, you need to use a different tool. A better option is to read the input as text using fgets (protecting against buffer overflows), and manually convert the string using strtol. Advantages: you can detect and reject bad strings like "12w4", you can reject inputs that are obviously too long and out of range, and you don't leave any garbage in the input stream. Disadvantages: it's a bit more work.
Here's an example:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
...
#define DIGITS ... // maximum number of digits for your target data type;
// for example, a signed 16-bit integer has up to 5 digits.
#define BUFSIZ (DIGITS)+3 // Account for sign character, newline, and 0 terminator
...
char input[BUFSIZ];
if (!fgets(input, sizeof input, stdin))
{
// read error on input - panic
exit(-1);
}
else
{
/**
* Make sure the user didn't enter a string longer than the buffer
* was sized to hold by looking for a newline character. If a newline
* isn't present, we reject the input and read from the stream until
* we see a newline or get an error.
*/
if (!strchr(input, '\n'))
{
// input too long
while (fgets(input, sizeof input, stdin) && !strchr(input, '\n'))
;
}
else
{
char *chk;
int tmp = (int) strtol(input, &chk, 10);
/**
* chk points to the first character not converted. If
* it's whitespace or 0, then the input string was a valid
* integer
*/
if (isspace(*chk) || *chk == 0)
val = tmp;
else
printf("%s is not a valid integer input\n", input);
}
}
I would use a char buffer to get the input and then convert it to an integer with e.g. atoi.
Only problem here is that atoi returns 0 on failure (you can't determine if it's 0 because of failure or because the value is 0).
Also you could just compare the strings with strncmp.
// edit:
As suggested in the comments you can do the check with isdigit()
Since I'm a bit in a hurry I couldn't implemented my example in your use case, but I also doubt that this causes any troubles.
Some example code would be:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int x;
char buf[4] = {0};
scanf("%s",buf);
if(isdigit(buf[0]))
{
x = atoi(buf);
if( x > 9)
{
// Not okay
}
else
{
// okay
}
}
else
{
// Not okay
}
return 0;
}
If the first element of the buffer is not a digit you know its wrong input anyway.
Otherwise you check the value now with atoi and look if its greater than 9. ( You don't need to check the lower value since -1 would already be detected in the isdigt call ( buf[0] would be "-" )
I have updated the code as follows (checked scanf() return value) and it works fine.
#include <stdio.h>
#include <errno.h>
#define MIN 0
#define MAX 9
int main()
{
int n, i;
while (1) {
errno = 0;
printf("Enter a number (%d-%d) :", MIN, MAX);
if (scanf("%d", &n) != 1) {
printf("Damn you!\n");
break;
}
if (n >= MIN && n <= MAX) {
printf("Good\n");
} else {
printf("Damn you!\n");
break;
}
}
return 0;
}
The following are few things to note from the scanf() man page!
man scanf
The format string consists of a sequence of directives which describe how to process the sequence of input characters. If processing of a directive fails, no further input is read, and scanf() returns. A "failure" can be either of the following: input failure, meaning that input characters were unavailable, or matching failure, meaning that the input was inappropriate.
RETURN VALUE:
scanf return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure. The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream is set, and errno is set indicate the error.
scanf return the number of fields it read, so you can do something like
if (scanf("%d",&n)<1) exit(1)
or even:
while(scanf("%d",&n)!=1);

Resources