輸入操作的原理,程序的輸入都建有一個緩沖區,即輸入緩沖區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin函數直接從輸入緩沖區中取數據。正因為cin函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,這就是例子中為什麼會出現輸入語句失效的原因!
cin輸入結束的條件:Enter、Space、Tab。cin對這些結束符的處理:丟棄緩沖區中這些字符。與cin.get()不同。
案例1:
#includeusing 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時,第一個字符串接受輸入的前四個字符,而第二次的輸入操作沒有執行,第二個字符串輸出為空。
案例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呢?
原理如下:
案例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
案例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');