题目描述
代码
#include <iostream>
#include <stdexcept>
using std::cin;
using std::cout;
using std::endl;
using std::istream;
istream &func(istream &);
int main()
{
cout << "请输入一些整数,按CTRL+Z结束:" << endl;
func(cin);
return 0;
}
istream &func(istream &in)
{
int i;
while (in >> i, !in.eof())
{
if (in.bad())
throw std::runtime_error("IO流错误");
if (in.fail())
{
std::cerr << "数据错误,请重试: " << endl;
in.clear();
in.ignore(100, '\0');
continue;
}
cout << i << endl;
}
in.clear();
return in;
}
若想了解istream类的成员函数ignore()的用法,点击这里
测试用例及分析
输入:
10 20 30
输出:
分析:
- 主函数创建一个cin对象,读入数据“10 20 30”,cin传递至func函数的形参in
- “>>”操作符抽取出in对象中的第一个数10,将10写入变量i中,写入时未发生错误,输出i,此时in对象中剩余数据为“20 30”
- 再次循环,“>>”操作符抽取中in对象的第一个数据20,将20写入变量i中,写入时未发生错误,输出i,此时in对象中剩余数据为“30”
- 重复上述过程,输出in对象中的最后一个数30
- in对象中的数据全部读完后,再读入新的数据,重复上述过程,直到遇到文件结束符(windows系统中CTRZ+Z代表文件结束符)
输入:
10 20 30a123456
输出:
分析:
- 输出10、20、30的过程与前面描述的类似
- 30输出完毕后,in对象中剩余数据为“a123456”
- 当再次进入循环时,in对象依旧向int型对象i中写入数据,但是由于数据类型不匹配,in的failbit标志位发生改变,进入第二个if语句,输出错误信息,然后将in对象状态位置为合法状态,执行in.ignore语句后,in对象中的数据被全部忽略(需要注意的是,当我们输入数据时,会在最后敲个回车,因此in对象的数据中最后一个字符位’\n’)
- in对象数据为空,再输入新的数据,重复上述过程
修改代码
in.ignore(2, '\0');//将100改为2
输入:
10 20 30a123456
输出:
分析:
- 输出10、20、30的过程如前所述,此时in对象中的剩余数据为“a123456”
- 再次进入循环,in对象的failbit标志位被设置,进入第二个if语句,再将in对象的状态置为合法,再执行ignore函数,越过两个字符,此时in对象中的数据变为“23456”(a和1被越过)
- continue,开始执行下一次循环
- in对象向变量i中写入数据123456,合法,输出变量i的值
- in对象数据为空,再输入数据,重复上述过程
注意
代码中的ignore函数那一行代码不能去掉,如果去掉,当in对象遇到不合法输入,重置标志位,continue,进行下次循环,此时,该非法输入依旧存在,无限循环