轉:問題描述一:(分析scanf()和getchar()讀取字符)
---------------------------------------------------- 測試二:
------------------ 第二:爲了避免出現上述問題,必須要清空緩衝區的殘留數據,可以用以下的方法解決: |
C/C++學習筆記2 - cin深入分析(上) - cin輸入操作處理
cin<<, cin.get,cin.getline等函數深入分析 很多初學者都認爲cin函數是一個很簡單的函數,其實不然!cin函數有很多需要了解的知識(比如:cin的返回值是什麼,cin提供了哪些成員函數且分別是什麼作用,如cin.clear(), cin.ignore(), cin.fail(), cin.good()等等),如果沒有很好的掌握,在使用的時候很可能會出問題卻不知其原因!而且很多人也確確實實遇到過不少問題,以下是幾個簡單的例子: 程序1: #include <iostream> using namespace std; int main() { int m, n; cin>>m; cin>>n; return 0; } 測試情況: 如果用戶每次都輸入兩個合法的數,程序不會出問題! 但是如果用戶第一次輸入時給一個非法的輸入,比如說輸入一個字符'a',你會發現程序不 會再執行第二條輸入語句。似乎有點奇怪!! 程序2: #include <iostream> using namespace std; 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時,第一個字符串接受輸入的前四個字符,而第二次的輸入操作沒有執行,第二個字符串輸出爲空。似乎也很奇怪!!! 其實在很多時候都會遇到諸如此類的問題,如果不熟悉程序輸入的原理和cin等一些函數的原理就不知道怎麼解決!我在這裏做一個簡單的介紹,也許介紹得不是很準確和全面,或者存在一些誤解,請大家包涵! 輸入操作的原理 與前一節中提到的scanf函數一樣,程序的輸入都建有一個緩衝區,即輸入緩衝區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩衝區,而cin函數直接從輸入緩衝區中取數據。正因爲cin函數是直接從緩衝區取數據的,所以有時候當緩衝區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,這就是例子中爲什麼會出現輸入語句失效的原因! cin的一些輸入函數和操作符 cin is a extern istream object。提供了很多可用的成員函數和重載的操作符,如:cin<<, cin.get(), cin.getline()等。下面我們來了解一下這幾個函數: 一. cin<< 該操作符是根據後面變量的類型讀取數據。 輸入結束條件 :遇到Enter、Space、Tab鍵。(這個很重要!) 對結束符的處理 :丟棄緩衝區中使得輸入結束的結束符(Enter、Space、Tab) 讀字符的情況: 程序3: #include <iostream> using namespace std; int main() { char c1, c2; cin>>c1; cin>>c2; cout<<c1<<" "<<c2<<endl; return 0; } 測試一輸入: a[Enter] b[Enter] 輸出: a b 測試二輸入: a b[Enter] 輸出: a b
讀字符串的情況: 程序4: #include <iostream> using namespace std; int main() { char str1[10], str2[10]; cin>>str1; cin>>str2; cout<<str1<<endl; cout<<str2<<endl; return 0; } 測試一輸入: abcd[Enter] efgh[Enter] 輸出: abcd efgh 【分析】輸入遇到回車符結束,很正常。 測試二輸入: abcd efgh 輸出: abcd efgh 【分析】第一次讀取字符串時遇到空格則停止了,將abcd讀入str1,並捨棄了空格,將後面的字符串給了第二個字符串。這證明了cin讀入數據遇到空格結束;並且丟棄空格符;緩衝區有殘留數據室,讀入操作直接從緩衝區中取數據。
二.cin.get() 該函數有三種格式:無參,一參數,二參數 即cin.get(), cin.get(char ch), cin.get(array_name, Arsize) 讀取字符的情況: 輸入結束條件:Enter鍵 對結束符處理:不丟棄緩衝區中的Enter cin.get() 與 cin.get(char ch)用於讀取字符,他們的使用是相似的, 即:ch=cin.get() 與 cin.get(ch)是等價的。 程序5: #include <iostream> using namespace std; int main() { char c1, c2; cin.get(c1); cin.get(c2); cout<<c1<<" "<<c2<<endl; // 打印兩個字符 cout<<(int)c1<<" "<<(int)c2<<endl; // 打印這兩個字符的ASCII值 return 0; } 測試一輸入: a[Enter] 輸出: a 97 10 【分析】會發現只執行了一次從鍵盤輸入,顯然第一個字符變量取的'a', 第二個變量取的是Enter(ASCII值爲10),這是因爲該函數不丟棄上次輸入結束時的Enter字符,所以第一次輸入結束時緩衝區中殘留的是上次輸入結束時的Enter字符! 測試二輸入: a b[Enter] 輸出: a 97 32 【分析】顯然第一個字符變量取的'a', 第二個變量取的是Space(ASCII值爲32)。原因同上,沒有丟棄Space字符。 讀取字符串的情況: cin.get(array_name, Arsize)是用來讀取字符串的,可以接受空格字符,遇到Enter結束輸入,按照長度(Arsize)讀取字符, 會丟棄最後的Enter字符。 程序6: #include <iostream> using namespace std; int main () { char a[20]; cin.get(a, 10); cout<<a<<endl; return 0; } 測試一輸入: abc def[Enter] 輸出: abc def 【分析】說明該函數輸入字符串時可以接受空格。 測試二輸入: 1234567890[Enter] 輸出: 123456789 【分析】輸入超長,則按需要的長度取數據。 程序7: #include <iostream> using namespace std; int main () { char ch, a[20]; cin.get(a, 5); cin>>ch; cout<<a<<endl; cout<<(int)ch<<endl; return 0; } 測試一輸入: 12345[Enter] 輸出: 1234 53 【分析】第一次輸入超長,字符串按長度取了"1234",而'5'仍殘留在緩衝區中,所以第二次輸入字符沒有從鍵盤讀入,而是直接取了'5',所以打印的ASCII值是53('5'的ASCII值)。 測試二輸入: 1234[Enter] a[Enter] 輸出: 1234 97 【分析】第二次輸入有效,說明該函數把第一次輸入後的Enter丟棄了!
三.cin.getline() cin.getline() 與 cin.get(array_name, Arsize)的讀取方式差不多,以Enter結束,可以接受空格字符。按照長度(Arsize)讀取字符, 會丟棄最後的Enter字符。 但是這兩個函數是有區別的: cin.get(array_name, Arsize)當輸入的字符串超長時,不會引起cin函數的錯誤,後面的cin操作會繼續執行,只是直接從緩衝區中取數據。但是cin.getline()當輸入超長時,會引起cin函數的錯誤,後面的cin操作將不再執行。(具體原因將在下一部分"cin的錯誤處理"中詳細介紹) 程序8: #include <iostream> using namespace std; int main () { char ch, a[20]; cin.getline(a, 5); cin>>ch; cout<<a<<endl; cout<<(int)ch<<endl; return 0; } 測試輸入: 12345[Enter] 輸出: 1234 -52 【分析】與cin.get(array_name, Arsize)的例程比較會發現,這裏的ch並沒有讀取緩衝區中的5,而是返回了-52,這裏其實cin>>ch語句沒有執行,是因爲cin出錯了! |