IO___C基礎部分(EOF, 斷行符號換行,getchar(), getch())

來源:互聯網
上載者:User
EOF

     EOF(End Of File)是檔案讀取操作所返回的一個狀態,它並不是從檔案中讀取到的值,而是檔案讀取函數在讀取到檔案末尾或者不能再往下讀取時的一個傳回值。該傳回值一般是-1,這也是大多數系統中為EOF宏定義的值。正因為這個特殊的傳回值,使得譬如getch(),getchar(),等函數的傳回值是int而不是char,這一點後面會講到。EOF一般可以通過傳回值,eof()或者feof()函數來檢測。在Windows控制台介面下,可以通過
ctrl+z來實現類比檔案末尾。      \r\n     即斷行符號換行,斷行符號是指讓游標(或者檔案位置指標)移到行首部,換行是讓游標移到下一行。行結束在不同的系統中有著不同的表示,網上有著這樣一段關於它們的來曆和區別的描述:     在電腦還沒有出現之前,有一種叫做電傳打字機(Teletype Model 33)的玩意,每秒鐘可以打10個字元。但是它有一個問題,就是打完一行換行的時候,要用去0.2秒,正好可以打兩個字元。要是在這0.2秒裡面,又有新的字元傳過來,那麼這個字元將丟失。

     於是,研製人員想了個辦法解決這個問題,就是在每行後面加兩個表示結束的字元。一個叫做“斷行符號”,告訴打字機把列印頭定位在左邊界;另一個叫做“換行”,告訴打字機把紙向下移一行。
這就是“換行”和“斷行符號”的來曆,從它們的英語名字上也可以看出一二。
      後來,電腦發明了,這兩個概念也就被般到了電腦上。那時,儲存空間很貴,一些科學家認為在每行結尾加兩個字元太浪費了,加一個就可以。於是,就出現了分歧。
Unix系統裡,每行結尾只有“<換行>”,即“\n”;Windows系統裡面,每行結尾是“ <斷行符號><換行>”,即“\r\n”;Mac系統裡,每行結尾是“<斷行符號>”。一個直接後果是,Unix/Mac系統下的檔案在Windows裡開啟的話,所有文字會變成一行;而Windows裡的檔案在Unix/Mac下開啟的話,在每行的結尾可能會多出一個^M符號。

     C語言為了統一這種區別,規定檔案行末尾為換行,即'\n',這也是我們用printf("\n");就能夠實現斷行符號+換行的原因。那麼除了unix(unix本身就用'\n'表徵行結束)的其他系統,如Windows系統中,C語言在讀取檔案時,如果讀取到"\r\n",會捨棄斷行符號符'\r'只用'\n'表示行結束。這裡指的讀取是指以文字檔的方式讀取,如果以二進位讀取檔案,則不會作此處理(C語言保證二進位的透明性)。這也是fopen函數參數有"r"(以文字檔方式開啟以便讀取)和"rb"(以二進位檔案開啟以便讀取)之分。而在unix系統中,"r"和"rb"

並無區別,即都是透明傳輸的。當然,C語言在寫入文字檔時,也會做對應的處理("\n"->"\r\n")。getchar()和getch()     在明白了上面兩個重要的概念後,我們選取C語言中兩個字元讀取函數作分析:     getchar()我們都比較熟悉了,它從stdin指向的流(通常就是我們所說的控制台)讀取一個字元,並返回該字元,如果stdin指向的流處於檔案結束處,那麼它返回-1。前面曾提到,由於EOF的特殊值,使得getchar的傳回值是int而不是char,而由於C系隱式轉換,這會帶來不少麻煩之處。     例如     char c;     while((c = getchar())!=EOF)          putchar(c);         咋一看並無問題,程式也的確能在getchar返回-1時退出,因為c為signed char ,接收到int型-1(32個1)截斷後為0xFF,在c==EOF中,又會將c隱式轉換成int,由於c是有符號的,所以擴充位後又回到0xFFFFFFFF,因此c仍然等於-1。但是這是有隱患的,當getchar得到的字元0xFF並返回0x000000FF時,傳回值轉換成char得到0xFF,這也等於-1即EOF, 這會使得迴圈提前退出。顯然並非程式本意。     你或許想將c定義為unsiged char來避免0xFF==-1 再如:     unsigned char c;     while(( c = getchar() ) != EOF)          putchar(c);      這又將導致另一個隱患:當getchar()返回-1時,轉換成unsiged char為0xFF即255.當c和EOF比較時,又會轉換成int,由於c是無符號的,此時(int)c為0x000000FF,即仍為255.因此迴圈永遠也不會退出,因為unsiged char 永遠得不到 -1.     在討論了這些過後,最後看看正確用法:     int c;     while(( c = getchar() ) != EOF)          putchar(c);     我們只考慮這裡如何區分字元0xFF和傳回值EOF(0xFFFFFFFF)。當讀取到字元0xFF時,getchar返回0x000000FF c也接收到0x00000000FF,明顯是不等於-1的,c在後面轉換成char時,能夠正確得到0xFF。當返回EOF時,getchar返回0xFFFFFFFF,這使得c的編碼也為0xFFFFFFFF == -1 迴圈退出。     getchar()還有一個容易給新手帶來困惑的是:有時候我們只想從控制台讀取一個字元,但是在輸入一個字元後,getchar()卻並沒有立即返回,比如上面那段代碼,在我們輸入一個字元後,並沒有putchar(c)立即輸出。而是當我們輸入abc按斷行符號後,程式會立即輸出abc並換行。這是因為前面提到的,getchar()返回stdin指向的流的下一個字元,這個流是有緩衝區的,當按斷行符號時,會將輸入的資料(包括斷行符號換行)送入流緩衝中(造成這種的輸入方式的解釋之一是很早以前沒有終端(即我們所說的控制台)的時候,資料讀取都是通過檔案的,而檔案都是以行結尾的,因此為了提高IO效率,當遇到換行時,才將資料送入流緩衝中。)這樣getchar()從流緩衝中取出字元,因此abc和換行看起來一次性的列印了出來,實際也是逐個字元讀取和列印的。     接下來看看getch()     getch()和getchar()有三個區別:     1.getch()並不從stdin指向的流的緩衝區中讀取資料,而是直接從鍵盤輸入讀取資料,這意味著,當你輸入abc時,每輸入一個字元,getch()便返回該字元。     2.getch()並不會回顯字元,亦即你輸入的字元並不會顯示在控制台上。這使得我們可以通過getch()來在控制台程式中中斷等待使用者輸入,比如所有控制台程式結束時都會有一個press anykey to continue.. 這便是通過:     puts("press anykey to continue..");     getch();     來實現的。這樣使得使用者輸入能夠及時響應,不必每次都輸入斷行符號(區別1),並且由於輸入不回顯,也不會影響到程式的美觀性。大家可能都試過點擊控制台程式的Debug檔案下的exe檔案,控制台總是一閃而沒,這就是因為在控制台產生的exe檔案中,沒有系統自動添加的getch()。     3.getch包含在conio.h標頭檔中,以此也可以看出嚴格來說它並不是C標準IO(如getchar()一類位於stdio.h標頭檔)。     我們可以在實際程式中選擇這兩種之一來實現對應功能,在通過getchar擷取一個字元時,經常有這樣的疏忽,在輸入一個字母並按下Enter之後,getchar得到了該字元的值,卻忘了處理流緩衝中剩下的斷行符號換行。這時我們就可以通過getch()並增加回顯來實現.     以下是一段關於它們的一個有意思的小程式     #include<stdio.h>                              #include<stdio.h>     void main()                                         #include<conio.h>     {                                                          void main()          int c = getchar();                              {          printf("%d", c);                                        int c = getch();     }                                                                  printf("%d", c);                                                                  }     前者輸出10          即'\n'                           後者輸出13     即'\r'     這個問題網上看了很多資料,都說的模模糊糊,不甚明了。我自己也不是很清楚,按照我自己的理解。斷行符號鍵Enter按下時,系統會收到'\r',但是由於斷行符號鍵按下的環境不同(如文本編輯環境),會使得系統對斷行符號符的解釋不同。在文本編輯環境下(如記事本,WORD,控制台),斷行符號符會被Windows系統解釋為"\r\n"即斷行符號換行(因為Windows系統下"\r\n"代表行末尾)。這樣的話,就能夠解釋第二個程式的輸出,由於getch()從鍵盤捕捉輸入,因此得到'\r'(我也考慮過可能getch()也會得到"\r\n",但是如果在printf後面再加一句c
= getch()並輸出, 並不能得到兩個輸出13 10  而是只得到13)。那麼在斷行符號分行符號並放在C IO流緩衝中時,需要遵守C的規定,即行末尾由換行表示,亦即"\r\n"並解釋為'\n'。前面也曾提到這種解釋,我們可以把控制台也抽象成一種檔案,事實上,C本身也將stdin stdout stderr作為檔案描述符(Unix下就是0, 1, 2)提供給開發人員。我們在讀控制台資料即讀檔案時,需要對Windows本身的行末尾進行修正。因此getchar()得到了'\n'。     上一段說法全無根據,也很牽強。僅是本人猜想,希望理解這個的高手留言修正。C語言IO的關鍵就是EOF,流緩衝,重定位,以及如何?不同環境下的檔案表示的統一等。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.