今天看完一篇牛人博文,受益匪淺,小記一下。原文更詳細http://blog.csdn.net/lewsn2008/archive/2008/04/16/2295790.aspx
首先我們呢看一下輸入操作的原理, 程序的輸入都建有一個緩沖區,即輸入緩沖區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin等輸入輸出函數直接從輸入緩沖區中取數據。正因為cin等輸入輸出函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入。
---------------
1,要注意不同的函數是否接受空格符、是否舍棄最后的回車符的問題!
讀取字符時:
scanf()以Space空格、Enter、Tab結束一次輸入,不會舍棄最后的回車符(即回車符會殘留在緩沖區中),(區別讀字符串時會清楚)//所以可以用getchar()清除;
getchar()以Enter結束輸入,也不會舍棄最后的回車符;
讀取字符串時:
scanf()以Space、Enter、Tab結束一次輸入,會舍棄最后的回車符(區別讀字符時)和所有的空格等等。
gets()以Enter結束輸入(空格不結束),接受空格,會舍棄最后的回車符!
第二:為了避免出現上述問題,必須要清空緩沖區的殘留數據,可以用以下的方法解決:
方法1:C語言里提供了函數清空緩沖區,只要在讀數據之前先清空緩沖區就沒問題了!
這個函數是fflush(stdin)。
方法2:自己取出緩沖區里的殘留數據。
scanf("%[^\n]",string);
-------------------------
cin的學問
一. cin<<
該操作符是根據后面變量的類型讀取數據。
輸入結束條件 :遇到Enter、Space、Tab鍵。(這個很重要!)
對結束符的處理 :清楚緩沖區中使得輸入結束的結束符(Enter、Space、Tab)
(這里有一點問題,
int i;
char c[100];
cin>>i;
cin.getline(str,100);
cout<<str;
如果輸入是:12 adjf回車
輸出將先是空格然后adjf;
如果輸入是:12回車adjf回車
輸出將是adjf.
看來cin>>要在連用時,比如cin>>a>>b;或者cin>>a;cin>>b消除空格能力才體現。
)
二.cin.get()
該函數有三種格式:無參,一參數,二參數
即cin.get(), cin.get(char ch), cin.get(array_name, Arsize)
(i)讀取字符的情況:
輸入結束條件:Enter鍵(遇空格不結束)
對結束符處理:不丟棄緩沖區中的Enter
cin.get() 與 cin.get(char ch)用于讀取字符,他們的使用是相似的,
即:ch=cin.get() 與 cin.get(ch)是等價的。
測試程序:
#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字符。
(ii)讀取字符串的情況:
cin.get(array_name, Arsize)是用來讀取字符串的,可以接受空格字符,遇到Enter結束輸入,按照長度(Arsize)讀取字符, 會丟棄最后的Enter字符。
(i i i)cin.getline()
cin.getline() 與 cin.get(array_name, Arsize)的讀取方式差不多,以Enter結束,可以接受空格字符。按照長度(Arsize)讀取字符, 會丟棄最后的Enter字符。
但是這兩個函數是有區別的:
cin.get(array_name, Arsize)
當輸入的字符串超長時,不會引起cin函數的錯誤,后面的cin操作會繼續執行,只是直接從緩沖區中取數據。但是cin.getline()
當輸入超長時,會引起cin函數的錯誤,后面的cin操作將不再執行。(具體原因將在下一部分"cin的錯誤處理"中詳細介紹)
------------
cin的錯誤處理
程序執行時有一個標志變量來標志輸入的異常狀態,其中有三位標志位分別用來標志三種異常信息,他們分別是:failbit,eofbit,badbit。這三個標志位在標志變量中是這樣分配的:
____________________________________
| 2 | 1 | 0 |
| failbit | eofbit | badbit |
|___________|__________|___________|
看一下這幾個標志位的作用(引用msdn):
badbit, to record a loss of integrity of the stream buffer.
eofbit, to record end-of-file while extracting from a stream.
failbit, to record a failure to extract a valid field from a stream.
In addition, a useful value is goodbit, where no bits are set.
接下來我么看幾個ios類的數據定義(引用msdn):
typedef T2 iostate;
static const iostate badbit, eofbit, failbit, goodbit;
這里ios類定義了這四個常量badbit, eofbit, failbit, goodbit,其實這四個標志常量就是取對應標志位的掩碼,也即輸入的四種異常情況!
以上四個常量對應的取值為:
ios::badbit 001 輸入(輸出)流出現致命錯誤,不可挽回
ios::eofbit 010 已經到達文件尾
ios::failbit 100 輸入(輸出)流出現非致命錯誤,可挽回
ios::goodbit 000 流狀態完全正常, 各異常標志位都為0
如果出現輸入錯誤,則cin不再工作,我們可以用cin.clear()重置標記位。
測試程序:
#include <iostream>
using namespace std;
int main ()
{
char ch, str[20];
cin.getline(str, 5);
cout<<"flag1:"<<cin.good()<<endl; // 查看goodbit狀態,即是否有異常
cin.clear(); // 清除錯誤標志
cout<<"flag1:"<<cin.good()<<endl; // 清除標志后再查看異常狀態
cin>>ch;
cout<<"str:"<<str<<endl;
cout<<"ch :"<<ch<<endl;
return 0;
}
測試輸入:
12345[Enter]
輸出:
flag1:0 // good()返回false說明有異常
flag2:1 // good()返回true說明,clear()已經清除了錯誤標志
str:1234
ch :5
但是當前一次讀取數據出錯后,如果緩沖區沒有清空的話,重置錯誤標志還不夠!要是能將緩沖區的殘留數據清空了就好了哦!下面我們再來看一個很重要的函數!cin.ignore()
這個函數用來丟棄輸入緩沖區中的字符,第一參數定義一個數,第二個參數定義一個字符變量。
例:cin.ignore(5, 'a'); 函數將不斷從緩沖區中取一個字符丟棄,直到丟棄的字符數達到5或者讀取的字符為'a'。
其實該函數最常用的方式是這樣的,將第一個參數設的非常大,將第二個參數設為'\n',這樣就可以緩沖區中回車符中的所有殘留數據,因為一般情況下前面輸入殘留的數據是沒有用的,所以在進行新一次輸入操作前將緩沖區中所有數據清空是比較合理。
如:cin.ignore(1024, '\n');
------
posted on 2009-07-21 15:18
luis 閱讀(1684)
評論(0) 編輯 收藏 引用 所屬分類:
格式.輸入輸出.數據類型