2010-10-19 2 views
5

Sto provando a scrivere un semplice programma che chiede a un utente di scegliere da un menu in un ciclo. Io uso getchar() per ottenere l'input, tuttavia ho notato che quando inserisco un carattere e premo 'Invio' il programma crea due loop (come se avessi premuto due volte) uno come input e un altro per 'Invio 'come input.Utilizzando getchar() su c si ottiene 'Invio' dopo l'immissione

Come posso risolvere questo problema?

Grazie.

risposta

0

Come su

#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

non devo usare stringa o array di char (il suo un lavoro per un corso) – SnapDragon

3

Hai bisogno di leggere su ingresso canonica vs. non canonico. I seguenti indirizzi Stack Overflow domanda a questo:

canonical-vs-non-canonical-terminal-input

+0

+1 - È possibile impostare il terminale in modalità raw (non canonica) utilizzando [tcsetattr()] (http: // www. opengroup.org/onlinepubs/000095399/functions/tcsetattr.html) per manipolare la struttura ** termios **. – jschmier

2

Aggiungi un getchar() dopo la getchar(): P

+0

Immagino che funzionerebbe, ma è un anestetico silenzioso. – SnapDragon

+0

Ciò causerà problemi in alcuni casi in cui l'utente si troverà a dover premere il tasto Invio due volte. – Kaitain

2

Il modo più semplice è quello di filtrare il tasto invio come valore restituito da getchar

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

Immagino tu intendessi getchar()? se è così, getchar() restituisce int. – Nyan

+0

@Nyan, 'getchar' restituisce effettivamente' int', ma è legale assegnare a 'char' tramite conversioni. Riferimento http://www.cplusplus.com/reference/clibrary/cstdio/getchar/ – JaredPar

+1

@ Jared: sì, ma char è limitato a (tipicamente) 256 valori e sono necessari (tipicamente) 257 valori per identificare ** TUTTI * * caratteri ** E ** EOF. Ecco perché 'getchar()' restituisce un int – pmg

2

getchar() restituisce il primo carattere nel buffer di input e lo rimuove dal buffer di input. Ma altri caratteri sono ancora nel buffer di input (\n nell'esempio). È necessario cancellare il buffer di ingresso prima di chiamare getchar() ancora:

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

Hai tipo di risposto alla tua domanda; devi affrontare il carattere newline in qualche modo.

Ci sono diverse opzioni. Se le opzioni di menu sono numerate, è possibile utilizzare scanf() per leggere in un valore intero e passare sulla base di tale:

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; 
} 

Il vantaggio di questa opzione è che l'identificatore %d conversione salta sopra un qualsiasi spazio, tra cui caratteri di nuova riga, in modo da non doversi preoccupare di qualsiasi lettura non letta \n che intasano il flusso di input (in effetti, la maggior parte degli specificatori di conversione salta gli spazi bianchi iniziali, %c no, il che si comporta molto come getchar()).

Lo svantaggio di questa opzione è che se qualcuno fat-dita un carattere non cifre nella loro ingresso, non verrà letto con l'identificatore %d di conversione, e rimarrà bloccato nel flusso di input fino a quando una chiamata a getchar() oppure scanf() con uno specificatore di conversione %s o %c.

Un'opzione migliore è quella di leggere tutti gli input come carattere stringhe utilizzando fgets(), quindi analizzare e convalidare se necessario.

/** 
* 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ì, è un sacco di lavoro da leggere in un'opzione di menu stupido, e questa è la versione semplice. Benvenuti nel meraviglioso mondo dell'elaborazione dell'input interattivo in C.