C语言循环双向链表插入异常:新对象与已有对象地址重复
C语言循环双向链表插入异常:第二个元素插入时
curr与prev地址重合 实现循环双向链表时,插入第一个元素功能正常,但插入第二个元素时,调试发现局部变量curr和prev的地址完全相同,导致链表结构异常。
问题代码
struct ListNode { void *item; struct ListNode *next; struct ListNode *prev; }; struct List { int num_members; ListNode head; /* function pointers */ ... }; int ListAppend(List* list, void* item){ ListNode* node = &(list->head); ListInsertBefore(list,item,node); return 0; } int ListInsertBefore(List* list, void* item, ListNode* node){ ListNode* prev = node->prev; ListNode curr; curr.item = item; node->prev = &curr; curr.next = node; prev->next = &curr; curr.prev = prev; list->num_members += 1; return 0; }
GDB调试输出
62 curr.item = item; 7: node = (ListNode *) 0xbfffef08 8: *node = {item = 0x0, next = 0xbfffee70, prev = 0xbfffee70} 9: &curr = (ListNode *) 0xbfffee70 10: curr = {item = 0x0, next = 0xbfffef08, prev = 0xbfffef08} 11: prev = (ListNode *) 0xbfffee70 12: *prev = {item = 0x0, next = 0xbfffef08, prev = 0xbfffef08}
问题分析
核心错误出在ListInsertBefore函数里的ListNode curr;——这是栈上分配的局部变量。函数执行完毕返回后,栈上的curr会被销毁,其内存地址会被后续函数调用复用。
第一次插入时,curr的地址被赋值给head的prev和prev(也就是head自己)的next,此时链表暂时看起来正常,但这块内存已经不属于有效节点了。第二次调用ListInsertBefore时,新的curr刚好分配到了和第一次curr相同的栈地址,也就是此时prev指向的地址,导致&curr和prev地址重合,最终破坏链表结构。
修复方案
- 用动态内存分配创建节点:确保节点内存在函数返回后依然有效
int ListInsertBefore(List* list, void* item, ListNode* node){ ListNode* curr = malloc(sizeof(struct ListNode)); if (!curr) { // 内存分配失败处理 return -1; } curr->item = item; ListNode* prev = node->prev; node->prev = curr; curr->next = node; prev->next = curr; curr->prev = prev; list->num_members += 1; return 0; }
- 初始化链表状态:创建List结构体后,需将head的next和prev指向自身,保证循环链表初始结构正确
void ListInit(List* list) { list->num_members = 0; list->head.next = &list->head; list->head.prev = &list->head; }
- 补充销毁逻辑:后续需实现链表销毁函数,用
free释放所有动态分配的节点,避免内存泄漏。
内容的提问来源于stack exchange,提问作者RichS
相关产品推荐
相关产品推荐

