程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++之輸入(cin)詳解

C++之輸入(cin)詳解

編輯:關於C++

1、cin:

輸入操作的原理,程序的輸入都建有一個緩沖區,即輸入緩沖區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin函數直接從輸入緩沖區中取數據。正因為cin函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,這就是例子中為什麼會出現輸入語句失效的原因!

cin輸入結束的條件:Enter、Space、Tab。cin對這些結束符的處理:丟棄緩沖區中這些字符。與cin.get()不同。

案例1:

#include 
using namespace std;
int main() 
{
	int m, n;
	cin >> m;
	cin >> n;
         cout << m << n << endl;
	return 0;
}

測試正常輸入:

 

 

測試異常輸入:

 

 

案例2:string的輸入

void main()
{	string str1;
	cin >> str1;  //遇到空格的地方就停止字符串的讀取輸入   
	cout << str1 << endl;

	cin.get();
	getline(cin, str1);
	cout << str1 << endl;
}

測試:

 

可以看出cin是遇到“空格”就停止讀取輸入,並且cin是從第一個“非空格字符”開始讀取;

而getline則是直接從第一個字符開始讀取(無論是不是空格,都要讀入),並且getline是遇到“回車”停止讀入;

當把上述代碼中 的cin.get()去掉,則輸入“123”----》回車 後,getline直接讀取“回車”,運行完畢!

 

案例3:

int main()
{
	char str[8];
	cin.getline(str, 5);
	cout << str << endl;

	cin.getline(str, 5);
	cout << str << endl;
	return 0;
}

測試一:abcd (回車)abcd (輸出)efgh(回車)efgh (輸出)當用戶第一次輸入的字符串字符數小於4時,程序執行正常!

測試二:abcdefgh (回車)abcd (輸出)(輸出-換行)當用戶第一次輸入的字符數字符數大於4時,第一個字符串接受輸入的前四個字符,而第二次的輸入操作沒有執行,第二個字符串輸出為空。

 

2、cin.get():

案例1:

int main()
{
	char str1;
	char str2;
	str1 = cin.get(); //讀取單個字符,在屏幕輸入
	str2 = cin.get();
	cout << str1 << str2 << endl; //輸出剛剛載入的單個字符
	system("pause");  //進行暫停,否則會一閃而過
}

輸入:abcd 輸出:ab
既然cin.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裡的流數據清空時,便需要重新輸入才能賦值。

 

案例2:

	{
		char str1[10], str2[10];
		cin >> str1;
		cin >> str2;
		cout << str1 << endl;
		cout << str2 << endl;
		return 0;
	}

測試一輸入:abcd[Enter]efgh[Enter]輸出:abcdefgh【分析】輸入遇到回車符結束,很正常。

測試二輸入:abcd efgh輸出:abcdefgh【分析】第一次讀取字符串時遇到空格則停止了,將abcd讀入str1,並捨棄了空格,將後面的字符串給了第二個字符串。這證明了cin讀入數據遇到空格結束;並且丟棄空格符;緩沖區有殘留數據室,讀入操作直接從緩沖區中取數據。

案例3:

int main()
{
	char str1;
	char str2;
	str1 = cin.get(); //讀取單個字符,在屏幕輸入
	cin.get();
	str2 = cin.get();
	cout << str1 << str2 << endl; //輸出剛剛載入的單個字符
}

輸入:abcd 輸出:ac

程序中有3個cin.get(),由此可知,當空回調cin.get()時,cin.get便自動在cin中的流數據中刪除一個字母,起了一個刪除作用。

 

案例4:

}
	char c1, c2;
	cin.get(c1);
	cin.get(c2);
	cout << c1 << " " << c2 << endl;   // 打印兩個字符       cout<<(int)c1<<""<<(int)c2<

測試一輸入:a[Enter]輸出:a 97 10【分析】會發現只執行了一次從鍵盤輸入,顯然第一個字符變量取的'a',第二個變量取的是Enter(ASCII值為10),這是因為該函數不丟棄上次輸入結束時的Enter字符,所以第一次輸入結束時緩沖區中殘留的是上次輸入結束時的Enter字符!

測試二輸入:a b[Enter]輸出:a 97 32【分析】顯然第一個字符變量取的'a',第二個變量取的是Space(ASCII值為32)。原因同上,沒有丟棄Space字符。

 

案例5:

	{
		char ch, a[20];
		cin.get(a, 5);
		cin >> ch;
		cout << a << endl;
		cout << (int)ch << endl;
		return 0;
	}

測試一輸入:12345[Enter]輸出:123453【分析】第一次輸入超長,字符串按長度取了"1234",而'5'仍殘留在緩沖區中,所以第二次輸入字符沒有從鍵盤讀入,而是直接取了'5',所以打印的ASCII值是53('5'的ASCII值)。

測試二輸入:1234[Enter]a[Enter]輸出:123497【分析】第二次輸入有效,說明該函數把第一次輸入後的Enter丟棄了!
 

3、cin.getline:

cin.getline()與 cin.get(array_name,Arsize)的讀取方式差不多,以Enter結束,但是接受空格字符。按照長度(Arsize)讀取字符, 會丟棄最後的Enter字符。但是這兩個函數是有區別的:cin.get(array_name, Arsize)當輸入的字符串超長時,不會引起cin函數的錯誤,後面的cin操作會繼續執行,只是直接從緩沖區中取數據。但是cin.getline()當輸入超長時,會引起cin函數的錯誤,後面的cin操作將不再執行。

	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");
}

\

 

4、cin異常:

ios類定義了這四個常量badbit, eofbit, failbit, goodbit,其實這四個標志常量就是取對應標志位的掩碼,也即輸入的四種異常情況!
以上四個常量對應的取值為:
ios::badbit 輸入(輸出)流出現致命錯誤,不可挽回
ios::eofbit已經到達文件尾
ios::failbit輸入(輸出)流出現非致命錯誤,可挽回
ios::goodbit流狀態完全正常,各異常標志位都為0

我們可以用輸出語句來驗證這幾個常量的值:
cout << ios:: failbit << endl;//2
cout << ios:: eofbit << endl;//1
cout << ios:: badbit << endl; //4
cout << ios:: goodbit << endl; //0

 

cin.fail()、cin.clear()、cin.sync()例子:

int main()
{
	int a;
	while (true)
	{
		cin >> a;
		if (!cin) //條件可改寫為cin.fail()
		{
			cout << "輸入類型錯誤,請重新輸入!" << endl;
			cin.clear(); //復為標志,將cin中的所有標志設置為有效狀態
			cin.sync(); //清空流
		}
		else
		{
			cout << a << endl;
			break;
		}
	}
	system("pause");
}

上面的cin默認值為非0,當輸入為非整形時,它的狀態標識符改為fail(即0),再用cin.clear()讓錯誤標識改回為非0,可以繼續輸入,再清空流數據繼續輸入。如果沒有了cin.clear(),則會進入死循環,其過程為我們輸入了英文字母,它的狀態標識便為fail,當運行到條件判斷時,便總是回到錯誤的條件表示裡,並且再也沒有辦法輸入,因為錯誤的表示關閉了cin,所以會進入死循環。可以分別注釋掉cin.clear()和cin.sync()進行驗證。

 

5、in.ignore()

這個函數用來丟棄輸入緩沖區中的字符,第一參數定義一個數(_Count),第二個參數定義一個字符變量(_Delim)。下面解釋一下函數是怎樣執行的:函數不停的從緩沖區中取一個字符,並判斷是不是_Delim,如果不是則丟棄並進行計數,當計數達到_Count退出,如果是則丟棄字符退出。

這個函數的默認值,第一個參數默認為1,第二個參數默認為EOF。所以cin.ignore()就是丟棄緩沖區中的第一個字符。

用cin.get()讀取字符,get函數不丟棄回車符,所以回車符仍殘留在緩沖區中,導致第二次讀取數據直接從緩沖區中取得回車符!既然cin.get()不會自動丟棄輸入結束時的回車符,這裡我們就用ignore()函數,手動丟棄回車符!

int main()
{
	char c1, c2;
	cin.get(c1);
	cin.ignore(); // 用該函數的默認情況,丟棄一個字符,即上次輸入結束的回車符  
	cin.get(c2);
	cout << c1 << " " << c2 << endl;   // 打印兩個字符  
	cout << (int)c1 << " " << (int)c2 << endl; // 打印這兩個字符的ASCII值  
	return 0;
}

 

清空整個緩沖區:——其實該函數最常用的方式是這樣的,將第一個參數設的非常大,將第二個參數設為'\n',這樣就可以緩沖區中回車符中的所有殘留數據,因為一般情況下前面輸入殘留的數據是沒有用的,所以在進行新一次輸入操作前將緩沖區中所有數據清空是比較合理。
如:cin.ignore(1024, '\n');

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved