3

最近我需要一个简单的程序来对标准输入上出现的所有整数求和,每行一个整数。输入碰巧包含一些未设置的行,其中包含一个减号 ('-') 符号,以及一些带有垃圾字符的行(将被忽略)。

我相信这将是一个微不足道的程序。但事实证明,单个减号并没有表现得像其他错误输入。在正常的非整数输入上,设置失败标志并且错误输入保留在输入缓冲区中。但是对于单个减号(或加号),设置了失败标志,但删除了 +/- 号,导致程序跳过下一个(有效)整数(导致错误的总和)。

我写了一个小测试程序(如下)来分析行为。上述带有 +/- 符号的行为是错误还是功能?

#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;
}
4

2 回答 2

2

这是一个特点。cin直到它读取了“-”之后的空格才知道输入错误。没有可移植的方式使用 iostreams 放回一个以上的字符,也没有可移植的方式在 cin 中查找。所以它被卡住了,必须将“-”保留为已读。

读取数据时有一点需要您自己进行解析。将所有数据读入字符串,然后自己解析这些字符串以确定什么是真实的,什么是垃圾。这样您就可以完全控制而不是与 iostream 所做的任何事情作斗争。

于 2013-03-16T19:09:01.257 回答
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;
}
于 2013-03-16T19:11:11.127 回答