C++—— 恢复状态标志和清理缓存(以标准库输入流std::cin输入整数时死循环为例)

来源:互联网 发布:淘宝类似威廉的男装店 编辑:程序博客网 时间:2024/05/21 22:35

C++—— 恢复状态标志和清理缓存(以标准库输入流std::cin输入整数时死循环为例)

标准库输入流std::cin输入整数时死循环

本文,主要解决用标准库输入流std::cin输入整数的时候,如果误输入了字符产生的死循环问题。
这也许是C++灵活的背后,给程序员所带来的一些问题。
解决方法比较简单,代码如下:

#include<iostream>#include <limits>// 带容错功能的控制台整数输入函数int input_int(){    int n;    // 处理输入字符时的死循环异常    while (!(std::cin >> n) || std::cin.peek() != '\n')    {        std::cin.clear();// 恢复状态标志        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');// 略过缓存        std::cerr << "输入数据错误,请重新输入:" << std::endl;    }    return n;}int main(){    std::cout << input_int() << " ,输入成功结束" << std::endl;    system("pause");    return 0;}

先搞清楚几个重要的函数:cin.fail(), cin.bad(), cin.good(), cin.clear(), cin.ignore()等。
在搞清楚了这几个函数后,对cin输入操作的错误处理就有了比较深的了解了。
用getline()读取字符串超长,所以导致出现异常,所以会导致后面的 cin>>ch 语句没有执行。

那我们利用前面学习的clear()函数来强制重置错误标志,看看会出现什么情况呢?

#include <iostream>using namespace std;int main (){char ch, str[20];cin.getline(str, 5);cout<<"flag1:"<<cin.good()<<endl;    // 查看goodbit状态,即是否有异常cin.clear();                         // 清除错误标志cout<<"flag1:"<<cin.good()<<endl;    // 清除标志后再查看异常状态cin>>ch; cout<<"str:"<<str<<endl;cout<<"ch :"<<ch<<endl;return 0;}

测试输入:
12345[Enter]
输出:
flag1:0 // good()返回false说明有异常
flag2:1 // good()返回true说明,clear()已经清除了错误标志
str:1234
ch :5

丢弃输入缓冲区中的字符

这个函数用来丢弃输入缓冲区中的字符,第一参数定义一个数,第二个参数定义一个字符变量。下面解释一下函数是怎样执行的:函数不停的从缓冲区中取一个字符,并判断是不是_Delim,如果不是则丢弃并进行计数,当计数达到_Count退出,如果是则丢弃字符退出。例:cin.ignore(5, ‘a’); 函数将不断从缓冲区中取一个字符丢弃,直到丢弃的字符数达到5或者读取的字符为’a’。下面我们看个程序例子:

#include <iostream>using namespace std;int main (){cin.ignore(5, 'a');return 0;}

测试一输入:
c[enter]
c[enter]
c[enter]
c[enter]
c[enter]
程序结束。
【分析】程序开始时缓冲区是空的,cin.ignore()到缓冲区中取数据,没有则请求从键盘输入,每次从键盘输入一个字符,如果不是’a’则丢弃,所以该测试中共输入了5次,直到计数达到5。
测试二输入:
c[enter]
c[enter]
a[enter]
程序结束。
【分析】前面两个字符不是’a’丢弃且计数没达到5,第三次输入为’a’, 丢弃该字符程序结束!

丢弃一个字符:

#include <iostream>using namespace std;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; }

测试一输入:
a[Enter]
b[Enter]
输出:
a
b
97 98
【分析】这样程序就正常了!

清空整个缓冲区:

其实该函数最常用的方式是这样的,将第一个参数设的非常大,将第二个参数设为’/n’,这样就可以缓冲区中回车符中的所有残留数据,因为一般情况下前面输入残留的数据是没有用的,所以在进行新一次输入操作前将缓冲区中所有数据清空是比较合理。
如:cin.ignore(1024, ‘/n’);
或者:cin.ignore(std::numeric_limits::max(), ‘/n’);

阅读全文
0 0
原创粉丝点击