我正在实现一个循环链表,我试图使函数将释放链表和链表中的节点。我有一个LL_t
类型,它指向链表的头和尾。然后是LL_node_t
节点的链表。
我已经尽我最大的努力得到代码的重要部分和我正在处理的输出,以更好地显示我的问题。
我的问题是,为什么在我的temp_llnode_ptr
开始这个值temp_llnode_ptr: 0x7fffcf9c7310
,但在调用我的自由函数结束后NEW temp_llnode_ptr: 0x7fffcf9c6010
。它从第二个节点的地址开始。我尝试释放我的第一个节点。然后在函数之后,我的temp_llnode_ptr
有一个不同的值。
void
free_LL (LL_t** list)
{
LL_node_t** temp_llnode_ptr = NULL;
for (int i = 0; i < (*list)->LL_length; i++)
{
printf("Inside FOR loopn");
printf("list->head: %pn", (void*)(*list)->head);
printf("list->tail: %pn", (void*)(*list)->tail);
temp_llnode_ptr = &(*list)->head->next;
printf("temp_llnode_ptr: %pn", (void*)(*temp_llnode_ptr));
printf("(*temp_llnode_ptr)->next: %pn", (void*)(*temp_llnode_ptr)->next);
free_LL_node(&(*list)->head);
printf("NEW temp_llnode_ptr: %pn", (void*)(*temp_llnode_ptr));
printf("NEW list->head: %pn", (void*)(*list)->head);
}
}
void
free_LL_node (LL_node_t** node)
{
(*node)->next = NULL;
(*node)->data = NULL;
printf("node about to be FREED is: %pn", (void*)(*node));
free(*node);
*node = NULL;
}
OUTPUT FROM PRINT FUNC (The nodes in my linked list)
Node#: 0 | Current node: 0x7fffcf9c72f0 | Node data: 10 | Next node 0x7fffcf9c7310
Node#: 1 | Current node: 0x7fffcf9c7310 | Node data: 20 | Next node 0x7fffcf9c7330
Node#: 2 | Current node: 0x7fffcf9c7330 | Node data: 30 | Next node 0x7fffcf9c72f0
Inside FOR loop
list->head: 0x7fffcf9c72f0
list->tail: 0x7fffcf9c7330
temp_llnode_ptr: 0x7fffcf9c7310 <--- Why do these change?
(*temp_llnode_ptr)->next: 0x7fffcf9c7330
node about to be FREED is: 0x7fffcf9c72f0
NEW temp_llnode_ptr: 0x7fffcf9c6010 <--- Why do these change?
NEW list->head: (nil)
设X
为(*list)->head
所指之物。然后将temp_llnode_ptr
设置为X->next
的地址。调用free_LL_node(&(*list)->head);
会释放X
。一旦X
被释放,它的内存内容就不再可靠了。除此之外,它们可能已经被内存管理例程更改,将内存用于自己的目的。X->next
在内存中,所以它的内容可能已经改变了。打印(*temp_llnode_ptr)
尝试打印X->next
的内容。
由于temp_llnode_ptr
指向一个已被释放的对象,因此根据C标准,它的值是不确定的。(这是正确的,正如C标准所规定的,在free(p)
之后,值的p
不再确定。尽管free
不能改变用于保存p
的内存,但它的"值"在语义上可能与内存中的其他数据绑定,并且这些数据可能被p
更改,因此它的"值"不再确定。另外,*temp_llnode_ptr
试图使用该内存,而这种行为没有在C标准中定义。
让我们看看有问题的部分:
temp_llnode_ptr = &(*list)->head->next;
printf("temp_llnode_ptr: %pn", (void*)(*temp_llnode_ptr));
free_LL_node(&(*list)->head);
printf("NEW temp_llnode_ptr: %pn", (void*)(*temp_llnode_ptr));
第一行设置temp_llnode_ptr
指向第一个节点中的next
变量。
第二行查看该变量中的值(该值是第二个节点的地址)并输出它。
第三行释放第一个节点。
第二行查看该变量中的值——该变量是我们刚刚释放的第一个节点的一部分——并打印它。因为我们释放了这个变量我们不应该再用它了。在这种情况下,看起来内存管理系统已经使用内存中的那个点来保存一些与内存管理相关的指针。不过这没关系——这不是你的问题——你的问题是,在你释放了它之后,你根本不应该使用它
你似乎认为temp_llnode_ptr
指向下一个节点。我想这符合你的目的,所以你可以这样做。temp_llnode_ptr
可以只是一个指针(而不是指针到指针,又名双指针),然后你有一堆额外的&
s和*
s删除为好。
如果您执行temp_llnode_ptr = (*list)->head->next;
(删除&
),则temp_llnode_ptr将指向下一个节点(而不是指向指向下一个节点的next
),您应该能够自己计算其余部分。