我正在从文件中读取行并将其存储到链接列表中。
void add(llist *list, somevalue) {
Node *newnode = (Node *) malloc(sizeof(Node));
newnode->value = somevalue;
newnode->next = list->head;
list->head = newnode;
}
我从初始化函数调用此函数,该函数打开文件并从文件中读取行。
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
我意识到的另一个问题是,每当我尝试打印值时,值都会被连接起来。也就是说,输出将是:
First Loop: Tony
Second Loop: Peter
TonyPeter
Third Loop: Mir
PeterMir
TonyPeterMir
如何解决此问题,以便添加功能将节点永久添加到链接列表中?
为什么这些价值会像那样混乱?
---- ---- EDITED
列表是一个全局变量,这里有一些来自init函数的片段。这是带有问题的while循环:
//open file
//initialize & declare pointers
while (1) {
for (i = 0; i < max; i++) {
value[i] = '\0';
}
if (!(fgets(value,max,f))) {
//segfaults if I try to print out the list inside this block.
break;
}
add(list, value);
//the values are well separated in this statement
printf("id is %s\n", list->head->value);
//This print list works, but works weird as shown above.
print_list(list);
}
fclose(f);
//This print list doesn't work, the list is NULL
print_list(list);
这是打印列表功能:
void print_users(llist *list) {
ListNode *e;
if (list->head == NULL) {
printf("NO USERS\r\n");
return;
}
e = list->head;
while (e != NULL) {
puts(e->id);
e = e->next;
}
}
答案 0 :(得分:0)
所以我对你正在尝试做的事情一点都不了解,所以我们只能这么做。您可以考虑发布MCVE。但是,我可以给你一些关于构建链表的指示。我直接将你的add
函数复制到我刚刚建立的链表类中,并且它工作正常,因此llist
类中可能还有其他东西导致了问题,或者它可能是代码中的其他内容。下面列出了班级和班级的简要说明。
基本节点类
注意:我使用了模板,但您可以轻松删除模板语句并将T
替换为任何类型。
template<typename T>
class node {
private:
T data;
node* next;
public:
// The C++11 rule of 5
// Default Constructor
node(T value = T(), node* nxt = nullptr) : data(value), next(nxt) { }
// Copy Constructor
node(const node<T>& src) : data(src.data), next(src.next) { }
// Move Constructor
node(node<T>&& src) : data(src.data), next(src.next) {
src.data = T();
src.next = nullptr;
}
// Copy Assignment Operator
node<T>& operator=(const node<T>& src) {
this->data = src.data;
this->next = src.next;
return(*this);
}
// Move Assignment Operator
node<T>& operator=(node<T>&& src) {
this->data = src.data;
this->next = src.next;
src.data = T();
src.next = nullptr;
}
// Destructor
~node() {};
// Some functions to help with encapsulation
void set_next(node* nxt) {
this->next = nxt;
}
void set_data(T value) {
this->data = value;
}
node* get_next() {
return(this->next);
}
T& get_data() {
return(data);
}
};
链接列表类正文 由于您使用的是动态内存,因此您需要确保遵守3 or 5规则,具体取决于您是否使用C ++ 11。
template<typename T>
class llist {
private:
node<T>* head;
public:
llist();
llist(const llist& src);
llist(llist&& src);
llist(~llist);
llist& operator=(const llist& src);
llist& operator=(llist&& src);
void push();
void insert();
};
默认构造函数 没什么好看的。
template<typename T>
llist<T>::llist() : head(nullptr) { }
复制构造函数 由于您使用的是动态内存,因此这是至关重要的
template<typename T>
llist<T>::llist(const llist& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
}
移动构造函数
template<typename T>
llist<T>::llist(llist&& src) {
// delete current nodes
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
// steal the sources list
this->head = src.head;
src.head = nullptr;
}
<强>析强>
template<typename T>
llist<T>::~llist() {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
}
复制分配运算符
template<typename T>
llist& llist<T>::operator=(const llist<T>& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
return(*this);
}
移动作业运算符
template<typename T>
llist& llist<T>::operator=(llist<T>&& src) {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
this->head = src.head;
src.head = nullptr;
return(*this);
}
推送会员
这与您的add
成员基本相反。
template<typename T>
void llist<T>push(T data) {
node<T>* new_node = new node<T>(data);
if(this->head) {
node<T>* tmp = this->head;
while(tmp->get_next()) {
tmp = tmp->get_next();
}
tmp->set_next(new_node);
} else {
this->head = new_node;
}
}
插入成员
这基本上是您的add
成员。
template<typename T>
void llist<T>insert(T data) {
node<T>* new_node = new node<T>(data, this->head);
this->head = new_node;
}
我不知道这是否会有所帮助,你可能已经知道了大部分内容,但我希望它有所帮助。
答案 1 :(得分:0)
在此代码中,您似乎试图为“llist”用户定义对象'malloc'空间。
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
首先,您将其标记为C ++。在C ++中,您只需使用new和delete。 C ++编译器不会将“malloc”与用户创建的名为“llist”的对象的ctor / dtor相关联。我向你保证,你确实想要创建这两种方法,即使每种方法都很简单。真。
另一方面,C ++编译器确实提供了New和Delete,并且在适用于动态变量(在堆中)和自动变量(在堆栈上)时将自动调用ctor和dtor。编译器不支持malloc。
其次,您的函数init()不会返回或以其他方式将您命名为“list”的自动变量的值传递给任何其他范围。 (通常,列表生命周期超过使用或创建它的任何函数的生命周期。)
因此,您的对象“list”仅存在于函数init()的范围内,在init()的生命周期内。不太有用。
因此,'malloc'事物列表的句柄丢失了,其他任何东西都无法访问。在init()之后,你在哪里计划listHead驻留?
即使您使用了新的(和删除),代码仍然无法在任何地方传递listHead。
为了推进您的计划,您可能需要以下两项内容中的一项:
1)“list”句柄的返回(来自函数)(我一直按你的意思称它为“listHead”,对吗?)
llist* init() {
llist *listHead = ...
return(listHead);
}
OR
2)init函数更改的参数引用。这会将列表头放在init()之外。
void init( llist** listHead) {
llist *list = ...
*listHead = list;
}
您可以查看并从std :: list中获取提示,其中有40多种方法,但您可能只需要10.对于您计划实现的方法,您应该努力遵守并使用类似的名称和参数
也许您打算将类数据属性与标签列表一起使用(很难从您提供的内容中想象这一点)。在这种情况下,您应该区分数据属性名称以帮助您记住它是什么,并且它具有不同的范围。例如,我会使用m_listHead。前缀m_(或者通常只是一个字符前缀'_')简单地向读者指示该符号是类的数据属性。这个想法是一个常见的c ++习惯用法,并不是由编译器强制执行的,但通常是编码标准的一部分。
祝你好运。