簡述
在 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;
}