天天看點

cin 詳解(get()、getline()、clear()、sync())

簡述

在 C 中,輸入輸出用 scanf 和 printf,在輸入資料的同時還需說明資料的類型,如果輸入資料較多,那就很麻煩,而 C++ 中也有相似的東西 cin 和 cout,它們來自 C++ 的一個名叫 iostream 的類庫。

iostream 是由 istream(輸入流)和 ostream(輸出流)派生。是以在 iostream 中就有了輸入和輸出的相關對象:

  • cin:标準輸入(standard input)的 istream 類對象,cin 使我們可以從裝置讀取資料。
  • cout:标準輸出(standard output)的 ostream 類對象。對應于标準輸出流,預設情況下是顯示器。這是一個被緩沖的輸出,可以被重定向。
  • cerr:标準錯誤流,用于顯示錯誤消息。預設情況下被關聯到标準輸出流,但它不被緩沖,也就說錯誤消息可以直接發送到顯示器,而無需等到緩沖區或者新的換行符時,才被顯示。一般情況下不被重定向。

cout 與 cerr 的差別:cout 的輸出可以重定向到一個檔案中,而 cerr 必須輸出在顯示器上。

暫時先介紹這些,以下主要介紹 cin 中 get()、getline()、clear()、sync() 的用法。

| 版權聲明:一去、二三裡,未經部落客允許不得轉載。

get()

首先看看 get(),它是一個讀取單個字元的方法。字元變量 = cin.get(),相當于 cin.get(字元變量)。

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str;
    str = cin.get();      //讀取單個字元,在螢幕輸入,相當于cin.get(str);
    cout << str << endl;  //輸出剛剛載入的單個字元
    system("pause");      //進行暫停,否則會一閃而過

    return 0;
}      

運作程式後:

輸入:a

輸出:a

但當輸入的為多個英文字元時,那又會如何呢?

輸入:abcd

輸出:a

結論:get() 隻能讀取第一個字元。

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str1;
    char str2;
    str1 = cin.get();  //讀取單個字元,在螢幕輸入
    str2 = cin.get();
    cout << str1 << str2 << endl;  //輸出剛剛載入的單個字元
    system("pause");  //進行暫停,否則會一閃而過

    return 0;
}      

運作程式後:

輸入:abcd

輸出:ab

既然 get() 是讀取第一個字元,那 str2 為什麼不也是 a 呢?

原理如下:

在 cin 這個對象裡,有一個儲存字元的流,可以想象成緩沖區,事實上是 cin 裡封裝的一個東西。當我們在程式上輸入字元後,對象 cin 獲得了我們輸入的字元。例如獲得 abcd,然後再通過 .get() 把流裡面的第一個字元去掉,賦給 str1,這時,cin 裡儲存的流的資料為 bcd,而 str1 則獲得了 a。當我們再次運作 str2 = cin.get() 時,同理把 cin 裡流的資料的 b 拿出來給了 str2,此後,cin 裡面的流的資料為 cd,而 str2 則為 b,是以最後輸出時,便能輸出 ab 了。

還有個補充,究竟什麼時候才輸入資料呢?我們可以再通過上面的代碼進行嘗試,我們輸入單個字母 ‘a’,然後按回車,發現并沒有輸出資料,而是再等待一次輸入資料,我們再輸入字母 ‘b’,按回車後便輸出ab了。相信到這裡,大家都應該明白了,因為當我們第一次輸入 a 後,通過 str1 = cin.get() 使 cin 裡的流沒有資料,清空了。是以到第二次要再賦給 str2 值時,它找不到資料,要重新再輸入資料。由此來看可以知道,當 cin 裡的流資料清空時,便需要重新輸入才能指派。

而 get() 還有個用法:

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str1;
    char str2;
    str1 = cin.get();  //讀取單個字元,在螢幕輸入
    cin.get();
    str2 = cin.get();
    cout << str1 << str2 << endl;  //輸出剛剛載入的單個字元
    system("pause");

    return 0;
}      

運作程式後:

輸入:abcd

輸出:ac

程式中有 3 個 get(),由此可知,當空回調 get() 時,get() 便自動在 cin 中的流資料中删除一個字母,起了一個删除作用。

getline()

對 get() 有了一定了解之後,對 getline() 的學習就可以更快了,原理是一緻的,但是 getline() 則是擷取一整行文本。

原型:getline(char *line, int size, char=’/n’)

參數一:字元指針

參數二:字元長度

參數三:結束辨別符。

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str[200];
    cin.getline(str, sizeof(str));  //第三個不輸入,預設回車為結束标符
    cout << str << endl;  //輸出
    system("pause");

    return 0;
}      

這樣,我們輸入多個英文或數字,然後按回車,就會輸出剛剛輸出的東西了。

接下來,我們讨論第三個參數的作用。

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str[200];
    cin.getline(str, sizeof(str), 'X'); //以單個英文字母'X'作為終止辨別符
    cout << str << endl; //輸出
    system("pause");

    return 0;
}      

當我們輸入多個數字或者字母時,例如:

輸入:abcdeX(回車) 輸出:abcde

輸入:aXbcde(回車) 輸出:a

輸入:Xabcde(回車) 輸出:

這樣X便成了終止符,如上可知:當遇到第一個結束符标志時,就結束,輸出其前面的所有字元。其原理和 get() 一樣。或許我們可以像 get() 那樣嘗試一下:

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    char str1[200];
    char str2[200];
    cin.getline(str1, sizeof(str1), 'X'); //以單個英文字母'X'作為終止辨別符
    cin.getline(str2, sizeof(str2), 'Y'); //以單個英文字母'Y'作為終止辨別符
    cout << "第一行是:" << str1 << endl; //輸出
    cout << "第二行是:" << str2 << endl;
    system("pause");

    return 0;
}      

輸入:abcdXXXefghYYYigkl(回車)

輸出: 第一行:abcd 第二行:XXefgh

如上可知,當遇到第一個結束符 ‘X’ 結束輸出 abcd,之後遇到第一個結束符 ‘Y’ 結束輸出 XXefgh。

clear()

接下來談談 clear() 的作用,第一次看到這東西,很多人以為就是清空 cin 裡面的資料流,而實際上卻與此相差甚遠,首先看看以下代碼:

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    int a;
    cin >> a;
    ios::iostate state = cin.rdstate();
    cout << state << endl;
    if (state == ios::goodbit)
    {
        cout << "輸入資料的類型正确,無錯誤!" << endl;
    }
    else if (state == ios_base::failbit)
    {
        cout << "輸入資料類型錯誤,非緻命錯誤,可清除輸入緩沖區挽回!" << endl;
    }
    system("pause");

    return 0;
}      

我們定義要輸入的變量是整型,但如果輸入了英文字母或者漢字,那就會發生錯誤,cin 裡有個方法能檢測這個錯誤,就是 rdstate()。

當 rdstate() 傳回 0(即:ios::goodbit)時表示無錯誤,可以繼續輸入或者操作,若傳回 2 則發生非緻命錯誤即 ios::failbit,則不能繼續輸入或操作。而 clear() 則可以控制我們此時 cin 裡對這個問題的一個辨別。

文法:cin.clear(辨別符)

辨別符号為:

  • goodbit:無錯誤。
  • Eofbit:已到達檔案尾。
  • failbit:非緻命的輸入/輸出錯誤,可挽回。
  • badbit:緻命的輸入/輸出錯誤,無法挽回。

若在輸入輸出類裡,需要加 ios:: 辨別符号。

sync()

通過 clear(),我們能确認它的内部辨別符,如果輸入錯誤則能重新輸入。結合真正的清空資料流方法 sync(),請看下例:

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    int a;
    while (true)
    {
        cin >> a;
        if (!cin)  //條件可改寫為cin.fail()
        {
            cout << "輸入類型錯誤,請重新輸入!" << endl;
            cin.clear(); //複為标志,将cin中的所有标志設定為有效狀态
            cin.sync(); //清空流
        }
        else
        {
            cout << a << endl;
            break;
        }
    }
    system("pause");

    return 0;
}