尝试将文本文件加载到链接列表时出现多次转换错误

时间:2019-02-11 20:13:25

标签: c++ struct linked-list text-files

我正在尝试将以下值的文本文件加载: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 :(得分:1)

我将创建一个类来跟踪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

答案 1 :(得分:0)

您的代码显示出很好的思想,因此请考虑:指针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等),但是转移通常并不难。