輸入輸出流狀態

1.流狀態

cin或cout對象包含一個描述流狀態(stream state)的數據成員(從ios_base那裏繼承的)。流狀態(被定義爲iostate類型,而iostate是一種bitmask類型)由3個ios_bae元素組成:eofbit、badbit或failbit,其中每個元素都是一位,可以是1(設置)或0(清除)。當cin操作到達文件末尾時,它將設置eofbit;當cin操作未能讀取到預期的字符時,它將設置failbit。I/O失敗(如試圖讀取不可訪問的文件或試圖寫入到保護的磁盤),也可能將failbit設置爲1.在一些無法診斷的失敗破壞流時,badbit元素將被設置。當全部3個狀態都設置爲0時,說明一切順利。程序可以檢查流狀態,並使用這種信息來決定下一步做什麼。

下表列出了這些位和一些報告或改變流狀態的ios_base方法

這裏寫圖片描述
上表中的兩種方法——clear( )和setstate( )很相似。他們都重置狀態,但採取的方式不同。clear( )方法將狀態設置爲它的參數。因此,下面的調用:

clear( );

將使用默認參數0,這裏將清除全部3個狀態位(eofbit、badbit和failbit)。同樣,下面的調用:

clear(eofbit);

將狀態設置爲eofbit;也就是說,eofbit將被設置,另外兩個狀態位將被清除。
而setstate( )方法隻影響其參數中已設置的位。因此,如果failbit被設置,則仍將被設置。

2.流狀態的影響
只有在流狀態良好(所有的位都被清除)的情況下,下面的if或while測試才能返回true:

while(cin>>input);

如果測試失敗,可以使用上表中的成員函數來判斷可能的原因。例如:

while(cin>>input)
{
    sum += input;
}
if(cin.eof())
    cout<<"Loop terminated because EOF encountered\n";

設置流狀態有一個非常重要的後果:流狀態對後面的輸入或輸出關閉,知道位被清除。例如,下面的代碼不能正常工作:

while(cin>>input)
{
    sum += input;
}
cin>>input;//won't work

如果希望程序在流狀態位被設置後能夠讀取後面的輸入,就必須將流狀態設置爲良好(即爲0)。這可以通過clear( )函數來實現:

whlie(cin>>input)
{
    sum += input;
}
cin.clear();
while(!isspace(cin.get()))
    continue;
cin>>input;

注意,這還不足以重新設置流狀態。導致輸入循環終止的不匹配輸入仍留在輸入隊列中,程序必須跳過它。一種方法是已知讀取字符,直到達到空白爲止。isspace( )參數是一個cctype函數,它在參數是空白字符時返回true。另一種方法是,丟棄行中剩餘部分,而不僅僅是下一個單詞:

while(cin.get()!='\n')
    continue;//get rid rest of line

這個例子假設循環由於不恰當的輸入而終止。現在,假設循環是由於達到文件尾或者由於硬件故障而終止的,則處理錯誤輸入的新代碼將毫無意義。可以使用fail( )方法檢測假設是否正確,來修復問題。由於歷史原因,fial( )在failbit或eofbit被設置時返回true,因此代碼必須排除後一種情況。下面是一個排除這種情況的例子:

while(cin>>input)
{
    sum += input;
}
if(cin.fail() && !cin.eof())
{
    cin.clear();
    while(!isspace(cin.get()))
        continue;
}
else
{
    cout<<"I cannot go on!\n";
    exit(1);
}
cin>>input;

3.其他istream類方法

1)單字符輸入,cin.get(ch)與cin.get()
這裏寫圖片描述
採用哪種單字符輸入形式呢?
首先,應該確認是否希望跳過空白。如果跳過空白方便,則使用抽取操作符>>。如果希望檢測每個字符,請使用get( )方法。

2)字符串輸入:getline( )、get( )和ignore( )

istream & get(char *, int, char);
istream & get(char *, int);
istream & getline(char *, int, char);
istream & getline(char *, int);

第一個參數是用於放置輸入字符串的內存單元的地址。第二個參數比要讀取的最大字符數大1(額外的一個字符用於存儲結尾的空字符,以便將輸入存儲爲一個字符串)。第三個參數指定用作分界符的字符,只有兩個參數的版本將換行符作爲分界符。上述函數都在讀取最大數目的字符或遇到換行符後爲止。
例如,下面的代碼:

char line[50];
cin.get(line,50);

將字符輸入讀取到字符數組line中。cin,get( )函數將在達到第49個字符或遇到換行符(默認情況)後停止將輸入讀取到數組中。get( )和getline( )之間的主要區別在於,get( )將換行符保留在輸入流中,這樣接下來的輸入操作首先看到的將是換行符,而getline( )抽取並丟棄輸入流中的換行符。
下面程序演示了getline( )和get( )是如何工作的,它還介紹了ignore( )成員函數。該函數接受兩個參數:一個是數字,指定要讀取的最大字符;另一個是字符,用作輸入分界符。如:

ignore(255, '\n');

將讀取並丟棄接下來的255個字符或直到到達第一個換行符。原型爲兩個參數提供的默認值爲1和EOF,該函數的返回類型爲istream &:

istream & ignore(int = 1, int = EOF);

示例代碼:

#include <iostream>
const int Limit = 255;

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

    char input[Limit];

    cout<<"Enter a string for getline()processing:\n";
    cin.getline(input,Limit,'#');
    cout<<"Here is your input: \n";
    cout<<input<<"\nDone with phase 1\n";

    char ch;
    cin.get(ch);
    cout<<"The next input character is "<<ch<<endl;

    if(ch != '\n')
        cin.ignore(Limit,'\n');
    cout<<"Enter a string for get()processing: \n";
    cin.get(input,Limit,'#');
    cout<<"Here is your input: \n";
    cout<<input<<"\nDone with phase 2\n";
    cin.get(ch);
    cout<<"The next input character is "<<ch<<endl;
    return 0;
}

注意:getline( )函數將丟棄輸入中的分界字符#,而get( )不會。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章