流(stream)是一個傳送和格式化固定寬度字元的對象。包括輸入流、輸出流和同時實作兩種功能的輸入/輸出流。其中,用istream及其派生類表示輸入流,用ostream及其子類表示輸出流,用iostream及其子類表示輸入輸出流。
1 輸入流與cin
cin是輸入流istream類的對象,它是一個全局變量。cin通過提取符(extractor)“>>”從流中擷取資訊。
2 錯誤處理
2.1 流狀态位
ios_base類中聲明了所有流類共有的内容,不依賴于流所處理的字元類型。其中,定義了4個标志位來測試流的狀态,badbit、eofbit、failbit和goodbit。其中,badbit位表示了在流緩沖區中發生了緻命性錯誤,流将不能繼續使用;eofbit位表示輸入結束,例如按下了Ctrl-Z;failbit位表示I/O操作由于非法資料而失敗,流可以繼續使用;goodbit位表示一切正常,沒有錯誤發生,也沒有發生輸入結束。
2.2 流狀态函數
通過good()、eof()、fail()和bad()等成員函數擷取流狀态。這些函數的傳回值是boolean類型,分别對應goodbit、eofbit、failbit和badbit标志位的。可以通過調用以上的成員函數,根據其傳回的布爾值來測試發生了什麼情況,傳回的布爾值表示相應的流狀态。
當除goodbit之外的其它3個标志位沒有被設定時,流類的成員函數good()傳回真。如果eofbit被設定則函數eof()傳回真,表明程式試圖從已經到達末尾的流(通常是檔案流)中讀取資料。如果設定了failbit和badbit标志位中的任意一個,則函數fail()傳回真,隻有設定了badbit标志位,函數bad()才傳回真。
2.3 清空标志位
一旦設定了流狀态中的任何一個标志位,這些标志位将保持不變。可以通過調用clear()函數來清空标志位。如:
cin.clear();
2.4 程式設計驗證
在控制台程式中,有如下代碼
int i;
cin >> i;
bool good = cin.good();
bool bad = cin.bad();
bool fail = cin.fail();
bool eof = cin.eof();
程式運作後,在控制台中輸入整數5,此時good的值是true,而其它三個值是false。輸入Ctrl-Z,此時good和bad的值是false,fail和eof的值是true。如果輸入一個字元,如’a’,此時good、bad和eof的值是false,而fail的值是true。
3 程式設計實踐
在CSDN論壇上有朋友問到這樣一個問題:
int i;
while(1)
{
cin >> i;
cout << i << endl;
}
運作以上代碼時,輸入正确格式(整數)時,程式可以正确運作。當輸入不正确的格式時,如輸入字元’a’,此時程式不報錯,但是會一直輸出i的最後一次正确值。也就是說,當輸入錯誤格式時
cin >> i;
此代碼不起作用了。
3.1 問題分析
從“2錯誤處理”中分析可知,當輸入不正确格式的數時,cin的failbit位将會被設定,導緻cin的提取符失效。
3.2 問題解決
使用“2.3 清空标志位”中提到的clear()函數,清空failbit位。之後調用ignore()函數跳過流中格式不正确的資料。
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
其中,ignore()函數的第一個參數表示要跳過的字元的數目,第二個參數指定了遇到哪個字元時,ignore()函數退出。
numeric_limits是一個模闆類,該類用于描述内置數字類型的數學屬性,streamsize是流大小的機關,max()函數是numeric_limits類的成員函數,該函數的作用是傳回指定類型(streamsize類型)的最大值。第二行代碼的含義是,當輸入流中的資料出現錯誤時,跳過該流,此時流的狀态為good()。
3.3 修改後的代碼
修改後的代碼如下所示
int i;
while (1)
{
cout << "請輸入一個整數:" << endl;
cin >> i;
while(cin.fail())
{
cout << "輸入格式錯誤,請重新輸入!" << endl;
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "請輸入一個整數:" << endl;
cin >> i;
}
cout << i << endl;
}
此時,當輸入不正确格式的資料時,程式會顯示錯誤提示資訊,并且可以重新輸入。