Многочисленные ошибки преобразования при попытке загрузить текстовый файл в связанный список - PullRequest
0 голосов
/ 11 февраля 2019

Я пытаюсь загрузить текстовый файл со значениями: 10 11 12 13 14 15 16 17 18 19 20 30 40 50 55 60 70 80 90 91 92 93 94 95 96 97 98 99 в связанный список, вставляякаждое новое значение в конце списка.Проблема, с которой я столкнулся, заключается в том, что когда я запускаю код, я получаю сообщение об ошибке, что пытаюсь запустить строку через функцию, которая ожидает int, что имеет смысл, но как только я добавил stoi() в микс дляпреобразовав значения в int, я начал получать сумасшедшие ошибки.

Я работал над этой функцией в течение последнего дня или около того, и ни один из моих поисков не дал никаких результатов.Я чувствую, что я довольно близок с этим, но я, вероятно, скучаю по чему-то большому здесь.Все еще довольно плохо знакомы со связанными списками в целом, мы только что узнали о них в классе на прошлой неделе.

#include <iostream>
#include <fstream>
#include <string>
#include "linkedlist.h" // Has the prototypes for each function
using namespace std;
// I didn't include a lot of functions since I don't think they're
// related to the error, but let me know if I should

Node* createNewNode(int data) {
    Node *ptr;
    Node *temp = new Node();
    temp -> data = data;
    temp -> next = NULL;
    ptr = temp;
    return ptr;
}

Node* createNewList() {
    Node *head = NULL;
    return head;
}

Node* load(string filename) {
    Node *head = createNewList();
    string num;
    ifstream myfile(filename.c_str());
    while(myfile >> num) { // looping through each number
        int num1 = stoi(num); // Converting string to int
        myfile << insertAtEnd(head, num1);      
    }
    return head;
}

void insertAtEnd(Node *list, int data) {
    Node *ptr = createNewNode(data);
    if (list == NULL) {
        list = ptr;
     }
     else { 
         Node *temp = list;
         while(temp -> next != NULL) {
             temp = temp -> next;
         }
         temp -> next = ptr;
    }
}

int main() {
    load("../resource/listdata.txt"); // name/location of the file
    //No errors from rest of code but I can post if necessary
}

Слишком много ошибок, чтобы я мог просто вставить их сюда, но я сделал скриншот большинстваиз них здесь: https://i.imgur.com/GtXZ5oy.png.

Заранее благодарю за любую помощь, которую вы можете мне оказать!

Исправления:

Node* load(string filename) {
    Node *head = createNewList();
    string num;
    ifstream myfile(filename.c_str());
    while(myfile >> num) { // looping through each number
        int num1 = stoi(num); // Converting string to int
        insertAtEnd(head, num1);      
    }
    myfile.close();
    return head;
}

Больше нет ошибок компиляции, хотя при выполнении кода он выдает: 0 0 NULL exit status -1

Если бы мне пришлось угадывать, я бы предположил, что моя проблема теперь в области while(myfile >> num), потому что я не думаю, что код правильно пересекает текстовый файл и использует числа, хотя яЯ не уверен в этом.

Редактировать 2:

Node *load (string filename) {
  Node *head;
  string num;
  ifstream myfile(filename.c_str());
  while(myfile >> num) {
    if(head) {
      int num1 = stoi(num);
      insertAtEnd(head, num1);
    } 
    else {
      head = createNewList();
      int num1 = stoi(num);
      head = createNewNode(num1);
    }
  }
  myfile.close();
  return head;
}

Я надеюсь, что я правильно следовал инструкциям, хотя есть хороший шанс, что я не ... Яполучить то же сообщение, что и выше, с 0 0 NULL exit status -1, но без ошибок, что хорошо и плохо, так как я бы хотел увидеть, что сейчас не работает.

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Я бы создал класс для отслеживания head и всех функций, относящихся к одному списку узлов.Я назову это NodeList.Я бы также добавил указатель на последний узел в списке для удобства и скорости.

#include <iostream>
#include <fstream>
#include <string>

struct Node {
    Node* next;
    int data;
};

class NodeList {
    Node* head;
    Node* last;
public:
    // default constructor - an empty list
    NodeList() : head(nullptr), last(nullptr) {}

    // construction using a filename
    NodeList(const std::string& filename) : NodeList() {
        load(filename);
    }

    // deleted copy & move ctors and assignment operators for simplicity
    NodeList(const NodeList&) = delete;
    NodeList(NodeList&&) = delete;
    NodeList& operator=(const NodeList&) = delete;
    NodeList& operator=(NodeList&&) = delete;

    // destructor    
    ~NodeList() {
        clear();
    }

    // go through all Nodes and delete them
    void clear() {
        Node* curr = head;
        Node* next;
        while(curr) {
            next = curr->next;
            delete curr;
            curr = next;
        }
        head = nullptr;
        last = nullptr;
    }

    // load data from a file
    void load(const std::string& filename) {
        clear();
        append(filename);
    }

    // append data from a file
    void append(const std::string& filename) {
        std::ifstream is(filename);
        is >> *this;   // using operator>> further down
    }

    // find a node by value      
    Node* find(int data) const {
        Node* curr = head;
        while(curr && curr->data != data) curr = curr->next;
        return curr;
    }

    // add a node last in the list    
    Node* add(int data) {
        Node* nn = new Node{nullptr, data};
        if(last) { last->next = nn; last = nn; }
        else { head = last = nn; }
        return nn;
    }

    // delete a node by supplying a Node*    
    void del(Node* n) { // delete a certain node
        if(n==nullptr) return;

        if(head==n) {
            if(last==n) head = last = nullptr;
            else head = head->next;
        } else {
            Node* curr = head;
            do {
                if(curr->next==n) {
                    curr->next = n->next;
                    break;
                }
                curr = curr->next;
            } while(curr);
        }
        delete n;
    }

    void del(int data) { // delete a Node by value
        del(find(data));
    }

    // operator>> to populate the NodeList from an istream
    friend std::istream& operator>>(std::istream&, NodeList&);

    // operator<< to stream all values in the NodeList to an ostream
    friend std::ostream& operator<<(std::ostream&, const NodeList&);
};

// add nodes from stream
std::istream& operator>>(std::istream& is, NodeList& nl) {
    int tmp;
    // no need for std::stoi(), just stream into an int
    while(is >> tmp) nl.add(tmp);
    return is;
}

// output nodes to stream
std::ostream& operator<<(std::ostream& os, const NodeList& nl) {
    Node* curr = nl.head;
    while(curr) {
        os << curr->data << " ";
        curr = curr->next;
    }
    return os;
}

int main() {
    NodeList nl("listdata.txt");
    std::cout << nl << "\n";

    Node* p = nl.find(40);
    nl.del(p);  // delete the Node found above
    nl.del(10); // delete the first Node
    nl.del(99); // delete the last Node

    std::cout << nl << "\n";
}

Вывод (учитывая данные в вашем посте):

10 11 12 13 14 15 16 17 18 19 20 30 40 50 55 60 70 80 90 91 92 93 94 95 96 97 98 99
11 12 13 14 15 16 17 18 19 20 30 50 55 60 70 80 90 91 92 93 94 95 96 97 98
0 голосов
/ 12 февраля 2019

Ваш код показывает хорошую мысль, поэтому учтите: указатель head должен указывать на ведущий элемент списка, не так ли?Однако единственные строки в вашем коде, которые присваивают значение head, присваивают NULL (должно быть nullptr, между прочим).

Это было бы проблемой.

С момента изменениятип возврата insertAtEnd() в вашей задаче запрещен, мы должны вызывать эту функцию только тогда, когда head уже имеет значение, как

    if (head != nullptr) {
        // call insertAtEnd()
    }
    else {
        // do something to start the list and, incidentally,
        // to assign a value to head
    }

На самом деле, это способ написания для начинающих.Более бегло бы было

    if (head) {
        // ...

, что означает то же самое.

В любом случае, если вы сделаете это таким образом, вы можете и, вероятно, должны сделать свою функцию insertAtEnd() более простой, потому что она не будетбольше нужно обрабатывать случай пустого списка.

[...]

Теперь вы поработали еще немного.Ваш вывод все еще не то, что вы ожидаете, так как его отладить?Если у вас есть проблема, но вы не знаете, где в вашем коде ошибка, как вы должны ее локализовать?То есть, как вы должны выяснить, по какой линии возникает проблема?Программа слишком большая, чтобы найти проблему, просто взглянув на код!

Для отладки я бы попробовал что-то вроде этого:

Node *load (string filename) {
  Node *head;
  string num;
  ifstream myfile(filename.c_str());
  cerr << "diagn 100\n";
  while(myfile >> num) {
    cerr << "diagn 150\n";
    if(head) {
      cerr << "diagn 200, head == " << head << "\n";
      int num1 = stoi(num);
      insertAtEnd(head, num1);
      cerr << "diagn 250\n";
    } 
    else {
      cerr << "diagn 300, head == " << head << "\n";
      head = createNewList();
      cerr << "diagn 325, head == " << head << "\n";
      int num1 = stoi(num);
      head = createNewNode(num1);
      cerr << "diagn 350, head == " << head << "\n";
    }
  }
  myfile.close();
  cerr << "diagn 900, head == " << head << "\n";
  return head;
}

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

(Кстати, «диагноз» означает «диагностика». Мне нравится «диагностика», потому что нетдругое английское слово, которое я использую, содержит эти буквы, поэтому его легко найти в тексте программы.)

Что касается потока ошибок, std::cerr, он по умолчанию отправляет вывод в то же место, что и std::cout.Тем не менее, можно перенаправить один поток или другой, или оба, отправив два в разные места.Точный способ переадресации зависит от того, какую систему (Debian, Windows, OSX и т. Д.) Вы используете, но переадресацию обычно не составляет труда.

...