using scanf() in while loop

O

obdict

Hello,

I used scanf() in a while loop, which ensures that user input is
valid (must be an integer no greater than 21 or less than 3).
If user enters a number out of the range, or enters non-number,
he/she will be asked to retry.

/* start */

int n;

while(1){
printf("Please enter an integer (3 <= x <= 21): \n");
if(scanf("%d", &n) && (n >= 3) && (n <= 21)){
return n;
}
printf("The input must be a number within the (3, 21) range,
inclusive. Please retry.\n"); //Point A
}

/* End */

In the above code, the first condition (scanf("%d", &n))
tests whether user inputs a number. In my tests, since
the format specifier is %d, my take is that if user enters
anything other than an integer, scanf() will not modify n,
and will by itself return 0 indicating reading data has failed
as a result of type mismatch.

My problem is that when user inputs something other than
an integer, the scanf() never runs again, and this while loop
continues indefinitely.

Weirdly, if I input an integer out of the (3,21) boundary,
it runs correctly and re-prompts me for a new value.

Any opinion is welcome. Thanks in advance
 
J

John Valko

obdict said:
Hello,

I used scanf() in a while loop, which ensures that user input is
valid (must be an integer no greater than 21 or less than 3).
If user enters a number out of the range, or enters non-number,
he/she will be asked to retry.

/* start */

int n;

while(1){
printf("Please enter an integer (3 <= x <= 21): \n");
if(scanf("%d", &n) && (n >= 3) && (n <= 21)){
return n;
}
printf("The input must be a number within the (3, 21) range,
inclusive. Please retry.\n"); //Point A
}

/* End */

In the above code, the first condition (scanf("%d", &n))
tests whether user inputs a number. In my tests, since
the format specifier is %d, my take is that if user enters
anything other than an integer, scanf() will not modify n,
and will by itself return 0 indicating reading data has failed
as a result of type mismatch.

My problem is that when user inputs something other than
an integer, the scanf() never runs again, and this while loop
continues indefinitely.

scanf() in fact does run again. The problem is that it sees data that
doesn't match your format string sitting on stdin, and thus returns
without touching it. You never take this data off the stream, and so
scanf() just keeps failing. To get around this, one solution is to read
the garbage data off of stdin:

int ch;
while((ch = getchar()) != '\n' && ch != EOF);

Although a better solution may be to not use scanf() at all. You should
also change your scanf() comparison, perhaps to == 1. If scanf() fails
because of end of file, it will return EOF which is negative, and your
current program will interpret this as a successful read.

Hope that helps,

--John
 
A

abhimanyu.v

In my view writing such code is not usefull at all. It is consfusing
as well as incorrect. So it is better to devide the range checking and
user input for better clarity of the logic. Though it is always your
wish. Also a character is an number if you see its Ascii equivalent. So
the logic you want to have it invalid in the case of character also.
 
V

Vladimir S. Oka

In my view writing such code is not usefull at all. It is consfusing
as well as incorrect.

What code? I see no code, and no code is correct code.
So it is better to devide the range checking and
user input for better clarity of the logic.

Indeed, but how is this related to C?
Also a character is an number if you see its Ascii equivalent.

No it is not, at least not in C. And what about EBCDIC?
So
the logic you want to have it invalid in the case of character also.

Now I'm really confused.

Advice (do follow it in this group):

- quote what and who you're replying to (if using Google, click on Show
Options, and then on Reply that appears below the headers)
- don't top post
- stay on topic (which is Standard C as defined by ISO)
 
F

Fred Kleinschmidt

obdict said:
Hello,

I used scanf() in a while loop, which ensures that user input is
valid (must be an integer no greater than 21 or less than 3).
If user enters a number out of the range, or enters non-number,
he/she will be asked to retry.

/* start */

int n;

while(1){
printf("Please enter an integer (3 <= x <= 21): \n");
if(scanf("%d", &n) && (n >= 3) && (n <= 21)){
return n;
}
printf("The input must be a number within the (3, 21) range,
inclusive. Please retry.\n"); //Point A
}

/* End */

In the above code, the first condition (scanf("%d", &n))
tests whether user inputs a number. In my tests, since
the format specifier is %d, my take is that if user enters
anything other than an integer, scanf() will not modify n,
and will by itself return 0 indicating reading data has failed
as a result of type mismatch.

Not true. For example, if the user enters "123xyz", n will be assigned a
value of 123, the input scan will stop when the "x" is encountered and scanf
will return a value of 3. Subsequent scanf will all fail, each time trying
to read "x".

Best bet is not to use scanf for input. Use fgets instead.
 
P

Pedro Graca

Fred said:
For example, if the user enters "123xyz", n will be assigned a
value of 123, the input scan will stop when the "x" is encountered and scanf
^^^^^
will return a value of 3. Subsequent scanf will all fail, each time trying ^^^^^^^^^^^^^^^^^^^^^^^^
to read "x".

Not exactly true either :)

<quote src="man 3 scanf">
RETURN VALUE
[...] If an error or end-of-file occurs after conversion has
begun, the number of conversions which were successfully
completed is returned.
</quote>


tmp$ cat foo.c
#include <stdio.h>

int main(void) {
int m, n=0;
m = scanf("%d", &n);
printf("Value read: %d\n", n);
printf("Value returned: %d\n", m);
return 0;
}

tmp$ gcc -W -Wall -Werror -std=c89 -pedantic -O2 foo.c -ofoo
tmp$ echo "123xyz" | ./foo
Value read: 123
Value returned: 1
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top