调用initUniversity时触发realloc invalid pointer错误求助
从存储学生信息的二进制文件读取数据初始化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; }
问题根源
未初始化的Group局部变量导致野指针:
在initUniversity中,Group group;是局部自动变量,未显式初始化,其成员studentsCount为随机垃圾值,students为野指针。调用addNewGroup时,这些垃圾值会被拷贝到university->groups数组的新元素中。
后续调用addNewStudent时,++group->studentsCount会把原本的随机值加1,大概率不会等于1,因此直接进入realloc(group->students, ...)分支,而group->students是野指针,触发realloc() invalid pointer错误。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,提问作者игорь кочнов

