C语言realloc内存重分配异常:double free错误及数据损坏
C语言结构体数组realloc扩容后数据损坏、崩溃问题修复
问题描述
我正在编写一个用C语言存储事件的简单程序,初始通过malloc()为单个事件分配内存(事件存储在结构体数组中)。每次从编辑菜单添加新事件时,先将事件数据写入已分配的结构体,再调用realloc()为下一个待添加事件扩容内存。
但程序运行时出现以下问题:
- 每次调用
realloc()后,第一个事件的名称会损坏,第二个事件的参数变为随机长数字; - 第三次调用
realloc()时程序崩溃,抛出free(): double free detected in tcache 2错误。
核心问题是(struct events*)realloc(p, sizeof(struct events)*(qtty+1));无法正确扩容结构体数组,导致内存访问异常。尝试调整指针传递方式和realloc分配大小后仍未解决,问题集中在edit_menu函数或main中的malloc调用部分。
原代码(完整)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> typedef struct events{ char name[50]; //date: int day; int month; int year; int budget; }events; void add_event(struct events *p, int i){ printf("\n> Enter event details"); printf("\n name: "); scanf(" %[^\n]%*c", p[i].name); printf(" Date (dd.mm.yyyy): "); scanf("%d.%d.%d", &p[i].day, &p[i].month, &p[i].year); printf(" Budget(USD): "); scanf("%d", &p[i].budget); } int edit_menu(struct events *p){ static int qtty=0; struct events *tmp; int select; do{ system("clear"); printf("\n> Edit menu:\n 1) Add event\n 2) Delete event\n 0) Return\n-->"); scanf("%d", &select); switch(select){ case 1:{ add_event(p, qtty); tmp=(struct events*)realloc(p, sizeof(struct events)*(qtty+1)); qtty+=1; if(tmp!=NULL) p=tmp; else printf("\n Fail!"); }break; } }while(select); return qtty; } void show_data(struct events *p, int i){ printf("\n> %d) ", i); puts(p[i].name); printf("\n Date: %d.%d.%d", p[i].day, p[i].month, p[i].year); printf("\n Budget: %d USD", p[i].budget); printf("\n"); } int main(){ int select, qtty=0; char search_input[50]; struct events *p=malloc(sizeof(events)); do{ system("clear"); printf("\n Event Menu:\n 1) Show all events[%d]\n 2) Search for event\n 3) Edit events\n 0) Quit\n-->", qtty); scanf("%d", &select); switch(select){ case 1: for(int i=0; i<qtty; i++) show_data(p, i); sleep(3); break; case 2:{ system("clear"); printf("\n Enter event name: "); scanf("%[^\n]%*c", search_input); //srch_event(e, search_input); }break; case 3:{ qtty=edit_menu(p); } } }while(select); free(p); return 0; }
问题根源解析
- 指针值传递导致地址不同步:
edit_menu函数接收的是struct events *p,属于值传递——函数内部修改p的指向(如p=tmp)不会同步到main函数中的原指针。realloc返回新地址后,main里的p仍指向旧的已失效内存,后续操作会破坏内存,最终触发double free。 - 内存操作顺序错误:先写入数据再扩容,初始malloc仅分配1个元素空间,第二次添加事件时写入
p[1]会直接越界,破坏堆内存结构。 - static变量
qtty的同步问题:edit_menu中的qtty是静态变量,与main中的qtty各自独立,两者值不同步会导致数组遍历或扩容时出错。
修复方案
1. 使用二级指针传递地址,保证指针同步
将edit_menu的参数改为二级指针,让函数内部能直接修改main中指针的指向:
- 修改函数签名为
int edit_menu(struct events **p, int *qtty) - main中调用时传入指针地址:
edit_menu(&p, &qtty)
2. 调整内存扩容顺序,先扩容再写入数据
先通过realloc申请新的内存空间,确认分配成功后再写入新事件数据,避免越界访问:
case 1:{ tmp = realloc(*p, sizeof(struct events)*(*qtty + 1)); if(tmp == NULL){ printf("\n Fail!"); break; } *p = tmp; add_event(*p, *qtty); (*qtty)++; }break;
3. 移除static变量,统一使用main中的qtty
将edit_menu中的静态qtty改为接收main中qtty的指针,确保两者值完全同步。
4. 修复输入残留问题
在case 2的scanf前添加空格,跳过之前输入留下的换行符:
scanf(" %[^\n]%*c", search_input);
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> typedef struct events{ char name[50]; int day; int month; int year; int budget; }events; void add_event(struct events *p, int i){ printf("\n> Enter event details"); printf("\n name: "); scanf(" %[^\n]%*c", p[i].name); printf(" Date (dd.mm.yyyy): "); scanf("%d.%d.%d", &p[i].day, &p[i].month, &p[i].year); printf(" Budget(USD): "); scanf("%d", &p[i].budget); } int edit_menu(struct events **p, int *qtty){ int select; struct events *tmp; do{ system("clear"); printf("\n> Edit menu:\n 1) Add event\n 2) Delete event\n 0) Return\n-->"); scanf("%d", &select); switch(select){ case 1:{ tmp = realloc(*p, sizeof(struct events)*(*qtty + 1)); if(tmp == NULL){ printf("\n Fail!"); break; } *p = tmp; add_event(*p, *qtty); (*qtty)++; }break; } }while(select); return *qtty; } void show_data(struct events *p, int i){ printf("\n> %d) ", i); puts(p[i].name); printf("\n Date: %d.%d.%d", p[i].day, p[i].month, p[i].year); printf("\n Budget: %d USD", p[i].budget); printf("\n"); } int main(){ int select, qtty=0; char search_input[50]; struct events *p=malloc(sizeof(events)); if(p == NULL){ printf("Memory allocation failed!\n"); return 1; } do{ system("clear"); printf("\n Event Menu:\n 1) Show all events[%d]\n 2) Search for event\n 3) Edit events\n 0) Quit\n-->", qtty); scanf("%d", &select); switch(select){ case 1: for(int i=0; i<qtty; i++) show_data(p, i); sleep(3); break; case 2:{ system("clear"); printf("\n Enter event name: "); scanf(" %[^\n]%*c", search_input); //srch_event(e, search_input); }break; case 3:{ edit_menu(&p, &qtty); } } }while(select); free(p); return 0; }
内容的提问来源于stack exchange,提问作者Marius Iordan
相关产品推荐
相关产品推荐

