1. 程式人生 > >談一談getchar()、EOF和Ctrl+D

談一談getchar()、EOF和Ctrl+D

getchar()

  getchar從stdio流中讀字元,getchar有一個int型的返回值.當程式呼叫getchar時.程式就等著使用者按鍵.使用者輸入的字元被存放在鍵盤緩衝區中.直到使用者按回車為止(回車字元也放在緩衝區中).當用戶鍵入回車之後,getchar才開始從stdio流中每次讀入一個字元.getchar函式的返回值是使用者輸入的第一個字元的ASCII碼,如出錯返回-1,且將使用者輸入的字元回顯到螢幕.如使用者在按回車之前輸入了不止一個字元,其他字元會保留在鍵盤快取區中,等待後續getchar呼叫讀取.也就是說,後續的getchar呼叫不會等待使用者按鍵,而直接讀取緩衝區中的字元,直到緩衝區中的字元讀完為後,才等待使用者按鍵。[以上定義來自百度百科]

EOF

  計算機術語,縮寫通常為EOF(End Of File),在作業系統中表示資料源無更多的資料可讀取。資料源通常稱為檔案或串流。
  在C語言中,或更精確地說成C標準函式庫中表示檔案結束符(end of file)。在while迴圈中以EOF作為檔案結束標誌,這種以EOF作為檔案結束標誌的檔案,必須是文字檔案。在文字檔案中,資料都是以字元的ASCII程式碼值的形式存放。我們知道,ASCII程式碼值的範圍是0~255,不可能出現-1,因此可以用EOF作為檔案結束標誌。
  在 UNIX中, EOF表示能從互動式 shell (終端) 送出 Ctrl+D (習慣性標準)。在微軟的 DOS 與 Windows 中能送出 Ctrl+Z。在控制檯要輸入eof的話 按ALT+65535就可以了。[以上概念來自百度百科]
  所以,EOF並不屬於檔案內容的一部分,它只是讀不到更多內容時返回的結束標誌。

看一個例子

1、

#include<stdio.h>
int main()
{
    int    a;
    while((a=getchar())!=EOF)
    {
        printf("a=%d\n",a);
    }
    printf("end:%d\n",a);
    return 0;
}

下面是幾種不同情況下的輸出:
(1)直接按Ctrl+D後,getchar()返回-1,退出
這裡寫圖片描述
(2)輸入一串字元後,再按Ctrl+D
這裡寫圖片描述
所有字元被從緩衝區讀出,與按回車不同的是,回車也會被送入緩衝,但Ctrl+D沒有在緩衝區中體現出來。本來想,如同(1)一樣,Ctrl+D相當於EOF(-1),在輸出所有字元後,getchar()會遇到EOF輸出-1的。
(3)輸入一串字元後,連續按兩次Ctrl+D
這裡寫圖片描述


最後會得到-1,退出迴圈。
既然getchar()是從緩衝區中讀字元,而根據(2)Ctrl+D是沒有放入緩衝區的,為什麼按兩次Ctrl+D就會輸出-1呢?
在網上查到的解釋如下:
  輸入緩衝是行緩衝。當從鍵盤上輸入一串字元並按回車後,這些字元會首先被送到輸入緩衝區中儲存。每當按下回車鍵後,就會檢測輸入緩衝區中是否有了可讀的資料。還會對鍵盤上是否有作為流結束標誌的 Ctrl+Z(windows) 或者 Ctrl+D 鍵 按下作出檢查,其檢查的方式有兩種:阻塞式以及非阻塞式。

  阻塞式檢查方式指的是隻有在回車鍵按下之後才對此前是否有 Ctrl+Z 組合鍵按下進行檢查,非阻塞式樣指的是按下 Ctrl+ D 之後立即響應的方式。如果在按 Ctrl+D 之前已經從鍵盤輸入了字元,則 Ctrl+D的作用就相當於回車(但是回車自己也會進入緩衝),即把這些字元送到輸 入緩衝區供讀取使用,此時Ctrl+D不再起流結束符的作用。如果按 Ctrl+D 之前沒有任何鍵盤輸入,則 Ctrl+D 就是流結束的訊號。

  Windows系統中一般採用阻塞式檢查 Ctrl+Z、Unix/Linux系統下一般採用非阻塞式的檢查 Ctrl+D。樓主是在Windows系統下,因此使用阻塞式的 Ctrl+Z 來標識流的結束。這種阻塞式的方式有一個特點:只有按下回車之後才有可能檢測在此之前是否有Ctrl+Z按下。還有一個特點就是:如果輸入緩衝區中有可讀的資料則不會 檢測Ctrl+Z(因為有要讀的資料,還不能認為到了流的末尾)。還有一點需要知道:Ctrl+Z產生的不是一個普通的ASCII碼值,也就是說它產生的 不是一個字元,所以不會跟其它從鍵盤上輸入的字元一樣能夠存放在輸入緩衝區。

[摘自:http://wenku.baidu.com/view/44e58e1d227916888486d744.html]
2、

#include<stdio.h>
int main()
{
    int    a;
    while((a=getchar())!=EOF)
    {
        sleep(1);
        printf("%d\n",a);
    }
    printf("end:%d\n",a);
    return 0;
}

在緩衝區字元沒讀完的時候按Ctrl+D
這裡寫圖片描述
結果在輸出所有字元後,getchar()返回了-1,說明只要沒有鍵盤輸入,直接Ctrl+D就會起作用。
  我覺得可以這樣理解,每按一次Ctrl+D就表示結束一輪輸入,此時Ctrl+D就告訴getchar()你去讀緩衝區吧。當Ctrl+D之前有字元輸入時,getchar就會正常讀到字元。當直接按Ctrl+D時,緩衝區沒有任何字元送進去,getchar()去讀的時候什麼也沒讀到,就會出錯返回-1。

3、

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int c;
    system("stty raw");
    /* 現在的終端驅動處於一次一個字元模式 */
    while(1)
    {
        c = getchar();
        putchar(c);
    }

    /* 終端驅動處又回到一次一行模式 */
     system("stty cooked");

    return 0;
}

stty raw 可以實現鍵入一個字元立即讀出的效果。此時回車不再起換行作用,按回車後游標會定位到行開頭。