2009-06-16 25 views
7

Zacząłem czytać "The C Programming Language" (K & R) i mam wątpliwości dotyczące funkcji getchar().Gdzie `getchar()` przechowuje dane wejściowe użytkownika?

Na przykład kod:

#include <stdio.h> 

main() 
{ 
    int c; 

    c = getchar(); 
    putchar(c); 
    printf("\n"); 
} 

Typing toomanychars + CTRL + D (EOF) drukuje tylko t. Myślę, że jest to oczekiwane, ponieważ jest to pierwsza postać wprowadzona.

Ale wtedy ten drugi kawałek kodu:

#include <stdio.h> 

main() 
{ 
    int c; 

    while((c = getchar()) != EOF) 
    putchar(c); 
} 

Wpisanie toomanychars + CTRL + D (EOF) drukuje toomanychars.

Moje pytanie brzmi: dlaczego tak się dzieje, gdy mam tylko jedną zmienną char? gdzie są przechowywane pozostałe znaki?

EDIT:

Dzięki wszystkim za odpowiedzi, zaczynam się go teraz ... tylko jeden haczyk:

Pierwsze program wychodzi, gdy dana CTRL + D chwilę drugi drukuje cały ciąg, a następnie czeka na więcej danych wprowadzanych przez użytkownika. Dlaczego czeka na inny ciąg i nie wychodzi tak jak pierwszy?

+1

Twoje drugie podejście przechodzi w pętle do EOF. CTRL + D (w typowych systemach uniksowych) nie spowoduje EOF, chyba że trafisz w linię. Naciśnięcie klawiszy CTRL + D po napisaniu postaci nie powoduje dokładnie EOF – nos

Odpowiedz

4

Traktuje strumień wejściowy jak plik. To tak, jakbyś otworzył plik zawierający tekst "toomanychów" i odczytał lub wypuścił go po jednym znaku naraz.

W pierwszym przykładzie, w przypadku braku pętli while, to tak jakbyś otworzył plik i przeczytał pierwszy znak, a następnie wyprowadził go. Jednak drugi przykład będzie nadal czytał znaki, dopóki nie otrzyma sygnału końca pliku (ctrl+D w twoim przypadku), tak jak gdyby czytał z pliku na dysku.


W odpowiedzi na zaktualizowane pytanie, z jakiego systemu operacyjnego korzystasz? Uruchomiłem go na moim laptopie z systemem Windows XP i działało dobrze. Gdybym wszedł, wydrukowałbym to, co do tej pory zrobiłem, stworzyłem nową linię, a następnie kontynuowałem. (Funkcja getchar() nie powraca, dopóki nie naciśniesz enter, czyli gdy nie ma nic w buforze wejściowym, gdy zostanie wywołana). Po naciśnięciu klawisza CTRL+Z (EOF w systemie Windows) program zostanie zamknięty. Należy zauważyć, że w systemie Windows EOF musi znajdować się w osobnej linii, aby zliczać je jako EOF w wierszu polecenia. Nie wiem, czy to zachowanie jest naśladowane w Linuksie, czy w jakimkolwiek systemie, który może być uruchomiony.

+0

@Carson! EOF musi znajdować się we własnej linii. WIELKIE DZIĘKI! –

+0

Nie ma za co. Walczyłem z tym również, ale rozwiązałem to dzięki SO :) –

9

getchar pobiera pojedynczy znak ze standardowego wejścia, w tym przypadku jest to bufor klawiatury.

W drugim przykładzie, funkcja getchar jest w while pętli, która trwa aż napotka EOF, więc będzie zachować pętli i pobrać znak (i ​​wydrukować znak ekranu) aż do wejścia staje się pusta.

Kolejne połączenia z getchar będą otrzymywać kolejne znaki, które pochodzą z danych wejściowych.

Aha, i nie przejmuj się zadając to pytanie - Byłem zdziwiony, kiedy po raz pierwszy spotkałem się z tym problemem.

+0

Czy zaczyna się zapętlać zaraz po napotkaniu instrukcji 'while (c = getchar())' lub czy oczekuje na naciśnięcie klawisza Enter, a następnie zapętlenie? Z tego co widzę, wykonuje ciało pętli 'while()' dopiero po naciśnięciu klawisza Enter. Moje pytanie brzmi: Czy 'getchar()' powoduje, że 'while()' czeka, aż 'enter' lub' CTRL + D' (w moim systemie) zostanie naciśnięty i zaraz po powrocie do 'while() 'zapętlaj, a następnie wykonuj resztę ciała. – dud3

3

Twój pierwszy program czyta tylko jeden znak, drukuje go i kończy pracę. Twój drugi program ma pętlę. Ciągle czyta znaki po kolei i drukuje je, aż odczyta znak EOF. Tylko jeden znak jest przechowywany w danym momencie.

2

Używana jest tylko zmienna c, aby zawierała każdy znak po jednym na raz.

Po wyświetlony pierwszy Char (t) używając putchar(c), zapomnienia o wartości c przez przypisanie następny znak (o) do zmiennej c, zastępując poprzednią wartość (t).

1

kod jest funkcjonalnym odpowiednikiem

main(){ 
    int c; 
    c = getchar(); 
    while(c != EOF) { 
    putchar(c); 
    c = getchar(); 
    } 
} 

może się okazać ta wersja łatwiejsza do zrozumienia. jedynym powodem umieszczenia przypisania w warunkowym jest uniknięcie dwukrotnego wpisania "c = getchar()".

4

Coś tutaj jest buforowane. na przykład standardowy plik *, który zapisuje dane do pliku może być line.buffered. Kiedy program się kończy (lub napotyka znak nowej linii), taki PLIK * będzie fflush() 'ed, a zobaczysz wynik.

W niektórych przypadkach rzeczywisty terminal, który przeglądasz, może buforować wyjście do nowego wiersza lub do samego terminalu, aby wypróżnić jego bufor, co może mieć miejsce w przypadku, gdy bieżący program pierwszego planu wychodzi, ponieważ chce zaprezentować nowy monit.

Teraz najprawdopodobniej mamy do czynienia z buforowanym wejściem (oprócz wyjścia :-)) Po naciśnięciu klawiszy pojawi się on w oknie terminala. Jednak terminal nie wyśle ​​tych znaków do twojej aplikacji, będzie je buforował, dopóki nie poinstruujesz go, aby był końcowym wejściem z Ctrl + D, a także prawdopodobnie znakiem nowej linii. Oto kolejna wersja się bawić i rozważać o:

int main() { 
    int c; 
    while((c = getchar()) != EOF) { 
    if(c != '\n') 
     putchar(c); 
    } 
    return 0; 
} 

Spróbuj karmienie program zdanie, i naciśnij Enter. I zrób to samo, jeśli komentujesz , jeśli (c! = '\ N') Być może możesz określić, czy twoje wejście, wyjście lub oba są buforowane w jakiś sposób. To staje się bardziej interesujące, jeśli uruchomisz powyższe: ./mytest | ./mytest

(Jako boczny zanotuj, że CTRD + D nie jest znakiem, ani EOF, ale w niektórych systemach spowoduje zamknięcie strumienia wejściowego, co ponownie podniesie EOF do każdego, kto spróbuje odczytać strumień).

0

Dla zaktualizowanego pytania, w pierwszym przykładzie czytana jest tylko jedna postać. Nigdy nie dociera do EOF. Program kończy działanie, ponieważ nie ma nic do zrobienia po wykonaniu instrukcji printf. Po prostu czyta jedną postać. Drukuje to. Stawia w nowej linii. A następnie kończy się, ponieważ nie ma nic więcej do zrobienia. Nie czyta więcej niż jednego znaku.

Podczas gdy w drugim kodzie, getchar i putchar są obecne wewnątrz pętli while.W tym programie program kontynuuje czytanie znaków jeden po drugim (jak to robi się za pomocą pętli), aż sięga się do znaku EOF (^ D). W tym momencie pasuje do c! = EOF i ponieważ warunki nie są spełnione, wychodzi z pętli. Teraz nie ma więcej instrukcji do wykonania. Zatem program kończy się w tym momencie.

Mam nadzieję, że to pomoże.

Powiązane problemy