我在C中制作了一个非常简单的链表节点结构,其中包含一些通用指针数据和指向下一个节点结构的指针。我有一个功能,它将采取一个链接列表节点,并删除它以及它链接到的任何其他节点。它目前是这样做的:
void freeLinkedList(LinkedListNode *node)
{
LinkedListNode *currentNode = node;
LinkedListNode *previousNode = NULL;
do
{
free(currentNode->data);
previousNode = currentNode;
currentNode = currentNode->next;
printf("Freeing node... %sn", previousNode->name);
free(previousNode);
printf("freed it!n");
} while (currentNode != NULL);
printf("Deleted node and all referencing nodes!");
}
它非常简单地从函数中给定的节点遍历,并继续删除指针数据,指向指向的下一个节点(如果有),然后删除上一个节点的内存。这确实如预测的那样有效。。。但仅在某些情况下。
实际的LinkedList结构如下:
typedef struct LinkedListNode {
void *data;
struct LinkedListNode *next;
char name[50];
} LinkedListNode;
在这样动态分配结构的情况下,该功能可以完美地工作:
LinkedListNode *myNode1 = malloc(sizeof(struct LinkedListNode));
LinkedListNode *myNode2 = malloc(sizeof(struct LinkedListNode));
LinkedListNode *myNode3 = malloc(sizeof(struct LinkedListNode));
strcpy(myNode1->name, "Node1");
myNode1->data = NULL;
myNode1->next = myNode2;
strcpy(myNode2->name, "Node2");
myNode2->data = NULL;
myNode2->next = myNode3;
strcpy(myNode3->name, "Node3");
myNode3->data = NULL;
myNode3->next = NULL;
freeLinkedList(myNode1); // CALLING DELETE FUNCTION HERE
但是如果我使用的函数的结构不是在堆内存上分配的,而是像这样的自动堆栈内存:
LinkedListNode myNode1 = {NULL, NULL, "Node1"};
LinkedListNode myNode2 = {NULL, NULL, "Node2"};
LinkedListNode myNode3 = {NULL, NULL, "Node3"};
myNode1.next = &myNode2;
myNode2.next = &myNode3;
freeLinkedList(&myNode1); // CALLING DELETE FUNCTION HERE
我在函数的这一行得到一个SIGSEGV-分段错误
free(previousNode);
这个错误只发生在最后一个节点的free函数上,也就是说,输出会说:"正在释放节点…node3
然后崩溃。
但非常有趣的是,到目前为止,我只使用上面的例子体验过它。如果我说,再声明一个本地LinkedListNode结构,如下所示:
LinkedListNode myNode1 = {NULL, NULL, "Node1"};
LinkedListNode myNode2 = {NULL, NULL, "Node2"};
LinkedListNode myNode3 = {NULL, NULL, "Node3"};
LinkedListNode myNode4 = {NULL, NULL, "Node4"};
myNode1.next = &myNode2;
myNode2.next = &myNode3;
freeLinkedList(&myNode1);
该功能实际上起作用,并按预期完成所有操作。
我已经试了几个小时来思考为什么会这样,但我只是被难住了。这与我试图释放堆栈上分配的内存有关吗?
您是由freeing of stack memory
引起的Undefined behavior
的受害者。这可能是致命的,有时似乎有效。
这已经在堆栈内存上的这个线程free()中得到了回答,应该可以解释这一切。