1.getchar()是標準I/O標準庫里的庫函數
原型是int getchar(void)-----------它沒有參數,原因是因為它是從stdin標準輸入流中讀入一個字符的函數,已經有了默認的流參數stdin了。其返回值是一個整型數,是用來表示字符用的。
輸入輸出往往都是內存與外設之間的數據來往,但是,內存的運行效率比外設的運行效率那要大得多,比如,從內存寫一個字符到磁盤上,內存很快地傳出字符數據,供給磁盤存儲,磁盤花了很多的時間來存儲,在這段存儲的時間里,我們寶貴的內存只能干等著磁盤做完存儲操作來傳遞下一個字符,這樣的做法是非常浪費內存的。所以計算機牛人們就設計出了緩沖的概念,來緩和內存與外設之間速度不匹配的問題。這意味著程序的輸入輸出已經不是跟外設直接打交道了,而是從一塊被稱為緩沖區(qū)的內存區(qū)域來回復制數據。就C程序而言,所有的IO操作只是簡單地從程序移進移出字節(jié),這種字節(jié)流即為流。
回到getchar()函數中來,我們以下面一個程序為例。
#include<stdio.h>
void main()
{
char ch1 = getchar(); //從輸入流中讀取一個字符
char ch2 = getchar(); //從緩沖區(qū)中讀取第二個字符
printf("%c\n", ch1);
printf("%c\n", ch2);
}
第一種情況:如果你的輸入只有一個字符,那么肯定的,ch1的值便是這個字符,那么ch2呢?在這里別忘了,你輸完前一個字符后是通過什么結束輸入的?是的,是Enter,Enter肯定會說:“人家可也是個正正經經的字符啊,不要不把無字幕的字符不當字符啊!”是的,在這里是向緩沖區(qū)中輸入了兩個字符,而getchar()是做什么呢?前面提到了,程序可不是直接跟外設打交道的,而是跟緩沖區(qū)打交道的,所以,getchar()庫函數是從緩沖區(qū)中讀取字符而不是從鍵盤讀取字符的,所以,你已經向緩沖區(qū)中輸入了兩個字符夠上面程序中兩個getchar()讀的了??梢杂孟旅娴某绦驕y試一下這種效果。
如果在第一次輸入的時候不是簡單的輸入一個字符和一個換行,而是輸入了一大堆字符,那么,這些字符將全部送往stdin流的緩沖區(qū)中,后面的所有包括getchar()的將從stdin流中讀入數據的庫函數將從這個緩沖區(qū)中讀入數據,直道緩沖區(qū)再次為空后,才提示輸入設備準備輸入數據。
一、getchar的兩點總結:
1.getchar是以行為單位進行存取的。
當用getchar進行輸入時,如果輸入的第一個字符為有效字符(即輸入是文件結束符EOF,Windows下為組合鍵Ctrl+Z, Unix/Linux下為組合鍵Ctrl+D),那么只有當最后一個輸入字符為換行符'\n'(也可以說是EOF)時, getchar才會停止執(zhí)行,整個程序將會往下執(zhí)行。譬如下面程序段: 可以清空緩沖區(qū)
while((c = getchar()) != EOF){
putchar(c);
}
執(zhí)行程序,輸入:abc,然后回車。則程序就會去執(zhí)行puchar(c),然后輸出abc,這個地方不要忘了,系統(tǒng)輸出的還有一個回車。然后可以繼續(xù)輸入,再次遇到換行符的時候,程序又會把那一行的輸入的字符輸出在終端上。
對于getchar,肯定很多初學的朋友會問,getchar不是以字符為單位讀取的嗎?那么,既然我輸入了第一個字符a,肯定滿足while循環(huán)(c = getchar()) != EOF的條件阿,那么應該執(zhí)行putchar(c)在終端輸出一個字符a。不錯,我在用getchar的時候也是一直這么想的,但是程序就偏偏不著樣執(zhí) 行,而是必需讀到一個換行符或者文件結束符EOF才進行一次輸出。
對這個問題的一個解釋是,在大師編寫C的時候,當時并沒有所謂終端輸入的概念,所有的輸入實際上都是按照文件進行讀取的,文件中一般都是以行為單位的。因 此,只有遇到換行符,那么程序會認為輸入結束,然后采取執(zhí)行程序的其他部分。同時,輸入是按照文件的方式存取的,那么要結束一個文件的輸入就需用到EOF (Enf Of File). 這也就是為什么getchar結束輸入退出時要用EOF的原因。
2.getchar()的返回值一般情況下是字符,但也可能是負值,即返回EOF。
這里要強調的一點就是,getchar函數通常返回終端所輸入的字符,這些字符系統(tǒng)中對應的ASCII值都是非負的。因此,很多時候,我們會寫這樣的兩行代碼:
char c;
c = getchar();
這樣就很有可能出現問題。因為getchar函數除了返回終端輸入的字符外,在遇到Ctrl+D(Linux下)即文件結束符EOF時,getchar ()的返回EOF,這個EOF在函數庫里一般定義為-1。因此,在這種情況下,getchar函數返回一個負值,把一個負值賦給一個char型的變量是不 正確的。為了能夠讓所定義的變量能夠包含getchar函數返回的所有可能的值,正確的定義方法如下(K&R C中特別提到了這個問題):
int c;
c = getchar();
二、EOF的兩點總結(主要指普通終端中的EOF)
1.EOF作為文件結束符時的情況:
EOF雖然是文件結束符,但并不是在任何情況下輸入Ctrl+D(Windows下Ctrl+Z)都能夠實現文件結束的功能,只有在下列的條件下,才作為文件結束符。
(1)遇到getcahr函數執(zhí)行時,要輸入第一個字符時就直接輸入Ctrl+D,就可以跳出getchar(),去執(zhí)行程序的其他部分;
(2)在前面輸入的字符為換行符時,接著輸入Ctrl+D;
(3)在前面有字符輸入且不為換行符時,要連著輸入兩次Ctrl+D,這時第二次輸入的Ctrl+D起到文件結束符的功能,至于第一次的Ctrl+D的作用將在下面介紹。
其實,這三種情況都可以總結為只有在getchar()提示新的一次輸入時,直接輸入Ctrl+D才相當于文件結束符。
2.EOF作為行結束符時的情況,這時候輸入Ctrl+D并不能結束getchar(),而只能引發(fā)getchar()提示下一輪的輸入。
這種情況主要是在進行getchar()新的一行輸入時,當輸入了若干字符(不能包含換行符)之后,直接輸入Ctrl+D,此時的Ctrl+D并不是文件 結束符,而只是相當于換行符的功能,即結束當前的輸入。以上面的代碼段為例,如果執(zhí)行時輸入abc,然后Ctrl+D,程序輸出結果為:
abcabc
注意:第一組abc為從終端輸入的,然后輸入Ctrl+D,就輸出第二組abc,同時光標停在第二組字符的c后面,然后可以進行新一次的輸入。這時如果再次輸入Ctrl+D,則起到了文件結束符的作用,結束getchar()。
如果輸入abc之后,然后回車,輸入換行符的話,則終端顯示為:
abc //第一行,帶回車
abc //第二行
//第三行
順便提一下輸出庫函數。輸出庫函數的效果也只是將程序中的內容輸出到緩沖區(qū)中,然后再刷新的時候輸出到外設上,如果在輸出的時候輸出輸出流stdout緩沖區(qū)中已經有了數據,那么輸出的是已經有的內容,而不一定是你輸出的內容。這是由緩沖區(qū)刷新的時間控制的,刷新的操作是根據具體的編譯器來決定的,一般調用fflush(stdout)來刷新一下stdout緩沖區(qū)。