How to scan only one whole and repeat reading if the user enters non-digital characters?

Here is a minor tyro issue with C code trying to simply prevent the user from entering a character or 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 did it halfway, and a slight boost will be appreciated.

+13
source share
7 answers

Use scanf("%d",&rows) instead of scanf("%s",input)

This allows you to get the direct integer value from stdin without the need for conversion to int.

If the user enters a string containing non-digital characters, you must clear your stdin before the next scanf("%d",&rows) .

your code might 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 that an integer is entered from the user and a non-digital character is next to him.

Example1: If the user enters aaddk and then ENTER , scanf will return 0. Nothing is closed

Example2: If the user enters 45 and then ENTER , scanf will return 2 (2 items are closed). Here %d is capting 45 and %c is capting \n

Example 3: If the user enters 45aaadd and then ENTER , scanf will return 2 (2 items are closed). Here %d is capting 45 and %c is capting a

2)

 (scanf("%d%c", &rows, &c)!=2 || c!='\n') 

In Example 1: this is a TRUE condition because scanf return 0 ( !=2 )

In Example 2: this is a FALSE condition because scanf return 2 and c == '\n'

In Example 3: this is a TRUE condition because scanf return 2 and c == 'a' (!='\n')

3)

 ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) 

clean_stdin() always TRUE because the function always returns 1

In example 1: (scanf("%d%c", &rows, &c)!=2 || c!='\n') - TRUE , so the condition after && must be checked to execute clean_stdin() , and that's it condition TRUE

In Example 2: (scanf("%d%c", &rows, &c)!=2 || c!='\n') is FALSE , so the condition after && will not be checked (since its result will be equal to the whole FALSE ), therefore clean_stdin() will not be executed, and the whole condition is FALSE

In example 3: (scanf("%d%c", &rows, &c)!=2 || c!='\n') - TRUE , so the condition after && must be checked to execute clean_stdin() and the whole condition TRUE

So, you may notice that clean_stdin() will only execute if the user enters a string containing a non-digital character.

And this condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) will return FALSE only if the user enters integer and nothing else

And if the condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) is FALSE and integer is between and 1 and 23 , then the while will break otherwise, while will continue

+33
source
 #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() copies everything that is not between 0 and 9 . Essentially, it clears the input stream without numbers and puts it in str . Well, the length of the non-digital sequence is limited to 100. The next %d selects only integers in the input stream and puts it in num .

+2
source

You can create a function that reads an integer from 1 to 23 or returns 0 if not-int

eg.

 int getInt() { int n = 0; char buffer[128]; fgets(buffer,sizeof(buffer),stdin); n = atoi(buffer); return ( n > 23 || n < 1 ) ? 0 : n; } 
+1
source
 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 a number, you can use foo as your input.

+1
source

You will need to repeat your strtol call inside your loops, where you ask the user to try again. In fact, if you do a loop a do { ... } while(...); and not time, you will not get the same duplication twice.

You should also format your code so that you can see where the code is inside the loop, not.

0
source

MOHAMED, your answer is great and it really helped me. Here I have posted the code, which I think is a 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. // (ie '\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 (ie 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 number<0 with number<1 || number>23 number<1 || number>23 in the if statement . You will also need to modify printf to print the corresponding message.

0
source

The above script created by Yonggoo Noh worked well for me.
I changed it to include the value 0 to return to main () at any time, but I have a problem :
- Sometimes, after returning to main (), when I enter the script again, it asks me for the value ("check1") 2 or more times.
Why is this going to happen?

 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) || foo==0))); // repeat if the input is not number if (n==0){ main(); } 
0
source

Source: https://habr.com/ru/post/977269/


All Articles