0

我得到一个由逗号分隔的 n 个整数的输入字符串(例如“23,4,56”)。我需要设置一个字符串流来表示这个字符串,然后用它将每个整数扫描成一个向量。向量的元素(列表中的整数)最终将逐行输出。我得到了 main(),并且只负责编写 parseInts(string str)。出于某种原因,我一直在超时。我猜这是我的 while 循环中的一些东西,特别是关于我如何使用 str() 操作我的 sstream,但我无法弄清楚到底发生了什么。我是 sstream 和 C++ 的新手,所以任何帮助都将不胜感激!

#include <sstream>
#include <vector>
#include <iostream>
using namespace std;

vector<int> parseInts(string str) {
    int a; //will use this to hold the value of the 1st int in the sstream
    stringstream list_initial; //will iterate over this sstream
    list_initial.str(str); //set sstream to represent input str
    vector<int> list_final; //will return this final vector for output in main
    while (!list_initial.str().empty()){ //stop iterating at end of string
        list_initial>>a; //store leading int value in a
        list_final.push_back(a); //add a to end of vector
        while (!ispunct(list_initial.str()[0])){ //get to next int in list
            list_initial.str(list_initial.str().erase(0,1));
        };
        list_initial.str(list_initial.str().erase(0,1)); //erase leading comma
    };
    return list_final;   
};

int main() {
    string str;
    cin >> str;
    vector<int> integers = parseInts(str);
    for(int i = 0; i < integers.size(); i++) {
        cout << integers[i] << "\n";
    }

    return 0;
}
4

2 回答 2

0

流是一个抽象文件。它只是一堆可以理解的文本,例如,cin >> n将数字转换为整数。

以下是如何使用流的想法:

#include <cctype>
#include <ciso646>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

vector<int> parse_ints( const string& s )
{
  vector<int> ints;     // resulting list of ints
  istringstream ss(s);  // stream of ints separated by (non-digits)
  int n;                // each int extracted from the stream

  // while input an int
  while (ss >> n)
  {
    // save the int
    ints.push_back(n);

    // skip to next digit
    while (ss and !isdigit(ss.peek())) ss.get();
  }

  return ints;
}

int main()
{
  vector<int> xs = parse_ints( "2, 3 ,5; 7 : 11.13\t17abc21" );
  for (int x : xs)
    cout << x << " ";
  cout << "\n";
}

这会产生:

2 3 5 7 11 13 17 21

注意我们如何可以简单地跳过我们不感兴趣的字符?在这种特殊情况下,我们跳过所有非数字字符。

希望这可以帮助。

于 2015-11-29T02:00:42.543 回答
0

while如果您替换第二行,则可以真正改进您的功能实现,但遵循您的逻辑:

        while (!ispunct(list_initial.str()[0])){ //get to next int in list

通过这个,添加一个长度检查:

        while (list_initial.str().size() && !ispunct(list_initial.str()[0])){ //get to next int in list

,然后运行,运行良好并且退出良好。

解释

这个循环从未中断,因为在过程结束时,ispunct()函数从未将其参数识别!list_initial.str()[0]为真:此时字符串list_initial.str()为空,则0索引不存在。
请查看cplusplus.com上的文档:

如果 pos 等于字符串长度,则 const-version 永远不会抛出异常(无抛出保证)。
否则,它会导致未定义的行为。

您的程序被冻结,因为它没有找到可能导致离开上述循环的正确条件。

建议

谈论您的问题的一件重要事情是:为什么您自己没有找到答案?这个问题的一个答案如下:您没有尝试调试您的代码。

为了回答您的问题,我刚刚调试了您的代码,并通过在您的代码周围添加这种行来快速发现问题,看看发生了什么:

cout << "list_initial: " << list_initial.str() << endl;

您的代码示例,添加了调试语句:

#include <sstream>
#include <vector>
#include <iostream>
using namespace std;

vector<int> parseInts(string str) {
    cout << "begin parseInts()" << endl;  // ######  DEBUG  ######

    int a; //will use this to hold the value of the 1st int in the sstream
    stringstream list_initial; //will iterate over this sstream
    list_initial.str(str); //set sstream to represent input str
    vector<int> list_final; //will return this final vector for output in main

    cout << "begin while 1" << endl;  // ######  DEBUG  ######
    while (!list_initial.str().empty()){ //stop iterating at end of string
        list_initial >> a; //store leading int value in a
        list_final.push_back(a); //add a to end of vector

        cout << "a: " << a << endl;  // ######  DEBUG  ######
        cout << "begin while 2" << endl;  // ######  DEBUG  ######
        while (!ispunct(list_initial.str()[0])){ //get to next int in list

            cout << "list_initial: " << list_initial.str() << endl;  // ######  DEBUG  ######

            list_initial.str(list_initial.str().erase(0,1));
        };
        cout << "endwhile 2" << endl;  // ######  DEBUG  ######

        list_initial.str(list_initial.str().erase(0,1)); //erase leading comma
    };
    cout << "endwhile 1" << endl;  // ######  DEBUG  ######

    cout << "end parseInts()" << endl;  // ######  DEBUG  ######

    return list_final;   
};

int main() {
    string str;
    cin >> str;
    vector<int> integers = parseInts(str);

    cout << "begin for" << endl;  // ######  DEBUG  ######
    for(int i = 0; i < integers.size(); i++) {
        cout << integers[i] << "\n";
    }
    cout << "end for" << endl;  // ######  DEBUG  ######

    return 0;
}

这种(非常基本的)调试技术允许您快速找出代码中的错误;只需cout << ... << endl;在代码中添加几行以指出一些重要信息,即:“哪个循环导致冻结?”或“此时此变量的内容是什么?”。

如果您在每个可疑循环cout << "Entering While loop 1" << endl;之前和cout << "Exiting While loop 1" << endl;之后放置,您可能会了解有关程序执行期间发生的许多事情。

添加此调试行后,您可以轻松发现第二个循环永远循环;然后你可以将你的错误调查缩小到这个循环。

于 2015-11-26T01:19:47.970 回答