重复调用之间的共享变量



我正在学习c++,所以我写了一个带有一些基本实用程序的链表实现。我的插入函数接受一个节点指针,并迭代到列表的末尾,以附加一个新初始化的Node对象,p。令我惊讶的是,对insert方法的重复调用似乎共享节点p!因此,在多次调用之后,insert会将p->next赋值给自己,从而引发一个无限循环。

#include <iostream>
#include <string>
using namespace std;
struct Node {
Node *next; 
int val;
};
void insert(Node *n, int val) {
Node * cur = n;
while (cur->next) {
cout << "Val " << cur->val << "n";
cur = cur->next;
}
Node p = {0, val};
cur->next = &p;
}
int main() {
Node n1;
n1.val = 1;
insert(&n1, 2);
insert(&n1, 3);
insert(&n1, 4);
return 0;
}

我通过gdb运行这个命令来查看insert中发生了什么。实际上,在对insert的第二次调用中,我发现p在执行Node p = {0, val};之前已经初始化,并且以后的调用保留了p->next相同的值,尽管显式地将其设置为0。我似乎在我的理解上有一个差距,因为把它翻译成C会产生同样的错误。我只能用malloc来修复,这不是我想要的。

为什么会发生?p在每次调用时分配到堆栈上。

insert函数返回后,局部变量curp被销毁,内存空间可供重用。在变量被销毁之后,即使使用指针也不允许访问它,因为内存空间可以被其他东西重用。编译器不会聪明到阻止你这样做。

正如你所看到的,这不仅是理论上的可能性,而且实际上一直在发生。如果你只是再次调用完全相同的函数,你很可能会得到完全相同的内存安排,所以变量p第二次将使用它第一次使用的完全相同的内存空间。如果调用不同的函数,如printf(或cout <<)而不是insert,您可能会发现空间被printf中的一些变量覆盖。

这就是为什么每个单独的链表教程告诉你使用malloc。除了全局变量之外,这基本上是创建一些变量的唯一方法,当函数返回时不会被删除。一个"variable"由malloc创建的直到您free它才会被删除。(它也没有名称,所以指针是使用该变量的唯一方式,这一事实似乎使许多人感到困惑。)

@user53751非常正确,您的问题源于可变生命周期问题。然而,mallocfree并不是用来实现动态分配内存的合适的c++工具。相反,您应该使用newdelete来实现此目的,特别是因为它们不仅为对象分配正确大小的内存,而且还运行默认构造函数,或者像我在下面写的那样,初始化指向nullptrnext指针。

您可能还希望将insert作为Node的成员函数,因为c++允许这样做。

struct Node {
Node *next = nullptr; 
int val;
void insert(int val) {
Node *temp;
for (temp = this; temp->next; temp = temp->next);
temp->next = new Node;
temp->next->val = val;
}
};
int main() {
Node *a = new Node;
a->val = 1;

a->insert(2);
a->insert(3);
for (Node *temp = a; temp; temp = temp->next) {
std::cout << temp->val << std::endl;
}
return 0;
}
还建议定义析构函数,以便您可以轻松地清理动态分配的内存。以简单、朴素的递归方式显示,用于演示。
struct Node {
Node *next = nullptr; 
int val;
void insert(int val) {
Node *temp;
for (temp = this; temp->next; temp = temp->next);
temp->next = new Node;
temp->next->val = val;
}
~Node() {
if (next) delete next;
}
};

相关内容

  • 没有找到相关文章

最新更新