问题
Here is some C code trying simply to prevent the user from typing a character or an integer less than 0 or more than 23.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char *input;
char *iPtr;
int count = 0;
int rows;
printf(\"Enter an integer: \");
scanf(\"%s\", input);
rows = strtol(input, &iPtr, 0);
while( *iPtr != \'\\0\') // Check if any character has been inserted
{
printf(\"Enter an integer between 1 and 23: \");
scanf(\"%s\", input);
}
while(0 < rows && rows < 24) // check if the user input is within the boundaries
{
printf(\"Select an integer from 1 to 23: \");
scanf(\"%s\", input);
}
while (count != rows)
{
/* Do some stuff */
}
return 0;
}
I made it halfway through and a small push up will be appreciated.
回答1:
Use scanf("%d",&rows) instead of scanf("%s",input)
This allow you to get direcly the integer value from stdin without need to convert to int.
If the user enter a string containing a non numeric characters then you have to clean your stdin before the next scanf("%d",&rows).
your code could look like this:
#include <stdio.h>
#include <stdlib.h>
int clean_stdin()
{
while (getchar()!='\n');
return 1;
}
int main(void)
{
int rows =0;
char c;
do
{
printf("\nEnter an integer from 1 to 23: ");
} while (((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) || rows<1 || rows>23);
return 0;
}
Explanation
1)
scanf("%d%c", &rows, &c)
This means expecting from the user input an integer and close to it a non numeric character.
Example1: If the user enter aaddk and then ENTER, the scanf will return 0. Nothing capted
Example2: If the user enter 45 and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting \n
Example3: If the user enter 45aaadd and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting a
2)
(scanf("%d%c", &rows, &c)!=2 || c!='\n')
In the example1: this condition is TRUE because scanf return 0 (!=2)
In the example2: this condition is FALSE because scanf return 2 and c == '\n'
In the example3: this condition is TRUE because scanf return 2 and c == 'a' (!='\n')
3)
((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())
clean_stdin() is always TRUE because the function return always 1
In the example1: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE
In the example2: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is FALSE so the condition after the && will not checked (because what ever its result is the whole condition will be FALSE ) so the clean_stdin() will not be executed and the whole condition is FALSE
In the example3: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE
So you can remark that clean_stdin() will be executed only if the user enter a string containing non numeric character.
And this condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) will return FALSE only if the user enter an integer and nothing else
And if the condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) is FALSE and the integer is between and 1 and 23 then the while loop will break else the while loop will continue
回答2:
#include <stdio.h>
main()
{
char str[100];
int num;
while(1) {
printf("Enter a number: ");
scanf("%[^0-9]%d",str,&num);
printf("You entered the number %d\n",num);
}
return 0;
}
%[^0-9] in scanf() gobbles up all that is not between 0 and 9. Basically it cleans the input stream of non-digits and puts it in str. Well, the length of non-digit sequence is limited to 100. The following %d selects only integers in the input stream and places it in num.
回答3:
You could create a function that reads an integer between 1 and 23 or returns 0 if non-int
e.g.
int getInt()
{
int n = 0;
char buffer[128];
fgets(buffer,sizeof(buffer),stdin);
n = atoi(buffer);
return ( n > 23 || n < 1 ) ? 0 : n;
}
回答4:
char check1[10], check2[10];
int foo;
do{
printf(">> ");
scanf(" %s", check1);
foo = strtol(check1, NULL, 10); // convert the string to decimal number
sprintf(check2, "%d", foo); // re-convert "foo" to string for comparison
} while (!(strcmp(check1, check2) == 0 && 0 < foo && foo < 24)); // repeat if the input is not number
If the input is number, you can use foo as your input.
回答5:
You will need to repeat your call to strtol inside your loops where you are asking the user to try again. In fact, if you make the loop a do { ... } while(...); instead of while, you don't get a the same sort of repeat things twice behaviour.
You should also format your code so that it's possible to see where the code is inside a loop and not.
回答6:
MOHAMED, your answer is great and it really helped me. Here I have posted a code, that I think it is a little bit simpler:
#include <stdio.h>
int getPositive(void);
void clean_input(void);
int main(void) {
printf("%d\n",getPositive());
return 0;
}
int getPositive(void) {
int number;
char buffer; // Holds last character from user input.
// (i.e '\n' or any other character besides numbers)
int flag; // Holds scanf return value
do{
flag = scanf("%d%c", &number, &buffer); // Gets input from user
// While scanf did not read 2 objects (i.e 1 int & 1 char)
// or the user inputed a number and then a character (eg. 12te)
// ask user to type a valid value
while (flag !=2 || buffer!='\n') {
clean_input();
printf("%s","You have typed non numeric characters.\n"
"Please type an integer\n?");
flag = scanf("%d%c", &number, &buffer);
}
if(number<0) {
printf("%s","You have typed a non positive integer\n"
"Please type a positive integer\n?");
} else { // If user typed a non negative value, exit do-while.
break;
}
}while(1);
}
void clean_input(void) {
while (getchar()!='\n');
return;
}
In my case I want the number to be just positive. If you want your number to be between 1 and 23, you replace the number<0 with number<1 || number>23 in the if statement. Also you will have to change the printf to print an appropriate message.
来源:https://stackoverflow.com/questions/14099473/how-to-scanf-only-integer-and-repeat-reading-if-the-user-enters-non-numeric-char