Чтение каждой строки из текстового файла, слово за словом и преобразование в int (бесконечное l oop или сбой?) - PullRequest
0 голосов
/ 30 января 2020

Я пытаюсь прочитать в этом текстовом файле:

8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4 
9 4 3 9 9
8 2 1 5 4 
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8 
11 2 11 10 7

И распечатать его точно так, как показано на консоли (чтобы убедиться, что я получил каждый ввод).

Однако, по какой-то причине мой код вылетает после чтения в первой строке. Я даже не могу прекратить отладчик.

Вот мой код:

while(getline(inFile, buffer)){
    buffer2 = strdup(buffer.c_str());
    line = strtok(buffer2, " ");
    size = atoi(line);
    cout << size << " ";

    while(line!=NULL){
        line = strtok(NULL, " ");
        cout << line << " ";
    }

    cout << "~~~~~~~~~" << endl;
}

Ответы [ 3 ]

2 голосов
/ 30 января 2020

Если вы собираетесь использовать C ++, вы должны воспользоваться этим, использовать строковые потоки:

#include <fstream>
#include <sstream>
#include <iostream>


using namespace std; //for sample purposes, should not be used

int main() {

    int temp, count = 0, sum = 0, total = 0;
    string buffer;
    ifstream myFile("in.txt");
    if (!myFile.is_open())
        cout << "No file" << endl;
    else{
        while(getline(myFile, buffer)){
            sum = 0;
            stringstream ss(buffer);
            while(ss >> temp){
                count++;         //number count            
                sum += temp;     //line sum
                cout << temp << " ";
            }
            total += sum;   //total sum
            cout << endl << "count: " << count <<  endl
                << "sum: " << sum << endl << "total: " << total << endl << endl;
        }
    myFile.close();
    }
    cout << "~~~~~~~~~" << endl;  
}
1 голос
/ 30 января 2020

Как всегда, существует множество возможных решений. Я хотел бы показать еще один. Для этого используются более современные элементы C ++, в основном из библиотеки алгоритмов и итераторов.

Итак, что мы будем делать?

Сначала мы читаем каждую строку как std::string в простом для l oop с std::getline. Затем мы снова поместим строку в std::istringstream, чтобы мы могли воспользоваться итератором C ++: std::istream_iterator.

Этот итератор будет перебирать элементы в строке и извлекать все целые числа. Это похоже на вызов оператора экстрактора (>>) для всех элементов в строке.

Мы используем итератор в так называемом конструкторе диапазона в os a std::vector. Этот вектор, созданный на месте, будет добавлен к данным описания. Таким образом, в результате мы получим вектор вектора типа int: 2-мерный вектор.

В целях отладки мы копируем каждую строку значений в std::cout.

Обратите внимание что нам действительно нужно всего лишь несколько очень простых заявлений для выполнения задачи.

Пожалуйста, проверьте.

#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
#include <iterator>

std::istringstream sourceFile{R"(8 4 4 6 1
8 4 4 6 2
8 4 4 6 3
8 4 4 6 4
8 4 4 6 5
8 4 4 6 6
8 4 4 6 7
8 4 4 6 8
11 4 4 6 3
15 11 13
7 2 1 4 4 
9 4 3 9 9
8 2 1 5 4 
10 1 2 3 4 6 1
6 1 1 2 5 3 2
13 1 1 2 10 3 8 
11 2 11 10 7)"};

int main()
{
    // Here we will store the resulting int values
    std::vector<std::vector<int>> data{};

    for (std::string line{}; std::getline(sourceFile, line); ) {

        // Split the line into integers and add to target array
        std::istringstream iss(line);
        data.emplace_back(std::vector<int>(std::istream_iterator<int>(iss), {}));
    }       

    // Now all data is in our vector of vector of int

    // Show read data on screen
    std::for_each(data.begin(), data.end(), [](const std::vector<int>& v){ 
        std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << "\n";});

    return 0;
}

Пожалуйста, обратите внимание. У меня нет файлов на SO. Поэтому я использовал std::istringstream в качестве входного потока. Конечно, вы можете обменять его на любой другой std::ftream

1 голос
/ 30 января 2020

Вы просачиваете память, выделенную strdup(). Вам нужно позвонить free(), когда вы закончите, используя buffer2.

Но, что более важно, strtok() возвращает NULL, когда больше нет токенов для возврата. Но это неопределенное поведение для передачи указателя NULL char* на operator<<. Ваш while l oop делает именно это, когда достигает конца каждой строки, поэтому может произойти все, что угодно , включая сбой.

Попробуйте вместо этого:

while (getline(inFile, buffer)) {
    buffer2 = strdup(buffer.c_str());
    if (buffer2 != NULL) {
        line = strtok(buffer2, " ");
        while (line != NULL) {
            size = atoi(line);
            cout << size << " ";
            line = strtok(NULL, " ");
        }
        free(buffer2);
    }
    cout << "~~~~~~~~~" << endl;
}

Как говорится, почему вы вообще используете strdup(), strtok() и atoi()? Вы пишете код на C ++, вам следует использовать семантику C ++ вместо C семантики. Например, вместо этого вы можете использовать std::istringstream, например:

while (getline(inFile, buffer)) {
    istringstream iss(buffer);
    while (iss >> size) {
        cout << size << " ";
    }
    cout << "~~~~~~~~~" << endl;
}
...