最近我需要一个简单的程序来对标准输入上出现的所有整数求和,每行一个整数。输入碰巧包含一些未设置的行,包含一个减号(' - ')符号,还有一些带有垃圾字符的行(要忽略)。
我相信,这将是一个微不足道的计划。但事实证明,单个减号不会表现为其他糟糕的输入。在正常的非整数输入上,设置了失败标志,坏输入保留在输入缓冲区中。但是使用单个减号(或加号)设置失败标志,但+/-符号被删除,导致程序跳过下一个(有效)整数(导致错误的总和)。
我写了一个小测试程序(下面)来分析行为。 上述行为+/-是一个错误还是一个特征?
#include <iostream>
using namespace std;
int main()
{
string s;
int n;
while (true)
{
n = -4711;
cin >> n;
cerr << (cin.bad() ? "ERROR: badbit is set\n" : "");
cerr << (cin.fail() ? "ERROR: failbit is set\n" : "");
cerr << (cin.eof() ? "ERROR: eofbit is set\n" : "");
if ( cin.bad() || cin.eof() )
break;
if ( cin.fail() )
{
cin.clear();
cin >> s;
cerr << "ERROR: ignored string '" << s
<< "' (integer is '" << n << "')" << endl;
}
else
{
cout << "OK: read integer '" << n << "'" << endl;
}
}
return 0;
}
运行程序(输入:“1 asdf 2 - 3 + 4 qwer 5”):
~ $ ./a.out
1 asdf 2 - 3 + 4 qwer 5
OK: read integer '1'
ERROR: failbit is set
ERROR: ignored string 'asdf' (integer is '0')
OK: read integer '2'
ERROR: failbit is set
ERROR: ignored string '3' (integer is '0')
ERROR: failbit is set
ERROR: ignored string '4' (integer is '0')
ERROR: failbit is set
ERROR: ignored string 'qwer' (integer is '0')
OK: read integer '5'
(我已经通过读取字符串解决了我原来的问题,并使用带有异常的C ++ 11 stoi来识别错误的输入。)
编辑:如果有人对我原来问题的解决方案感兴趣:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int sum = 0;
string n;
while ( cin >> n )
{
try {
sum += stoi(n);
cout << n << endl;
}
catch (exception& e)
{
cerr << e.what() << " ERROR: '" << n << "' is not a number." << endl;
}
}
cout << sum << endl;
return 0;
}
答案 0 :(得分:2)
这是一个功能。 cin
直到它读取' - '之后的空格才知道输入是错误的。没有可移植的方式使用iostreams来放回多个单个字符,并且没有可移植的方式来查找cin。所以它被卡住了,不得不把' - '留下来。
在阅读数据时,有一点是对自己的解析更好。将所有数据读入字符串,然后自己解析这些字符串以确定什么是真实的以及什么是垃圾。这样你就可以完全控制而不是与iostream所做的任何事情作斗争。
答案 1 :(得分:1)
我会这样做:
#include <locale>
#include <sstream>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
struct number_only: std::ctype<char> {
number_only() : std::ctype<char>(get_table()) {}
static mask const *get_table() {
static std::vector<mask> rc(table_size, space);
std::fill_n(&rc['0'], 10, digit);
return &rc[0];
}
};
int main() {
std::string input("1 asdf 2 - 3 + 4 qwer 5 ");
std::istringstream x(input);
// use our ctype facet:
x.imbue(std::locale(std::locale(), new number_only));
// initialize vector from the numbers in the file:
std::vector<int> numbers((std::istream_iterator<int>(x)),
std::istream_iterator<int>());
// display what we read:
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}