2012-09-29 31 views
7

Tengo dificultades para entender getchar(). En el siguiente programa getchar funciona como se esperaba:getchar no se detiene al usar scanf

#include <stdio.h> 


int main() 
{ 
    printf("Type Enter to continue..."); 
    getchar(); 
    return 0; 
} 

Sin embargo, en el siguiente programa, getchar no crea un retraso y termina el programa:

#include <stdio.h> 

int main() 
{ 
    char command[100]; 
    scanf("%s", command); 
    printf("Type Enter to continue..."); 
    getchar(); 
    return 0; 
} 

He la siguiente solución weired, que trabaja , pero no entiendo por qué:

#include <stdio.h> 

int main() 
{ 
    char command[100]; 
    int i; 
    scanf("%s", command); 
    printf("Type Enter to continue..."); 
    while (getchar() != '\n') { 
     i=0; 
    } 
    getchar(); 
    return 0;  
} 

Así que mis preguntas son: 1. ¿Qué
es scanf haciendo? ¿Por qué scanf hace esto?
2. ¿Por qué funciona mi trabajo?
3. ¿Qué es una buena manera de emular el siguiente código Python:

raw_input("Type Enter to continue") 

Respuesta

9

La entrada sólo se envía al programa después de que ha escrito una nueva línea, pero

scanf("%s", command); 

deja el salto de línea en el buffer de entrada, ya que el formato %s(1) se detiene cuando el primer carácter en blanco se encuentra después de un espacio no en blanco, getchar() y luego devuelve inmediatamente esa nueva línea y no necesita esperar más entradas.

Su solución temporal funciona porque borra la nueva línea del búfer de entrada antes de llamar al getchar() una vez más.

Para emular el comportamiento, borrar el buffer de entrada antes de imprimir el mensaje,

scanf("%s", command); 
int c; 
do { 
    c = getchar(); 
}while(c != '\n' && c != EOF); 
if (c == EOF) { 
    // input stream ended, do something about it, exit perhaps 
} else { 
    printf("Type Enter to continue\n"); 
    getchar(); 
} 

(1) cuenta que el uso %s en scanf es muy inseguro, se debe restringir la entrada a lo que su memoria intermedia puede mantener con un ancho de campo, scanf("%99s", command) leerá como máximo 99 (sizeof(command) - 1)) caracteres en command, dejando espacio para el 0-terminador.

+0

+1 Me pregunto si un EOF es likley cuando 'stdin' permanece unido a la consola? Sin duda, puede ocurrir si 'stdin' se redirige de un archivo, lo que hace que mi respuesta sea menos robusta. – Clifford

+0

No es probable, pero por supuesto uno puede escribir Ctrl-D (Ctr-Z en Windows, iirc) para cerrar la secuencia. Gracias por la edición, por cierto. –

-2

después de tomar la entrada de comando lavar el stdin.

fflush(stdin); 

pero enjuagar un flujo de entrada da como resultado un comportamiento indefinido (aunque biblioteca C de Microsoft define el comportamiento como una extensión).

+2

fflush() no está definido para flujos de entrada. – Clifford

+1

-1: aplicar 'fflush()' a una secuencia de entrada (o una secuencia de entrada/salida para la cual se ingresó la última operación) es uno de los pocos ejemplos específicos de Comportamiento no definido especificado por [Norma C] (http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1570.pdf). – pmg

+0

Tenga en cuenta que si bien esto funciona con la biblioteca C de Microsoft, ciertamente no lo hace con la biblioteca C de GNU. Evitar. – Clifford

2

El espacio en blanco es un delimitador para el especificador de formato de 5y3% s, y nueva línea se considera espacio en blanco, por lo que permanece almacenado en el búfer. La entrada de la consola normalmente está orientada a la línea, por lo que una llamada posterior a getchar() regresará inmediatamente porque una 'línea' permanece almacenada.

scanf("%s", command); 
while(getchar() != '\n'){ /* flush to end of input line */ } 

Igualmente si utiliza getchar() o% c para obtener un solo carácter que normalmente tienen que limpiar la línea, pero en este caso el carácter introducido puede ser él mismo una nueva línea lo que necesita un poco diferente solución:

scanf("%c", ch); 
while(ch != '\n' && getchar() != '\n'){ /* flush to end of input line */ } 

de manera similar para getchar():

ch = getchar(); 
while(ch != '\n' && getchar() != '\n'){ /* flush to end of input line */ } 

lo más sensato que hacer, por supuesto, es envolver estas soluciones en funciones de entrada especializadas autónomas que puede reutilizar y también usar como lugar para poner validación de entrada común y código de comprobación de errores (como en la respuesta de Daniel Fischer que comprueba sensiblemente EOF; normalmente, debería evitar tener que duplicar esos controles y errores) manejo en todas partes).

2

Prefiero usar primero fgets y luego usar sscanf para analizar la entrada. He estado haciendo esto durante mucho tiempo y el comportamiento ha sido más predecible que con el scanf.

0

Bueno, tengo algo más fácil: agregue otro getchar() ... problema resuelto !!

+0

que no necesariamente resuelve el problema, aún puede tener más de un byte en el búfer y 'getchar()' regresará inmediatamente. – Pablo

Cuestiones relacionadas