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

调用initUniversity时触发realloc invalid pointer错误求助

排查realloc() invalid pointer错误:从二进制文件初始化University结构体

从存储学生信息的二进制文件读取数据初始化University结构体时,调用initUniversity函数触发「realloc() : invalid pointer」错误,以下是相关代码及问题排查:

结构体定义

typedef struct
{
    unsigned long id;       // Уникальный id, получаемый из g_Id
    char name[SIZE];        // Имя
    char surname[SIZE];     // Фамилия
    char groupName[SIZE];   // Название группы
    unsigned birthYear;     // Год рождения
} Student;

// Структура описывающая группу 
// Cоздается при чтении, если getGroup() вернула NULL; название группы берется из структуры студента
typedef struct
{
    char name[SIZE];        // Название группы
    unsigned studentsCount; // Количество студентов в группе (размер динамического массива)
    Student *students;      // Динамический массив со студентами
} Group;

// Структура описывающая университет
typedef struct
{
    unsigned groupsCount;   // Количество групп в университете
    Group *groups;          // Динамический массив с группами
} University;

辅助函数

char *_strtoupper(char *str) {
    if (str == NULL) {
        return NULL;
    }
    for (int i = 0; i < strlen(str); ++i) {
        if (str[i] > 96 && str[i] < 123) {
                str[i] -=32;
        }
    }
    return str;
}

int strcm(char *s, char *st) {
    char cs[SIZE];
    char cst[SIZE];
    strcpy(cs, s);
    strcpy(cst, st);
    return strcmp(_strtoupper(cs), _strtoupper(cst));
}

新增组函数

bool addNewGroup(University *university, const Group group) {
    if (university == NULL) {
        return false;
    }
    university->groupsCount += 1;
    Group *t;
    if (university->groupsCount == 1) {
        if (!(university->groups = calloc(1, sizeof(Group)))) {
            return false;
        }
        university->groups[0] = group;
        return true;
    }
    if (!(t = realloc(university->groups, 
        university->groupsCount  * sizeof(Group)))) {
        return false;
    }
    university->groups = t;
    university->groups[university->groupsCount - 1] = group;
    strcpy(university->groups[university->groupsCount - 1].name, group.name);
    return true;
}

新增学生函数

bool addNewStudent(Group *group, Student student) {
    if (group == NULL) {
        return false;
    }
    int ind = 0;
    int fl = 0;
    if (student.id == 0) {
        student.id = g_Id;
        ++g_Id;
    }
    ++group->studentsCount;
    Student *t;
    if (group->studentsCount == 1) {
        if (!(group->students = calloc(1, sizeof(Student)))) {
            return false;
        }
        group->students[0] = student;
        return true;     
    }
    if (!(t = realloc(group->students, group->studentsCount * sizeof(Student)))) {
        return false;
    }
    group->students = t;
    group->students[group->studentsCount - 1] = student;
    Student tmp;
    for (int i = 0; i < group->studentsCount - 1; ++i) {
        for (int j = 0; j < group->studentsCount - 1 - i; ++j) { 
            if (strcm(group->students[j].surname, group->students[j + 1].surname) > 0) {
                tmp = group->students[j];
                group->students[j] = group->students[j + 1];
                group->students[j + 1] = tmp; 
            }
        }
    } 
    return true;
}

问题函数initUniversity

University* initUniversity(const char *fileName) {
    University* un;
    if (!(un = (University *)calloc(1, sizeof(University)))) {
        return un;
    }
    if (fileName == NULL) {
        return un;
    }
    FILE *fd = fopen(fileName, "rb");
    if (fd == NULL) {
        return un;
    }
    Student student;
    Group group;
    char gr[SIZE] = "";
    int i = -1;
    int j = 0;
    unsigned max = 0;
    while (fread(&student,sizeof(Student), 1, fd)) {
        if (student.id > max ) {
            g_Id = student.id + 1;
            max = student.id;
        }
        if (strcmp(gr, student.groupName) != 0) {
            ++i;
            j = 0;
            strcpy(group.name, student.groupName);
            addNewGroup(un, group);
        }
        addNewStudent(&un->groups[i], student);
        strcpy(gr, student.groupName);
        }
    fclose(fd); 
    return un;
}

问题根源

  1. 未初始化的Group局部变量导致野指针:
    在initUniversity中,Group group;是局部自动变量,未显式初始化,其成员studentsCount为随机垃圾值,students为野指针。调用addNewGroup时,这些垃圾值会被拷贝到university->groups数组的新元素中。
    后续调用addNewStudent时,++group->studentsCount会把原本的随机值加1,大概率不会等于1,因此直接进入realloc(group->students, ...)分支,而group->students是野指针,触发realloc() invalid pointer错误。

  2. addNewStudent依赖studentsCount判断初始化存在风险:
    函数通过group->studentsCount == 1判断是否为第一次分配内存,但如果studentsCount被垃圾值污染,这个判断就会失效,直接执行realloc操作野指针。

修复方案

方案1:初始化Group局部变量

在initUniversity中,将Group group;改为显式初始化,确保成员初始值合法:

Group group = {0}; // 所有成员初始化为0,studentsCount=0,students=NULL

方案2:修改addNewStudent的初始化逻辑

不再依赖studentsCount判断,而是直接检查students指针是否为NULL,从根源避免野指针问题:

bool addNewStudent(Group *group, Student student) {
    if (group == NULL) {
        return false;
    }

    // 处理ID逻辑
    if (student.id == 0) {
        student.id = g_Id;
        ++g_Id;
    }

    Student *new_students;
    if (group->students == NULL) {
        // 第一次分配内存
        new_students = calloc(1, sizeof(Student));
        if (!new_students) {
            return false;
        }
        group->studentsCount = 1;
    } else {
        // 扩容已有数组
        new_students = realloc(group->students, (group->studentsCount + 1) * sizeof(Student));
        if (!new_students) {
            return false;
        }
        group->studentsCount += 1;
    }

    group->students = new_students;
    // 添加新学生到数组末尾
    group->students[group->studentsCount - 1] = student;

    // 排序逻辑保持不变
    Student tmp;
    for (int i = 0; i < group->studentsCount - 1; ++i) {
        for (int j = 0; j < group->studentsCount - 1 - i; ++j) { 
            if (strcm(group->students[j].surname, group->students[j + 1].surname) > 0) {
                tmp = group->students[j];
                group->students[j] = group->students[j + 1];
                group->students[j + 1] = tmp; 
            }
        }
    } 

    return true;
}

方案3:优化addNewGroup的冗余操作

addNewGroup中university->groups[university->groupsCount - 1] = group;已经完成了结构体的完整拷贝,包括name字段,后续的strcpy是冗余操作,可以删除:

// 删除此行
// strcpy(university->groups[university->groupsCount - 1].name, group.name);

内容的提问来源于stack exchange,提问作者игорь кочнов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:05:27