getline成員函數分析

來源:互聯網
上載者:User

今天一個學生寫了如下程式碼片段,其目的將一個文字檔的內容輸出到螢幕上。

ifstream in("file3.txt")char buf[3];while(!in.eof())  {       in.getline(buf,  sizeof(buf));cout<<buf<<endl;}

file3.txt的內容如下:

abcefg

在執行的時候程式輸出一個ab之後便進入了死迴圈。原因何在?

經過一個小時的查資料和看代碼,終於大致搞清問題所在,與getline的實現機制有關。

getline成員函數的聲明如下

basic_istream<Elem, Tr>&

getline(     char_type *_Str,      streamsize _Count,       char_type _Delim);

第一個參數是字元緩衝區地址,第二個是緩衝區長度,第三個是分隔字元(預設是斷行符號)。

其實現的大致流程是:

1、首先判斷istream的failbit位是否為1,為1的話意味著輸入資料流的狀態有錯誤,則不進行讀操作,getline函數結束執行

2、從當前位置開始從輸入資料流中依次讀取單個字元並拷貝到緩衝區,直到遇到下列條件滿足時,迴圈結束。

(1)遇到檔案尾時停止讀操作,並設定流對象的結束標記為1

(2)讀到調用者指定的分隔字元時,此時將分隔字元之前的字元拷貝到緩衝區中,但分隔字元本身不拷貝進去,並且下次讀操作將從分隔字元後的下一個字元開始。

(3)已經讀了n-1個字元(n是調用者傳入的第二個實參_Count的初值),此時要把流對象的錯誤標誌位置1(為什麼要這麼幹,我也不知道,個人覺得這麼設計不太合理....)

當迴圈結束後,gelline函數會在字串的尾部加一個C風格的結束符'\0'。

這樣,學生遇到的現象就可以解釋了。

首先,由於file3.txt檔案是存在的,所以in對象開始時的狀態是正常的,因此第一次getline將會執行,由於緩衝區的長度是3,因此在讀完ab兩個字元之後getline內部的迴圈便終止了。此時getline會把in對象的failbit設為1,但檔案還未讀到尾部,所以in.eof()為false,這樣在第二次進入while迴圈體時,迴圈條件!in.eof()為true,於是繼續執行getline函數

,但是由於第一次的getline操作已經把in對象的failbit設為1,第二次的getline便不進行任何讀操作了,此時流的指標和流的狀態均未發生變化,於是第三次迴圈時與第二次迴圈一樣,迴圈條件為真,可以進入迴圈體,in對象的failbit設為1,getline函數不進行讀取操作,如是反覆,便導致了死迴圈。

知道了病因,於是便有了下面的解決方案

while(!in.eof()){in.getline(buf,sizeof(buf));//將if(in.fail() && in.gcount()==(sizeof(buf)-1))             in.clear();       cout<<buf<<endl;}

這裡的clear成員函數的作用是將in對象的狀態設回正常狀態。gcount函數返回上次讀操作中從輸入資料流中提取的字元數(包括分隔字元)。

請讀者自行分析和改進這個解決方案。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.