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()更精确控制缓冲区。

猜你喜欢

转载自blog.csdn.net/josephpai/article/details/78896235