C++與G++編譯器對於cin.sync()的不同表現

期中考的牢騷

最近快要期中考了,臺灣這邊大學的期中考試不同於大陸。

我記得,在北京讀了兩年書,考過期中考的只有高數、大物和英語,成績佔期末總評的10%。
那在這邊呢,幾乎每一門課都是有期中考的,並且,會在期末總評中佔有30%左右的成績(視不同課程而定)。
所以,意味着期中考試也是不能放鬆的,因此最近幾天就進入了考試周狀態。

忘了說,前幾天和學長學姐聊天得知,這邊的期末也不像大陸會有兩週專門拿來考試,而是和期中一樣,就在平日上課時間考。
該佈置的作業也不會因爲考試周而有特殊待遇。也就意味着,考前突擊這種戰略很難使用了。

也難怪剛剛到臺灣的時候,小貓老師就很好奇我讀CS爲什麼還來交流(可能覺得我腦子有泡吧),並且千叮嚀萬囑咐我一定要保重。
剛剛進入期中考試期的時候,小貓老師還特別關照我,讓我一定加油,嗯我的心瞬間涼了半截。

在這樣一個緊張的週末,還是要在四門考試的複習中垂死寫完第五門課程的每週作業。

來看看遇到了什麼問題。

C++ VS G++

在OOP(Object Oriented Programming)本週作業中,我們需要搭建一個RPG遊戲的基本框架。具體實現過程不在贅述。
遊戲,一定是有交互的。在console級別的時候,基本就是那個黑框框,我們通過鍵盤輸入。

涉及到輸入就不可避免的要處理非法輸入(臺灣老師叫做防呆,蠻有意思的),在之前的多次作業中,輸入量較小,我的處理方式是正則表達式。
正則是處理字符串一個很正統的方法,構建PATTERN有點繁瑣,但是一旦構建完成可以高枕無憂。

但是這次的作業,設計到的輸入種類非常的多,如果使用正則的話,可能需要構建較多的PATTERN,所以這次考慮直接操作變量。(雖然這樣好像並沒有簡化代碼)

#include <iostream>

using namespace std;

int main()
{
  int a;
  while(true)
  {
      cout<<"input a integer";
      cin >> a;
      cout << a;
  }
return 0;
}

用這樣一個簡單的程序示例,如果在這程序輸入一個char型或者字符串(即非法輸入),此時,程序陷入死循環。

原因:

當cin嘗試將輸入的字符讀爲int型數據失敗後,會產生一個錯誤狀態–cin.fail().而要用cin讀取輸入流中的數據,輸入流必須處於無錯誤狀態。因此,由錯誤狀態的存在,會一直執行while循環。

解決:

網絡上提供的方法爲:

        while(true)
        {
            cout<<"input a integer";
            cin >> a;
            if(cin.fail()) {
                cout<<"try again!"<<endl;
                cin.clear(); //清除std::cin的錯誤狀態
                cin.sync(); //清空輸入緩衝區
            }
            cout << a;
        }

增加了兩行代碼,cin.clear()是用來更改cin的狀態標示符的,cin.sync()是用來清除緩存區的數據流的。

嘗試

按照該方法,在Visual Studio 2015上進行調試,依舊是死循環。
clear()和sync()失效了。
但是呢,在Dev C++(搭載GNU C++ Complier)進行測試,達到了預期效果。
也就是說這樣的寫法是不通用的。難怪有人說MS的C++是方言。真正的解決方法是什麼的,調用更加嚴謹的函數cin.ignore()(好吧我之前也是不知道的)

對比

cin.sync()和cin.ignor()的比較
sync()的作用就是清除輸入緩衝區。成功時返回0,失敗時badbit會置位,函數返回-1.
另外,對於綁定了輸出的輸入流,調用sync(),還會刷新輸出緩衝區。

但由於程序運行時並不總是知道外部輸入的進度,很難控制是不是全部清除輸入緩衝區的內容。通常我們有可能只是希望放棄輸入緩衝區中的一部分,而不是全部。比如清除掉當前行、或者清除掉行尾的換行符等等。但要是緩衝區中已經有了下一行的內容,這部分可能是我們想保留的。這個時候最好不要用sync()。可以考慮用ignore函數代替。
cin.ignore(numeric_limits::max(),’/n’);//清除當前行
cin.ignore(numeric_limits::max()); //清除cin裏所有內容
不要被長長的名字嚇倒,numeric_limits::max()不過是climits頭文件定義的流使用的最大值,你也可以用一個足夠大的整數代替它。
使用ignore顯然能比sync()更精確控制緩衝區。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章