Почему я получаю тайм-аут (используя sstream для анализа списка целых чисел, разделенных запятыми)?

Мне дают входную строку из n целых чисел, разделенных запятыми (например, "23,4,56"). Мне нужно установить поток строк для представления этой строки, а затем использовать его для сканирования каждого целого числа в вектор. Элементы вектора (целые числа в списке) будут выводиться построчно. Мне дано main(), и я просто отвечаю за написание parseInts(строка str). По какой-то причине я продолжаю получать тайм-аут. Я предполагаю, что это что-то в моих циклах while, особенно относительно того, как я манипулирую своим потоком с помощью str(), но я не могу точно понять, что происходит. Я новичок в 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;
}

2 ответа

Реализация вашей функции может быть действительно улучшена, но следуя вашей логике, если вы замените второй 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-версия никогда не генерирует исключения (гарантия без бросков).
В противном случае это вызывает неопределенное поведение.

Ваша программа зависла, потому что она не нашла правильное условие, которое могло привести к выходу из вышеуказанного цикла.

Советы

Важно поговорить о вашем вопросе: почему вы сами не нашли ответ? Один из ответов на этот вопрос следующий: вы не пытались отлаживать свой код.

Чтобы ответить на ваш вопрос, я просто отладил ваш код и быстро нашел проблему, просто добавив такие строки вокруг кода, чтобы увидеть, что произошло:

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; после каждого предполагаемого цикла вы можете многое узнать о том, что происходит во время выполнения вашей программы.

После добавления этих строк отладки вы можете легко обнаружить, что второй цикл зацикливается вечно; тогда вы можете сузить свое расследование ошибок до этого цикла.

Поток - это абстрактный файл. Это просто набор текста, который можно понять с помощью таких вещей, как, например, 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

Заметьте, как мы можем просто пропустить символы, которые нам не интересны? В данном конкретном случае мы пропускаем все нецифровые символы.

Надеюсь это поможет.

Другие вопросы по тегам