How to scanf only integer and repeat reading if the user enters non-numeric characters?

守給你的承諾、 提交于 2019-11-26 04:47:47

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!