You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题根源解析

  1. 指针值传递导致地址不同步:edit_menu函数接收的是struct events *p,属于值传递——函数内部修改p的指向(如p=tmp)不会同步到main函数中的原指针。realloc返回新地址后,main里的p仍指向旧的已失效内存,后续操作会破坏内存,最终触发double free。
  2. 内存操作顺序错误:先写入数据再扩容,初始malloc仅分配1个元素空间,第二次添加事件时写入p[1]会直接越界,破坏堆内存结构。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 17:05:22