调用free()释放循环链表节点时为何会修改另一个指针的地址?
问题根因
你看到*temp_llnode_ptr的值发生异常变化,是访问已释放内存的未定义行为导致的,具体拆解逻辑:
- 你写的
temp_llnode_ptr = &(*list)->head->next;并不是把head->next的值拷贝一份存下来,而是存了「第一个节点(地址0x7fffcf9c72f0)内部的next成员的内存地址」,也就是说*temp_llnode_ptr等价于直接读第一个节点的next字段。 - 调用
free_LL_node释放第一个节点的时候,会执行两个操作:- 首先你主动把
(*node)->next = NULL;,这时候已经修改了第一个节点的next值; - 调用
free(*node)释放第一个节点的内存,释放后的内存所有权归堆分配器,大部分堆实现会在释放的内存块里写入堆管理的元数据,用来维护空闲内存链表,这会直接覆盖这块内存里原来存储的所有内容,包括你原来的next字段。
- 首先你主动把
- 你后续打印
*temp_llnode_ptr,本质是读已经被释放、已经被改写的内存,输出什么值都是合法的未定义行为,你看到的0x7fffcf9c6010就是堆管理器写入的元数据值。
额外的代码逻辑问题
你当前的释放逻辑还有两处明显错误:
- 释放头节点后没有把链表的
head指针指向第二个节点,而是直接设为NULL,后续遍历会直接崩溃 - 循环链表释放需要注意不要出现循环访问,你当前按
LL_length遍历的逻辑如果没有正确更新head,也会出现访问悬垂指针的问题
正确的释放逻辑可以参考:
void free_LL(LL_t** list) { if (!list || !*list) return; LL_node_t *current = (*list)->head; LL_node_t *next = NULL; for (int i = 0; i < (*list)->LL_length; i++) { next = current->next; free_LL_node(¤t); current = next; } // 释放链表结构体本身 free(*list); *list = NULL; }
内容的提问来源于stack exchange,提问作者Darrin
相关产品推荐
相关产品推荐

