链表节点释放导致while(1)循环随机退出问题求助
双向链表随机崩溃问题排查
问题描述
实现双向链表节点操作时,程序正常运行3-7次后随机退出while(1)循环,调试时崩溃位置有时在free()处,有时在cur->prev相关的else分支中。程序本应持续运行直到按下Ctrl+C。
相关代码
链表节点处理函数
node *print_immu(node *root, unsigned char *map[HEIGHT], player *enemy){// need to check if(root != NULL){ node *cur = root; node *tmp; while(cur->next != NULL){ //if there are many > if(cur->width == WIDTH - 1 || map[cur->height][cur->width + 2] == '#'){ if(map[cur->height][cur->width + 2] == '#'){ enemy->lives--; } tmp = cur; if(tmp->prev == NULL){ root = cur->next; tmp->next->prev = NULL; }else{ tmp->next->prev = tmp->prev; tmp->prev->next = tmp->next; } map[cur->height][cur->width] = '`'; cur = cur->next; free(tmp); }else{ map[cur->height][cur->width] = '`'; cur->width += 2; map[cur->height][cur->width] = '>'; cur = cur->next; } } tmp = cur; if(cur->width == WIDTH - 1 || map[cur->height][cur->width + 2] == '#'){ if(map[cur->height][cur->width + 2] == '#'){ enemy->lives--; } if(cur->prev == NULL){ map[cur->height][cur->width] = '`'; free(cur); root = NULL; }else{ map[cur->height][cur->width] = '`'; tmp = tmp->prev; free(cur); tmp->next = NULL; } }else{ map[cur->height][cur->width] = '`'; cur->width += 2; map[cur->height][cur->width] = '>'; } } return }
节点创建函数
node *players_u(player *me, node *root, unsigned char *map[HEIGHT]){ for(int i=0; i<me->size; i++){ if(map[me->height + i][1] == '+'){ if(me->block == '#'){ me->lives--; }else{ if(root == NULL){ root = (node*)malloc (sizeof(node*)); root->next = NULL; root->prev = NULL; }else{ node *nw = (node*)malloc (sizeof(node*)); nw->next = root; root->prev = nw; root = nw; nw->prev = NULL; } root->height = me->height + i; root->width = 1; } } } return root; }
排查及修复建议
1. 内存分配错误(核心根因)
在players_u函数中,malloc时错误地分配了指针大小(sizeof(node*)),而非node结构体的完整大小:
root = (node*)malloc (sizeof(node*)); // 错误:仅分配了指针的字节数 node *nw = (node*)malloc (sizeof(node*)); // 同样错误
这会导致结构体成员(height、width、prev、next)越界覆盖相邻内存,随机损坏链表指针,引发后续free()或指针访问崩溃。修复为:
root = (node*)malloc(sizeof(node)); node *nw = (node*)malloc(sizeof(node));
2. 函数返回值缺失
print_immu函数末尾的return没有返回值,但函数声明要求返回node*类型,这会导致调用方拿到无效的垃圾地址,后续操作链表必然崩溃。修复为:
return root;
3. 数组越界访问风险
print_immu中,当cur->width接近WIDTH时,cur->width + 2可能超出map数组的宽度范围,引发非法内存访问:
if(cur->width == WIDTH - 1 || map[cur->height][cur->width + 2] == '#')
添加边界判断后修复:
bool has_obstacle = (cur->width + 2 < WIDTH) && (map[cur->height][cur->width + 2] == '#'); if(cur->width == WIDTH - 1 || has_obstacle)
4. 链表操作校验
在删除节点后,确保cur指针未指向已释放内存;每次修改链表的prev/next关联后,打印指针地址校验双向关联是否正确,避免出现野指针。
辅助调试方法
- 启用编译器内存检测(如GCC的
-fsanitize=address),直接定位内存越界、重复释放等问题。 - 在
malloc和free时打印指针地址,检查是否存在重复释放或释放未分配内存的情况。
内容的提问来源于stack exchange,提问作者mat989
相关产品推荐
相关产品推荐

