今天看完一篇牛人博文,受益匪淺,小記一下。原文更詳細(xì)http://blog.csdn.net/lewsn2008/archive/2008/04/16/2295790.aspx
首先我們呢看一下輸入操作的原理, 程序的輸入都建有一個(gè)緩沖區(qū),即輸入緩沖區(qū)。一次輸入過程是這樣的,當(dāng)一次鍵盤輸入結(jié)束時(shí)會(huì)將輸入的數(shù)據(jù)存入輸入緩沖區(qū),而cin等輸入輸出函數(shù)直接從輸入緩沖區(qū)中取數(shù)據(jù)。正因?yàn)閏in等輸入輸出函數(shù)是直接從緩沖區(qū)取數(shù)據(jù)的,所以有時(shí)候當(dāng)緩沖區(qū)中有殘留數(shù)據(jù)時(shí),cin函數(shù)會(huì)直接取得這些殘留數(shù)據(jù)而不會(huì)請(qǐng)求鍵盤輸入。
---------------
1,要注意不同的函數(shù)是否接受空格符、是否舍棄最后的回車符的問題!
讀取字符時(shí):
scanf()以Space空格、Enter、Tab結(jié)束一次輸入,不會(huì)舍棄最后的回車符(即回車符會(huì)殘留在緩沖區(qū)中),(區(qū)別讀字符串時(shí)會(huì)清楚)//所以可以用getchar()清除;
getchar()以Enter結(jié)束輸入,也不會(huì)舍棄最后的回車符;
讀取字符串時(shí):
scanf()以Space、Enter、Tab結(jié)束一次輸入,會(huì)舍棄最后的回車符(區(qū)別讀字符時(shí))和所有的空格等等。
gets()以Enter結(jié)束輸入(空格不結(jié)束),接受空格,會(huì)舍棄最后的回車符!
第二:為了避免出現(xiàn)上述問題,必須要清空緩沖區(qū)的殘留數(shù)據(jù),可以用以下的方法解決:
方法1:C語(yǔ)言里提供了函數(shù)清空緩沖區(qū),只要在讀數(shù)據(jù)之前先清空緩沖區(qū)就沒問題了!
這個(gè)函數(shù)是fflush(stdin)。
方法2:自己取出緩沖區(qū)里的殘留數(shù)據(jù)。
scanf("%[^\n]",string);
-------------------------
cin的學(xué)問
一. cin<<
該操作符是根據(jù)后面變量的類型讀取數(shù)據(jù)。
輸入結(jié)束條件 :遇到Enter、Space、Tab鍵。(這個(gè)很重要!)
對(duì)結(jié)束符的處理 :清楚緩沖區(qū)中使得輸入結(jié)束的結(jié)束符(Enter、Space、Tab)
(這里有一點(diǎn)問題,
int i;
char c[100];
cin>>i;
cin.getline(str,100);
cout<<str;
如果輸入是:12 adjf回車
輸出將先是空格然后adjf;
如果輸入是:12回車adjf回車
輸出將是adjf.
看來cin>>要在連用時(shí),比如cin>>a>>b;或者cin>>a;cin>>b消除空格能力才體現(xiàn)。
)
二.cin.get()
該函數(shù)有三種格式:無(wú)參,一參數(shù),二參數(shù)
即cin.get(), cin.get(char ch), cin.get(array_name, Arsize)
(i)讀取字符的情況:
輸入結(jié)束條件:Enter鍵(遇空格不結(jié)束)
對(duì)結(jié)束符處理:不丟棄緩沖區(qū)中的Enter
cin.get() 與 cin.get(char ch)用于讀取字符,他們的使用是相似的,
即:ch=cin.get() 與 cin.get(ch)是等價(jià)的。
測(cè)試程序:
#include <iostream>
using namespace std;
int main()
{
char c1, c2;
cin.get(c1);
cin.get(c2);
cout<<c1<<" "<<c2<<endl; // 打印兩個(gè)字符
cout<<(int)c1<<" "<<(int)c2<<endl; // 打印這兩個(gè)字符的ASCII值
return 0;
}
測(cè)試一輸入:
a[Enter]
輸出:
a
97 10
【分析】會(huì)發(fā)現(xiàn)只執(zhí)行了一次從鍵盤輸入,顯然第一個(gè)字符變量取的'a', 第二個(gè)變量取的是Enter(ASCII值為10),這是因?yàn)樵摵瘮?shù)不丟棄上次輸入結(jié)束時(shí)的Enter字符,所以第一次輸入結(jié)束時(shí)緩沖區(qū)中殘留的是上次輸入結(jié)束時(shí)的Enter字符!
測(cè)試二輸入:
a b[Enter]
輸出:
a
97 32
【分析】顯然第一個(gè)字符變量取的'a', 第二個(gè)變量取的是Space(ASCII值為32)。原因同上,沒有丟棄Space字符。
(ii)讀取字符串的情況:
cin.get(array_name, Arsize)是用來讀取字符串的,可以接受空格字符,遇到Enter結(jié)束輸入,按照長(zhǎng)度(Arsize)讀取字符, 會(huì)丟棄最后的Enter字符。
(i i i)cin.getline()
cin.getline() 與 cin.get(array_name, Arsize)的讀取方式差不多,以Enter結(jié)束,可以接受空格字符。按照長(zhǎng)度(Arsize)讀取字符, 會(huì)丟棄最后的Enter字符。
但是這兩個(gè)函數(shù)是有區(qū)別的:
cin.get(array_name, Arsize)
當(dāng)輸入的字符串超長(zhǎng)時(shí),不會(huì)引起cin函數(shù)的錯(cuò)誤,后面的cin操作會(huì)繼續(xù)執(zhí)行,只是直接從緩沖區(qū)中取數(shù)據(jù)。但是cin.getline()
當(dāng)輸入超長(zhǎng)時(shí),會(huì)引起cin函數(shù)的錯(cuò)誤,后面的cin操作將不再執(zhí)行。(具體原因?qū)⒃谙乱徊糠?cin的錯(cuò)誤處理"中詳細(xì)介紹)
------------
cin的錯(cuò)誤處理
程序執(zhí)行時(shí)有一個(gè)標(biāo)志變量來標(biāo)志輸入的異常狀態(tài),其中有三位標(biāo)志位分別用來標(biāo)志三種異常信息,他們分別是:failbit,eofbit,badbit。這三個(gè)標(biāo)志位在標(biāo)志變量中是這樣分配的:
____________________________________
| 2 | 1 | 0 |
| failbit | eofbit | badbit |
|___________|__________|___________|
看一下這幾個(gè)標(biāo)志位的作用(引用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.
接下來我么看幾個(gè)ios類的數(shù)據(jù)定義(引用msdn):
typedef T2 iostate;
static const iostate badbit, eofbit, failbit, goodbit;
這里ios類定義了這四個(gè)常量badbit, eofbit, failbit, goodbit,其實(shí)這四個(gè)標(biāo)志常量就是取對(duì)應(yīng)標(biāo)志位的掩碼,也即輸入的四種異常情況!
以上四個(gè)常量對(duì)應(yīng)的取值為:
ios::badbit 001 輸入(輸出)流出現(xiàn)致命錯(cuò)誤,不可挽回
ios::eofbit 010 已經(jīng)到達(dá)文件尾
ios::failbit 100 輸入(輸出)流出現(xiàn)非致命錯(cuò)誤,可挽回
ios::goodbit 000 流狀態(tài)完全正常, 各異常標(biāo)志位都為0
如果出現(xiàn)輸入錯(cuò)誤,則cin不再工作,我們可以用cin.clear()重置標(biāo)記位。
測(cè)試程序:
#include <iostream>
using namespace std;
int main ()
{
char ch, str[20];
cin.getline(str, 5);
cout<<"flag1:"<<cin.good()<<endl; // 查看goodbit狀態(tài),即是否有異常
cin.clear(); // 清除錯(cuò)誤標(biāo)志
cout<<"flag1:"<<cin.good()<<endl; // 清除標(biāo)志后再查看異常狀態(tài)
cin>>ch;
cout<<"str:"<<str<<endl;
cout<<"ch :"<<ch<<endl;
return 0;
}
測(cè)試輸入:
12345[Enter]
輸出:
flag1:0 // good()返回false說明有異常
flag2:1 // good()返回true說明,clear()已經(jīng)清除了錯(cuò)誤標(biāo)志
str:1234
ch :5
但是當(dāng)前一次讀取數(shù)據(jù)出錯(cuò)后,如果緩沖區(qū)沒有清空的話,重置錯(cuò)誤標(biāo)志還不夠!要是能將緩沖區(qū)的殘留數(shù)據(jù)清空了就好了哦!下面我們?cè)賮砜匆粋€(gè)很重要的函數(shù)!cin.ignore()
這個(gè)函數(shù)用來丟棄輸入緩沖區(qū)中的字符,第一參數(shù)定義一個(gè)數(shù),第二個(gè)參數(shù)定義一個(gè)字符變量。
例:cin.ignore(5, 'a'); 函數(shù)將不斷從緩沖區(qū)中取一個(gè)字符丟棄,直到丟棄的字符數(shù)達(dá)到5或者讀取的字符為'a'。
其實(shí)該函數(shù)最常用的方式是這樣的,將第一個(gè)參數(shù)設(shè)的非常大,將第二個(gè)參數(shù)設(shè)為'\n',這樣就可以緩沖區(qū)中回車符中的所有殘留數(shù)據(jù),因?yàn)橐话闱闆r下前面輸入殘留的數(shù)據(jù)是沒有用的,所以在進(jìn)行新一次輸入操作前將緩沖區(qū)中所有數(shù)據(jù)清空是比較合理。
如:cin.ignore(1024, '\n');
------
posted on 2009-07-21 15:18
luis 閱讀(1701)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
格式.輸入輸出.數(shù)據(jù)類型