2010-09-04 11 views
10

jestem zdezorientowany kawałek kodu znalezionego w funkcji uczę:C getchar vs scanf

char GetCommand(void) 
{ 
    char command; 

    do { 
     printf("Enter command (q=quit, n=new, l=list): "); 
     scanf("%c", &command); 
     Flush(); 
    } 
    while ((command != 'q') && (command != 'n') 
      && (command != 'l')); 

    printf("\n----------\n"); 
    return(command); 
} 

void Flush(void) { 
    while (getchar() != '\n') 
     ; 
} 

Co ja nie bardzo rozumiem tutaj jest wykorzystanie funkcji Flush(). Chodzi mi o to, że czytana przeze mnie książka wyjaśnia to, mówiąc, że uniemożliwia to użytkownikowi wprowadzenie więcej niż jednego znaku, a następnie odczytanie tego znaku, gdy zostanie poproszony o wprowadzenie go po raz drugi.

To, czego nie rozumiem, to to, w jaki sposób zapobiega temu. Nic nie robi. Wszystko to jest polecenie while. (Chociaż to prawda ...... co ?????) Nie ma sensu.

Odpowiedz

8

ma efekt uboczny usunięcia następnego znaku z bufora wejściowego. Pętla w Flush odczytuje i odrzuca znaki, aż do końca linii - włącznie z nową linią \n.

Od czasu, gdy scanf ma przeczytać tylko jeden znak (%c), spowoduje to zignorowanie wszystkich pozostałych elementów tej linii wejściowej.

Prawdopodobnie byłoby bardziej jasne, czy scanf było zastąpić

command = getchar(); 

ale to faktycznie ogólnie zły przykład, ponieważ nie radzi sobie dobrze koniec pliku.

Ogólnie najlepiej zapomnieć o scanf; fgets i sscanf działają znacznie lepiej, ponieważ jeden jest odpowiedzialny za uzyskanie danych wejściowych, a drugi za przetwarzanie. scanf (i fscanf) starają się wykonywać zbyt wiele zadań naraz.

+0

OHHHH, nie wiedziałem, że getchar usunął następny znak w buforze wejściowym - to wyjaśnia moje zamieszanie. Dziękuję Ci. – startuprob

2

getchar odczytuje jeden znak ze standardowego wejścia. Jeśli umieścisz go w pętli while, będzie on nadal czytał po jednym znaku, dopóki warunek nie jest fałszywy.

Funkcja Flush robi odczyt, dopóki nie napotka nowej linii (\n). Jest to znak powstały, gdy użytkownik uderza klawiszem Enter.

Tak więc kod, który podałeś, przeczyta jeden znak (nie jestem pewien, dlaczego używa on scanf do tego zamiast po prostu getchar, który byłby szybszy), a następnie odrzuca resztę wejścia, dopóki użytkownik nie wejdzie .

Jeśli było karmić program foobar, zajęłoby się f i wyrzucić oobar w funkcji Flush. Bez wywoływania flush, f może przejść do jednego scanf, a drugi scanf otrzyma pierwszy o.

+0

ja nadal nie rozumiem. Czym dokładnie jest Flush? Wydaje się to równoważne warunkowi warunku if, ale nie komendą. Rozumiem, że scanf pomieści wszystkie dane wejściowe użytkownika, a następnie uruchomi je ponownie, ale w jaki sposób Flush uniemożliwi mu uruchomienie "o" na twoim przykładzie? – startuprob

-1

Poniższy przykład kodu może pomóc, aby dowiedzieć się logiki użyciu Flush():

std::cerr << "Save this data (y for yes/Enter for no)? "; 
int chr = getchar(); 
if(chr != '\n') while(getchar() != '\n'); // Flush() 
if(chr == 'y') 
    std::cerr << "The current data was saved\n";