Ingrese un carácter como entrada a una variable entera, dando un bucle infinito

#include #include int main() { int number, sum = 0; // loop body is executed at least once do { printf("Enter a number: "); scanf("%d", &number); sum += number; } while(number != 0); printf("Sum = %d",sum); } 

Este código debía imprimir la sum de todos los enteros ingresados ​​por el usuario. Pero cuando el usuario ingresa una letra como entrada, en lugar de lanzar un error, entraba en un bucle infinito, imprimiendo la statement “ingrese un número” pero sin ejecutar ninguna otra statement en el bucle.

¿Alguien puede decirme por qué sucede esto?

Una solución adecuada para su código sería el siguiente fragmento. Compruebe si scanf () fue exitoso y luego proceda

 if (scanf("%d", &number) != 1) { break; } 

scanf es raro Tiene un búfer interno y solo se leerá de la secuencia si ese búfer está vacío. Al comienzo de su código, no hay nada, por lo que se lee una línea de la entrada estándar. Entonces scanf intenta encontrar un número entero allí. Si se encuentra un entero, notificará que leyó correctamente un elemento (devolviendo 1 ) y coloca el valor de lectura en la ubicación del puntero suministrado. Sin embargo, si no se encuentra un entero, devolverá 0 para “cero elementos leídos correctamente”, y no consumirá nada del búfer . Esto significa que, la próxima vez que se invoque scanf , el búfer no estará vacío, por lo tanto, no se le solicitará una nueva línea al usuario, y scanf intentará nuevamente leer un número entero exactamente en el mismo lugar que probó la última vez (y falla por exactamente la misma razón). Así, el bucle infinito.

Para ilustrar esta cosa del “buffer”, intente esto:

 scanf("%d", &a); scanf("%d", &b); printf("a: %d, b: %d\n", a, b); 

e ingrese 12 53 en una línea , como la entrada al primer scanf . Mágicamente, a termina como 12 y b termina como 53 . La explicación para la magia es: el primer scanf encontró el búfer vacío, leyó la línea del usuario y encontró un entero, como se le dijo; el segundo scanf encontró el búfer con algunas cosas todavía allí, y continuó leyendo donde se quedó el último sin tener que pedirle al usuario una nueva línea.

Como ya han comentado otros, generalmente es mejor leer una línea usted mismo ( fgets ) y analizarla usted mismo ( strtol ), o si necesita usar scanf , asegúrese de verificar si scanf lee lo que esperaba al inspeccionar su devolución código. Consulte aquí cómo limpiar el búfer de entrada si falla scanf .

scanf() no descarta la entrada que no coincide con el especificador de formato. Debería leerlo en un char [] con %s luego hacer un atoi() para intentar convertirlo en una cadena. Si falla, ERRNO se establecerá en algún código de error. De esa manera, no dejará ninguna entrada sin procesar si se ingresa algo más que un dígito.

Esta pregunta ya ha sido respondida aquí .

Citando de la respuesta:

El especificador de conversión% d espera que el texto de entrada se formatee como un entero decimal. Si no es así, la conversión falla y el carácter que causó la falla de la conversión se deja en la secuencia de entrada. Las llamadas adicionales a scanf () con el especificador de conversión% d se ahogarán con el mismo carácter.

Básicamente, esto significa que cuando llama a scanf() con %d como especificador de conversión, esperará que el usuario ingrese un entero decimal. Sin embargo, cuando el usuario ingresa un carácter (% c) como entrada, la conversión falla y el carácter ingresado permanece en el flujo de entrada. Esto hará que el bucle while continúe para siempre sin permitir que el usuario ingrese más entradas.

Para evitar esto, puedes probar algo como:

 while (x != 0){ int tmp; if (scanf("%d", &tmp) == 0) getchar(); else number = tmp; } 

Una de las posibles soluciones es agregar el código de limpieza del búfer de entrada después del escaneo, por ejemplo, bucle con getchar:

 #include #include int main() { int number = -1; // any number not equal 0, to prevent loop break // after wrong input at the first iteration int sum = 0; int c; // char to read input // loop body is executed at least once do { printf("Enter a number: "); if(scanf("%d", &number) == 1) { sum += number; // add if read was successful } // buffer clean while ((c = getchar()) != '\n' && c != EOF); } while(number != 0); printf("Sum = %d",sum); } 

También se conocen opciones para limpiar el buffer de entrada:

  1. fseek(stdin,0,SEEK_END);
  2. fflush(stdin); (para algunos comstackdores y sistemas operativos funciona)