我正在尝试将以下值的文本文件加载: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
,但仍然没有错误,这很好并且不好,因为我很想看看现在不起作用。
答案 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等),但是转移通常并不难。