2012-06-21 9 views
5

Me encontré con este problema cuando quiero comprobar lo que ingresé es número. La función scanf devolverá 1 si ingreso con éxito un número. Así que aquí está lo que escribí:¿Qué sucede cuando ingresas cosas como 12ab a scanf ("% d", & argu)?

int argu; 
while(scanf("%d",&argu)!=1){ 
    printf("Please input a number!\n"); 
} 

Pero cuando las cosas I de entrada como ABCD para él, el bucle irían para siempre y no parar para pronta.

Lo busqué en línea y descubrí que tenía algo que ver con el caché y necesito limpiarlo para que scanf pueda obtener nuevos datos. Así que probé fflush pero no funcionó.

Y vi esto:

int argu,j; 
while(scanf("%d",&argu)!=1){ 
    printf("Please input a number!\n"); 
    while((j=getchar())!='\n' && j != '\n'); 
} 

Luego, cuando las cosas que de entrada como 'ABCD' funcionó bien y se impulsó para mi entrada. Pero cuando ingreso cosas como '12ab', no funcionaría de nuevo.

Entonces, ¿hay alguna manera de verificar la entrada de scanf ("% d", & argu) es realmente un número y solicitar otra entrada si no es así?

EDITAR:

vi las respuestas y resolvió mi problema utilizando while(*eptr != '\n').

Observe que la función fgets realmente lee '\ n' en la matriz y fget no. Así que ten cuidado.

Respuesta

4

Es mejor leer una línea completa, usando fgets(), y luego inspeccionarla, en lugar de intentar analizar "sobre la marcha" desde la secuencia de entrada.

Es más fácil ignorar la entrada no válida, de esa manera.

Utilice fgets() y luego solo strtol() para convertir a un número, lo que hará que sea más fácil ver si hay datos detrás del número.

Por ejemplo:

char line[128]; 

while(fgets(line, sizeof line, stdin) != NULL) 
{ 
    char *eptr = NULL; 
    long v = strtol(line, &eptr, 10); 
    if(eptr == NULL || !isspace(*eptr)) 
    { 
    printf("Invalid input: %s", line); 
    continue; 
    } 
    /* Put desired processing code here. */ 
} 
+0

use el código como fgets (s, 10, stdin)? – Gnijuohz

+0

¡Gracias! No sabía Strtol. ¡Aprendió mucho! – Gnijuohz

+0

lo siento, ¿puedes explicar 'if (eptr == NULL ||! Isspace (* eptr))'? cuando se utiliza el código que se da, se aceptan entradas como '12 34 ', pero no deberían serlo. cuando ingresé '1234' ¿a qué se referiría el eptr y qué tal '12ab' y '12 34 '? – Gnijuohz

1

voy a sugerir a obtener una entrada como una cadena y comprobar los caracteres no numéricos en ella. Si la entrada es válida, convierta cadena a int por sscanf(str,"%d",&i); o error de diplay.

1

Simplemente llame a scanf ("% * [^ \ n] \ n") dentro del bucle, y descartará el "caché".

+0

Lo intenté. No funcionó. – Gnijuohz

+0

Esto se debe a que el comportamiento de 'fflush' no está definido para las secuencias de entrada. Consulte el [estándar de lenguaje C] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf), sección 7.19.5.2, párrafo 2. –

+0

Ambos tienen razón. Espero que la edición, sin embargo, ahora sea correcta (según el estándar). – Spidey

2

Pero cuando ingreso cosas como abcd a él, el ciclo se iría para siempre y no se detendría.

Esto se debe a que si scanf encuentra un carácter que no coincide con el especificador de conversión, lo deja en el flujo de entrada. Básicamente, lo que está sucediendo es que scanf lee el carácter a de la secuencia de entrada, determina que no es una coincidencia válida para el especificador de conversión %d, y luego lo vuelve a enviar al flujo de entrada. La próxima vez en el ciclo hace lo mismo. Y otra vez. Y otra vez. Y otra vez.

fflush no es una buena solución, porque no está definido para trabajar en flujos de entrada.

Para la entrada "12ab", scanf leerá y convertirá "12", dejando "ab" en el flujo de entrada.

La mejor solución es leer todas las entradas como texto, luego convertir a tipos numéricos usando strtol (para valores integrales) y strtod (para valores reales). Por ejemplo:

char input[SIZE]; // assume SIZE is big enough for whatever input we get 
int value; 

if (fgets(input, sizeof input, stdin) != NULL) 
{ 
    char *chk; 
    int tmp = (int) strtol(input, &chk, 10); 
    if (isspace(*chk) || *chk == 0) 
    value = tmp; 
    else 
    printf("%s is not a valid integer string\n", input); 
} 

chk apunta al primer carácter en el flujo de entrada que no es un dígito decimal. Si este carácter no es un espacio en blanco o el terminador 0, entonces la cadena de entrada no era un entero válido. Esto detectará y rechazará entradas como "12ab" y "abcd".

scanf es una buena solución si sabe que su entrada siempre se formará correctamente y se comportará bien. Si existe la posibilidad de que su entrada no sea de buen comportamiento, use fgets y convierta según sea necesario.

0

Llame al scanf("%*[^\n]\n") dentro del lazo. Esto debería ser suficiente para descartar cualquier cosa asociada con la memoria caché.

Cuestiones relacionadas