2010-10-19 14 views
5

Estoy tratando de escribir un programa simple que le pida a un usuario que elija de un menú en un bucle. Utilizo getchar() para obtener la entrada, sin embargo, he notado que cuando ingreso un carácter y presiono 'Enter', el programa crea dos bucles (como si hubiera presionado dos veces) uno como entrada y otro como 'Enter' 'como una entrada.Usando getchar() en c obtiene 'Enter' después de la entrada

¿Cómo puedo solucionar esto?

Gracias.

Respuesta

0

¿Qué tal

#include <stdio.h> 

/*! getline() reads one line from standard input and copies it to line array 
* (but no more than max chars). 
* It does not place the terminating \n in line array. 
* Returns line length, or 0 for empty line, or EOF for end-of-file. 
*/ 
int getline(char line[], int max) 
{ 
    int nch = 0; 
    int c; 
    max = max - 1;   /* leave room for '\0' */ 

    while ((c = getchar()) != EOF) { 
    if (c == '\n') 
     break; 

    if (nch < max) { 
     line[nch] = c; 
     nch = nch + 1; 
    } 
    } 

    if (c == EOF && nch == 0) 
    return EOF; 

    line[nch] = '\0'; 
    return nch; 
} 

Source

+0

No debo usar cadenas o arreglos de caracteres (es un trabajo para un curso) – SnapDragon

3

Es necesario leer sobre canónica frente a la entrada no canónica. Las siguientes preguntas direcciones desbordamiento de pila esto:

canonical-vs-non-canonical-terminal-input

+0

+1 - Puede configurar el terminal en modo raw (no canónico) usando [tcsetattr()] (http: // www. opengroup.org/onlinepubs/000095399/functions/tcsetattr.html) para manipular la estructura ** termios **. – jschmier

2

Añadir un getchar() después de la getchar(): P

+0

Supongo que funcionaría, pero es un anestésico silencioso. – SnapDragon

+0

Eso producirá problemas en algunos casos donde el usuario tendrá que presionar regresar dos veces. – Kaitain

2

La forma más sencilla es filtrar la tecla enter como el valor de retorno de getchar

char c = (char)getchar(); 
if (c != '\n') { 
    ... 
} 
+0

Supongo que querías decir getchar()? si es así, getchar() devuelve int. – Nyan

+0

@Nyan, 'getchar' de hecho devuelve' int', pero es legal asignarlo a 'char' mediante conversiones. Referencia http://www.cplusplus.com/reference/clibrary/cstdio/getchar/ – JaredPar

+1

@Jared: sí, pero char está limitado (por lo general) a 256 valores, y necesita (típicamente) 257 valores para identificar ** TODOS * * caracteres ** Y ** EOF. Es por eso que 'getchar()' devuelve un int – pmg

2

getchar() devuelve el primer carácter en el búfer de entrada y lo elimina del búfer de entrada. Pero otros caracteres están todavía en el búfer de entrada (\n en su ejemplo). Es necesario borrar el buffer de entrada antes de llamar de nuevo getchar():

void clearInputBuffer() // works only if the input buffer is not empty 
{ 
    do 
    { 
     c = getchar(); 
    } while (c != '\n' && c != EOF); 
} 
1

Usted ha contestado clase de su propia pregunta; tienes que tratar con el personaje de nueva línea de alguna manera.

Hay varias opciones. Si sus opciones de menú se contados, puede utilizar scanf() a leer en un valor entero y cambiar sobre la base de que:

printf("Pick an option: "); 
fflush(stdout); 
scanf("%d", &option); 
switch(option) 
{ 
    case 0 : do_something(); break; 
    case 1 : do_something_else(); break; 
    ... 
    default: bad_option(); break; 
} 

La ventaja de esta opción es que el especificador %d conversión omite espacios en blanco,, incluyendo caracteres de nueva línea, por lo que no tiene que preocuparse de que \n no leído obstruya la secuencia de entrada (de hecho, la mayoría de los especificadores de conversión omiten espacios en blanco; %c no lo hace, lo que hace que se comporte como getchar()).

La desventaja de esta opción es que si alguien engatilla un carácter que no es un dígito en su entrada, no se leerá con el especificador de conversión %d, y permanecerá bloqueado en la corriente de entrada hasta una llamada al getchar() o scanf() con un especificador de conversión %s o %c.

Una mejor opción es leer todas las entradas como caracteres strings usando fgets(), luego analizar y validar según sea necesario.

/** 
* Prints a prompt to stdout and reads an input response, writing 
* the input value to option. 
* 
* @param prompt [in] - prompt written to stdout 
* @param option [out] - option entered by user 
* 
* @return - 1 on success, 0 on failure. If return value is 0, then option 
* is not changed. 
*/ 
int getOption(const char *prompt, char *option) 
{ 
    char input[3]; // option char + newline + 0 terminator 
    int result = 0; 

    printf("%s: ", prompt); 
    fflush(stdout); 

    if (fgets(input, sizeof input, stdin)) 
    { 
    /** 
    * Search for a newline character in the input buffer; if it's not 
    * present, then the user entered more characters than the input buffer 
    * can store. Reject the input, and continue to read from stdin until 
    * we see a newline character; that way we don't leave junk in the 
    * input stream to mess up a future read. 
    */ 
    char *newline = strchr(input, '\n'); 
    if (!newline) 
    { 
     printf("Input string is too long and will be rejected\n"); 
     /** 
     * Continue reading from stdin until we find the newline 
     * character 
     */ 
     while (!newline && fgets(input, sizeof input, stdin)) 
     newline = strchr(input, '\n'); 
    } 
    else 
    { 
     *option = input[0]; 
     result = 1; 
    } 
    } 
    else 
    printf("Received error or EOF on read\n"); 

    return result; 
} 

Sí, eso es mucho trabajo por leer en una opción de menú estúpida, y esa es la versión simple. Bienvenido al maravilloso mundo del procesamiento de entrada interactiva en C.

Cuestiones relacionadas