¿Cómo escanear solo un número entero y repetir la lectura si el usuario ingresa caracteres no numéricos?

Aquí está el problema de un pequeño tío joven con el código C intentando simplemente evitar que el usuario escriba un carácter o un número entero menor que 0 o más de 23.

#include  #include  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; } 

Lo hice a la mitad y se apreciará un pequeño impulso.

Utilice scanf("%d",&rows) lugar de scanf("%s",input)

Esto le permite obtener directamente el valor entero de stdin sin necesidad de convertir a int.

Si el usuario ingresa una cadena que contiene caracteres no numéricos, entonces debe limpiar su stdin antes del siguiente scanf("%d",&rows) .

tu código podría verse así:

 #include  #include  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; } 

Explicación

1)

 scanf("%d%c", &rows, &c) 

Esto significa esperar que el usuario ingrese un entero y cerca de él un carácter no numérico.

Ejemplo 1: si el usuario ingresa aaddk y luego ENTER , el scanf devolverá 0. Nothing capted

Ejemplo 2: si el usuario ingresa 45 y luego ENTER , el scanf devolverá 2 (2 elementos están captados). Aquí %d está encabezando 45 y %c está encabezando \n

Ejemplo 3: si el usuario ingresa 45aaadd y luego ENTER , el scanf devolverá 2 (2 elementos están captados). Aquí %d está limitando 45 y %c está limitando a

2)

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

En el ejemplo1: esta condición es TRUE porque scanf return 0 ( !=2 )

En el ejemplo2: esta condición es FALSE porque scanf return 2 c == '\n'

En el ejemplo3: esta condición es TRUE porque scanf return 2 c == 'a' (!='\n')

3)

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

clean_stdin() siempre es TRUE porque la función devuelve siempre 1

En el ejemplo1: El (scanf("%d%c", &rows, &c)!=2 || c!='\n') es TRUE por lo que debe verificarse la condición después de && para que clean_stdin() sea ejecutado y toda la condición es TRUE

En el ejemplo2: El (scanf("%d%c", &rows, &c)!=2 || c!='\n') es FALSE por lo que la condición después de && no se marcará (porque el resultado es toda la condición será FALSE ) por lo que clean_stdin() no se ejecutará y toda la condición es FALSE

En el ejemplo3: El (scanf("%d%c", &rows, &c)!=2 || c!='\n') es TRUE por lo que debe verificarse la condición después de && para que clean_stdin() sea ejecutado y toda la condición es TRUE

Por lo tanto, puede observar que clean_stdin() se ejecutará solo si el usuario ingresa una cadena que contiene caracteres no numéricos.

Y esta condición ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) devolverá FALSE solamente si el usuario ingresa un integer y nada más

Y si la condición ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) es FALSE y el integer está entre y 1 y 23 entonces el while loop se romperá, el ciclo while continuará

 #include  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] en scanf() devora todo lo que no está entre 0 y 9 . Básicamente, limpia la stream de entrada de los no dígitos y la pone en str . Bueno, la longitud de la secuencia sin dígitos está limitada a 100. El siguiente %d selecciona solo enteros en la secuencia de entrada y lo coloca en num .

Puede crear una función que lea un número entero entre 1 y 23 o devuelva 0 si no es int

p.ej

 int getInt() { int n = 0; char buffer[128]; fgets(buffer,sizeof(buffer),stdin); n = atoi(buffer); return ( n > 23 || n < 1 ) ? 0 : n; } 

Tendrá que repetir su llamada a strtol dentro de sus bucles donde le está pidiendo al usuario que intente de nuevo. De hecho, si haces que el ciclo sea un do { ... } while(...); en lugar de while, no obtienes el mismo tipo de comportamiento de repetir cosas dos veces.

También debe formatear su código para que sea posible ver dónde está el código dentro de un bucle y no.

MOHAMED, tu respuesta es genial y realmente me ayudó. Aquí he publicado un código, que creo que es un poco más simple:

 #include  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; } 

En mi caso, quiero que el número sea simplemente positivo. Si quieres que tu número esté entre 1 y 23, reemplazas el number<0 con el number<1 || number>23 number<1 || number>23 en la statement if . También tendrá que cambiar la letra de molde para imprimir un mensaje apropiado.

 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 

Si la entrada es número, puede usar foo como su entrada.