2009-09-16 23 views
6

¿Por qué mi profesor usa dos getchar(); al final de nuestros tutoriales del programa C?¿Por qué mi profesor usa dos getchar() ;?

¿Y cuál es la "mejor manera" para esto?

+63

¿Lo has preguntado en/después de la clase? – crashmstr

+6

Ve a preguntarle; tal vez él está tratando de ser inteligente. –

+4

Creo que una mejor manera sería un programa de modificación automática que inserta tantas llamadas al getchar hasta el final del programa, ya que hay caracteres no leídos en el búfer de entrada. Sabes, a veces dos tampoco son suficientes. ;) – UncleBens

Respuesta

15

La mejor manera es no agregar ningún código para intentar mantener abierta la ventana de la consola: inicie su programa directamente desde la ventana de la consola.

Si debe iniciar su programa desde el IDE y desea que el programa no termine antes de que el usuario presione Enter, debería hacerlo uno solo getchar().

La segunda mejor manera de hacer que el programa finalice después de que el usuario presiona una tecla, es asegurarse siempre de que no haya entradas pendientes y usar una sola getchar().

La razón de su profesor utiliza 2 getchar(), supongo, es que ya hay un carácter en el buffer de entrada de las entradas anteriores. Para consumir todos los caracteres de las entradas, hasta e incluyendo el ENTER, esto es lo normal:

int ch; 
/* ... */ 
printf("Press Enter"); fflush(stdout); 
while ((ch = getchar()) != '\n' && ch != EOF) /* void */; 
+0

es esta sintaxis para C o C++? – HollerTrain

+5

Este es un idioma C estándar. Creo que también funciona en C++, pero puede no ser idiomático en ese idioma. – pmg

+0

[Veganaize] (https://stackoverflow.com/users/5039027/veganaize) sugirió 'puts()' en lugar de 'printf(); fflush (stdout); '.El motivo de mi elección es mantener el cursor parpadeante en la misma línea que el texto "Presionar ENTER". Tenga en cuenta que 'puts()' agrega automáticamente una nueva línea haciendo que la llamada 'fflush()' sea redundante. – pmg

23

Está esperando la entrada del usuario para que pueda ver la salida del programa; de lo contrario, simplemente se completará y la salida no será visible (dependiendo del sistema operativo). Sácalo y pruébalo.

+26

También recuerde esta respuesta a medida que avanza en sus estudios: "Quítelo y pruébelo" es una herramienta muy útil en lo que hacemos. No tengas miedo de jugar a veces. – Steven

0

getchar(); al final del programa crea una situación "Presione cualquier tecla para continuar". Supongo que le gusta presionar cualquier tecla dos veces.

+0

No creo, que le gusta presionar dos veces las teclas, creo que se dio cuenta de que a veces no funciona cuando pone solo un getchar(). Ver mi ejemplo. – Lucas

1

Probablemente para mantener la ventana de salida abierta cuando ejecuta el programa desde el IDE.

... por qué hay dos más allá de mi.

3

para pausar el programa de línea de comandos (probablemente). él está usando dos, porque usar uno no funcionó y probablemente no sabe por qué ...

encuentra una mejor solución para hacer esto (y no std :: cin) y serás el héroe del día.

+0

sí, estoy tratando de encontrar esta solución :) dijo que lo cubriría más adelante en el semestre, pero quiero averiguarlo ahora. – HollerTrain

+0

bueno, en primer lugar, está haciendo el 'truco' porque el búfer (que usa getchar()) ya podría contener un char, omitiendo el primer getchar() (o al menos no hacer una pausa en él). quizás podrías vaciar el buffer primero? o use un método diferente para pausar (¡no System ("sleep")!) – Jake

0

Para recuperar el "\ n" restante del búfer para que la aplicación se cierre.

+0

¿No se cerraría también la aplicación, si todavía había algo en el búfer? – Lucas

+0

¿No es por eso que lo hace dos veces? – Jake

16

Quiere que la consola permanezca abierta y esperar a que el usuario presione una tecla. Creo que recordar eso depende de lo que suceda en el programa de tu profesor sobre el "getchar()". Todavía puede haber algo en el búfer, por lo que agregó un segundo "getchar()". No es exactamente la manera más elegante de resolver el problema.

Editar: Aquí hay un pequeño ejemplo. Todavía queda un "\ n" en el búfer de "scanf()". Si agrega un segundo "getchar()", obtiene el resultado esperado. Tienes que lavar el buffer antes del "getchar()".

#include <stdio.h> 

main() 
{ 
int input; 
scanf("%d", &input); 
printf("The input is %d\n", input); 
getchar(); 
return 0; 
} 

Editar 2: Aquí es una solución tomada de here.

int c; 
printf("Press ENTER to continue... "); 
fflush(stdout); 
do c = getchar(); while ((c != '\n') && (c != EOF)); 
+0

Y pensé que todos los demás ya lo saben, usted parece ser el único aquí que entiende el problema del búfer. – abyx

+0

@abyx Creo que el problema del búfer es bastante conocido, pero ¿no debería ser recomendable enjuagar el búfer? O tal vez incluso el sistema ("PAUSA") ;? El sistema – Agos

+3

("PAUSE") depende de la plataforma y funciona solo bajo Windows. – Lucas

-3

Debido a un golpe de la tecla "enter" genera dos caracteres en Windows, consulte wikipedia. Por lo menos es utilizado también, hace mucho tiempo en una galaxia muy muy lejana ...

+1

No, eso no tiene nada que ver con eso. –

+0

stdin se abre como una secuencia de "texto" (en lugar de binaria), lo que significa que solo lee "\ n" cuando se pulsa la tecla Intro. – Artelius

+0

- E incluso si al presionar enter generara dos caracteres, solo necesitaría esperar el primero antes de terminar el programa. – Artelius

5

La razón una gran cantidad de principiantes consideró necesario poner dos getch llamadas en su código es que una sola llamada a menudo no lo hace trabajo.

El motivo es que getch recupera la siguiente entrada de teclado de la cola de entrada. Desafortunadamente, esta cola se llena cada vez que el usuario presiona las teclas del teclado, incluso si la aplicación no está esperando la entrada en ese momento (si no está leyendo toda la entrada, consulte la respuesta de Lulu para ver un ejemplo). Como consecuencia, getch obtendrá un carácter de la cola de entrada sin esperando la siguiente tecla presionada, que es lo que realmente quiere el programador.

Por supuesto, esta "solución" seguirá fallando en muchos casos, cuando hay más de un solo carácter en la cola del teclado. Una mejor solución es vaciar esa cola y luego solicitar el siguiente carácter.Desafortunadamente, no tengo una forma de plataforma independiente para hacer esto en C/C++, que yo sepa. La forma convencional de hacer esto en C++ (lo siento, mi C es limitado) tiene el siguiente aspecto:

std::cin.ignore(std::cin.rdbuf()->in_avail()); 

Esto simplemente ignora todas las entradas disponibles, eliminar eficazmente la cola de entrada. Desafortunadamente, este código no siempre funciona, tampoco (por razones muy extrañas).

+0

¿Qué tal aquí para enrojecer? void clearStdin() { int c; while ((c = getchar())! = EOF && c! = '\ N'); }; – Christian

+0

@Christian Es muy posible que esto funcione, pero supongo que podría fallar por la misma razón que el código C++ anterior a veces falla. –

+0

La pregunta es sobre 'getchar', no' getch' –

5

¿Por qué mi prof utilizando dos getchar(); al final de nuestros tutoriales del programa C?

suponiendo que tiene algo así como

int main (void) 
{ 
    int  input; 

    scanf ("%d", &input); 

    printf ("The input is %d.\n", input); 

    getchar(); 
    getchar(); 

    return 0; 
} 

dos porque scanf no volverá hasta después de introducir una es presionado, pero no será el '\ n' de la entrada y cualquier otro carácter que tiene ingresado en el buffer de entrada.

lo tanto, si se ejecuta la entrada de arriba y 1234Introduzca, el programa hará una pausa después de la impresión The input is 1234. hasta entonces pulsa Enter nuevo. El primer getchar lee el '\n' asociado con el primer Ingrese. Si ingresa algo más, como 1234EspacioIngrese, el programa no pausará, ya que el primer getchar leerá el espacio. Dos getchar s pueden no ser suficientes, y ha intercalado el código para imprimir la respuesta en el código para manejar la entrada.

¿Y cuál es la "mejor manera" para esto?

Hay varias formas estándar de lectura de entrada en C. También hay plataforma de formas específicas de hacer caso omiso de texto en el buffer de entrada, pero no deberían tener que hacer eso si se utiliza fgets para leer una línea de entrada en lugar de scanf para leer alguna entrada de la última línea ingresada.

fgets (leer la entrada hasta '\ n' o al final del archivo), seguido de sscanf (analizar una cadena de entrada) está a salvo de las saturaciones del búfer, y absorberá cualquier entrada y la línea de terminación adicional '\ n':

#include <stdio.h> 

int main (void) 
{ 
    int  input; 
    char buf[16] = ""; 

    fgets (buf, sizeof buf, stdin); 

    sscanf (buf, "%d", &input); 

    printf ("The input is %d.\n", input); 

    fflush (stdout); 

    getchar(); 

    return 0; 
} 

Flushing stdout después de la printf normalmente no es necesario para el terminal IO, pero puede ser si está tubería en un disco (normalmente cuando se está acumulando un programa estrellarse perderá el bit más interesante justo antes el choque si no se descarga).

Debido fgets lee hasta e incluyendo el extremo de la línea, no hay caracteres que quedan en la memoria intermedia de modo que sólo necesita un getchar, y la entrada de algo torpe como 1234espacioIntroduzca no causa la programa para terminar sin pausar.

Sin embargo, la mayoría de las veces no necesita esperar después de ejecutar una aplicación de consola: en Linux u otros sistemas Unix normalmente tiene una consola abierta y ejecuta el programa allí, luego de lo cual el control vuelve al shell. En Windows, entornos de desarrollo como Visual Studio normalmente run the program and pause que usar algo como:

"C:\WINDOWS\system32\cmd.exe" /c ""...\ConsoleApplication1.exe" & pause" 

O puede abrir cmd.exe y ejecutarlo desde allí, o se puede ejecutar con un acceso directo .pif y establecer la casilla de verificación se no cerrar la consola al salir, o puede crear un archivo por lotes que la ejecute y haga una pausa.

Solo necesita hacer que el programa se detenga solo si está en Windows y está utilizando un depurador para ejecutarlo y no ha establecido ningún punto de interrupción.

1

Es una solución ingenua para el problema de la entrada del buffer no utilizado. Tu profesor reconoce el problema, pero parece que no sabe cómo resolverlo correctamente.

Si utiliza la entrada formateada, solo se utilizan los caracteres ingresados ​​que coincidan con el especificador de formato. Así que si, por ejemplo, la última entrada solicitó un entero decimal utilizando% d, es posible introducir en la consola:

123<newline>

La entrada formateada consumirá el "123", dejando el <newline> tamponada. Una entrada no formateada como getchar() consumirá eso y regresará inmediatamente. Como esto no es lo que quieres, tu profesor ha utilizado "simplemente agrega otro getchar() kludge". Esto funciona solo si el usuario ingresa la entrada esperada. Una mecanógrafa hamfisted podría escribir:

123w<newline>

Ahora la primera getchar() obtiene la 'w', la segunda obtiene el <newline>, y el programa termina antes de lo encaminó a, y en un entorno GUI, si el proceso de terminación posee la ventana en la que se está ejecutando, luego el sistema operativo lo cierra.

Una solución más robusta es para llamar repetidamente getchar() hasta que el <newline> se encuentra:

while(getchar() != '\n') { /*do nothing*/} ; 
getchar() ; /* wait */ 

Por supuesto, si la entrada anterior era un personaje, es necesario comprobar que no era ya un <newline>:

while(ch != '\n' && getchar() != '\n') { /*do nothing*/} ; 
getchar() ; /* wait */ 

En lugar de poner el bucle de enjuague al final justo antes de la llamada de entrada de "espera", es mejor realizar la descarga del búfer después de cada entrada que lo requiera. Esto es porque es donde sabes que lo necesitas y cómo debe codificarse. Tiendo a escribir funciones de envoltura para los tipos de entrada que necesito.

+0

La explicación es pertinente, pero sus soluciones no son * robustas *: también debe verificar para 'EOF', de lo contrario, un final prematuro de archivo causará un bucle infinito. – chqrlie

+0

@chqrlie: ¡Solo 8 años para detectar eso! – Clifford