Tengo un pequeño programa en C que solo lee números de stdin, uno en cada ciclo de ciclo. Si el usuario ingresa algo de NaN, se debe imprimir un error en la consola y el indicador de entrada debe regresar nuevamente. Al ingresar “0”, el ciclo debe terminar y el número de valores positivos/negativos dados debe imprimirse en la consola. Aquí está el programa:
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
Mi problema es que al ingresar algo que no es un número (como “a”), esto da como resultado un bucle infinito que escribe “-> Err …” una y otra vez. Supongo que es un problema de scanf() y sé que esta función podría reemplazarse por una más segura, pero este ejemplo es para principiantes, que saben solo sobre printf/scanf, if-else y bucles.
Ya he leído las respuestas a la pregunta.scanf()
se salta todos los demás while
bucle en C y hojeó otras preguntas, pero nada realmente responde a este problema específico.
Debido a los problemas con scanf
señalado por las otras respuestas, realmente debería considerar usar otro enfoque. siempre he encontrado scanf
demasiado limitado para cualquier lectura y procesamiento de entrada serio. Es una mejor idea leer líneas completas con fgets
y luego trabajar en ellos con funciones como strtok
y strtol
(que, por cierto, analizará correctamente los enteros y le dirá exactamente dónde comienzan los caracteres no válidos).

Lucas
Creo que solo tienes que vaciar el búfer antes de continuar con el ciclo. Algo así probablemente haría el trabajo, aunque no puedo probar lo que estoy escribiendo desde aquí:
int c;
while((c = getchar()) != '\n' && c != EOF);
scanf()
deja el “a
” todavía en el búfer de entrada para la próxima vez. Probablemente deberías usar getline()
para leer una línea sin importar qué y luego analizarla con strtol()
o similar en su lugar.
(Sí, getline()
es específico de GNU, no POSIX. ¿Así que lo que? La pregunta está etiquetada como “gcc” y “linux”. getline()
también es la única opción sensata para leer una línea de texto a menos que desee hacerlo todo a mano).
Hola, sé que este es un hilo antiguo, pero acabo de terminar una tarea escolar donde me encontré con este mismo problema. Mi solución es que usé gets() para recoger lo que scanf() dejó atrás.
Aquí está el código OP ligeramente reescrito; probablemente no le sirva de nada, pero tal vez ayude a alguien más.
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
char unwantedCharacters[40]; //created array to catch unwanted input
unwantedCharacters[0] = 0; //initialzed first byte of array to zero
while (1)
{
printf("-> ");
scanf("%d", &number);
gets(unwantedCharacters); //collect what scanf() wouldn't from the input stream
if (unwantedCharacters[0] == 0) //if unwantedCharacters array is empty (the user's input is valid)
{
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
else
printf("Err...\n");
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
Muchas preguntas de SO estrechamente relacionadas, que incluyen: stackoverflow.com/questions/1669821
–Jonathan Leffler
11 de noviembre de 2009 a las 22:34
En respuesta a todas las respuestas y sugerencias: Agregar while (getchar() != ‘\n’); antes de “continuar” dentro de la declaración if funciona muy bien para mí y (con suerte) resuelve todos/la mayoría de los problemas. Además, es razonablemente explicable para los principiantes :).
– usuario208785
13 de noviembre de 2009 a las 20:51
Véase también Uso
fflush(stdin)
.–Jonathan Leffler
15 de septiembre de 2016 a las 5:32