2012-03-05 22 views
18

tengo este bloque de código (funciones omitido como la lógica es parte de una asignación de la preparación):C: de múltiples scanf, cuando entro en un valor para uno scanf se salta la segunda scanf

#include <stdio.h> 

int main() 
{ 
    char c = 'q'; 
    int size; 

    printf("\nShape (l/s/t):"); 
    scanf("%c",&c); 

    printf("Length:"); 
    scanf("%d",&size); 

    while(c!='q') 
    { 
     switch(c) 
     { 
      case 'l': line(size); break; 
      case 's': square(size); break; 
      case 't': triangle(size); break; 
     } 


     printf("\nShape (l/s/t):"); 
     scanf("%c",&c); 

     printf("\nLength:"); 
     scanf("%d",&size); 
    } 

    return 0; 
} 

El Los primeros dos Scanf funcionan genial, no hay problema una vez que entramos en el ciclo while, tengo un problema donde, cuando se supone que se te pide que ingreses un nuevo carácter de forma, en lugar de eso salta al printf de Longitud y espera a recibir entrada de allí para un char, luego un decimal en la siguiente iteración del ciclo.

Preloop iteración:

Scanf: Forma. Funciona bien
Scanf: Longitud. No hay problema

Loop 1.

Scanf: Forma. Omite este
Scanf: longitud. Problema, este scanf se asigna a la forma char.

Loop 2
Scanf: Shape. Omite este
Scanf: longitud. Problema, este scanf se asigna al tamaño int ahora.

¿Por qué está haciendo esto?

Respuesta

34

scanf("%c") lee el carácter de nueva línea de la tecla ENTER.

Al escribir digamos 15, escribe un 1, un 5 y luego pulsa la tecla de ENTER. Entonces ahora hay tres caracteres en el búfer de entrada. scanf("%d") lee 1 y 5, interpretándolos como el número 15, pero el carácter de nueva línea todavía está en el búfer de entrada. El scanf("%c") leerá inmediatamente este carácter de nueva línea y el programa pasará al siguiente scanf("%d"), y esperará a que ingrese un número.

El consejo habitual es leer líneas enteras de entrada con fgets, e interpretar el contenido de cada línea en un paso separado. Una solución más simple a su problema inmediato es agregar getchar() después de cada scanf("%d").

+0

Eso fue impresionante !! Gracias^_^ – noMAD

+0

Acabas de salvarme la vida. –

+2

El 'scanf ("% d "); la combinación getchar(); 'falla si el usuario ingresa accidentalmente un espacio (u otra basura) después del número. – ilkkachu

1

Cuando escribe la forma y ENTER, la forma es consumida por el primer scanf, pero el ENTER no! El segundo scanf espera un número así, se omite el ENTER porque se considera un espacio en blanco, y el scanf espera una entrada válida (un número) que, de nuevo, finaliza con ENTER. Bueno, el número se consume, pero el ENTER no lo está, por lo que el primer scanf dentro del tiempo lo usa y se omite su mensaje de forma ... este proceso se repite. Debe agregar otro% c en los scanfs para manejar la tecla ENTER. ¡Espero que esto ayude!

1

El carácter '\n' todavía queda en el flujo de entrada después de que se completó la primera llamada a scanf, por lo que la segunda llamada a scanf() lo lee. Use getchar().

5

Utilice la función

void fflushstdin(void) 
{ 
    int c; 
    while((c = fgetc(stdin)) != EOF && c != '\n'); 
} 

a limpiar su memoria intermedia de entrada.

+0

Esta es una buena función. Para la legibilidad, pondría la declaración nula (el único punto y coma) en una línea separada. –

+1

También me gusta esto, pero creo que sería mejor * no * usar la palabra "flush", ya que tiene una definición establecida dentro del estándar que contradice el uso aquí. Tal vez 'seek_to_next_line' sería un nombre más descriptivo? – Sebivor

18

El problema básico es que scanf() deja la nueva línea después del número en el búfer, y luego la lee con %c en la próxima pasada. En realidad, esta es una buena demostración de por qué no uso scanf(); Utilizo un lector de línea (fgets(), por ejemplo) y sscanf(). Es más fácil de controlar.

Probablemente pueda rescatarlo utilizando " %c" en lugar de "%c" para la cadena de formato. El espacio en blanco provoca scanf() para omitir el espacio en blanco (incluidas las líneas nuevas) antes de leer el carácter.

Pero será más fácil en el largo plazo a renunciar a scanf() y fscanf() y utilizar fgets() o equivalente, más sscanf(). Aparte de todo lo demás, el informe de errores es mucho más fácil cuando se tiene que trabajar con la cadena completa, no con los moldes que quedan scanf() después de que falla.

También debe, siempre, verificar que obtenga un valor convertido de scanf(). La entrada falla — de forma rutinaria y horrible. No dejes que arruine tu programa porque no lo has verificado.

4

Intenta agregar un espacio en el escaneo.

scanf(" %d", &var); 
// ^
// there 

Esto hará que scanf() para descartar todos los espacios en blanco antes de hacer coincidir un número entero.

+1

Según [sección 7.21.6.2p8] (http://port70.net/~nsz/c/c11/n1570.html#7.21.6.2p8), 'scanf' * normalmente * descarta todos los espacios en blanco antes de hacer coincidir un entero , de todos modos, hacer que el espacio en blanco de este formato no tenga sentido: * "Los caracteres de entrada de espacio en blanco (especificados por la función isspace) se saltan, a menos que la especificación incluya un especificador [, c, o n" * – Sebivor

+0

Esto no lo hará arregla el problema '% d' ya omite los caracteres principales de espacios en blanco. –

1

También puede utilizar scanf("%c%*c", &c); leer dos caracteres e ignorar el último (en este caso, '\ n')