程序编译通过但运行时触发realloc指针未分配错误排查
问题分析与修复方案
核心错误点
- 变量声明类型不匹配:main里的
monster_s *monsters[MAX_MONSTERS];是栈上的指针数组,但load_monsters_csv需要的是指向单个动态结构体数组指针的指针,用来接收realloc分配的连续内存块。这种不匹配导致realloc操作的是未初始化的野指针,触发报错。 - 错误的内存释放操作:
load_monsters_csv里的free(monsters);完全错误,monsters是传入的参数指针,并非函数内动态分配的内存;main里的free(monsters);释放的是栈上数组,属于未定义行为。 - 缺失文件打开检查:
fopen可能失败(比如文件不存在),未做判断会导致后续操作崩溃。 - 未检查
realloc返回值:内存分配可能失败,直接赋值会丢失原内存地址,造成泄漏。
修复后的代码
修正后的load_monsters_csv函数
// FUNCTION int load_monsters_csv(monster_s **monsters, FILE *fp) { int num_read = 0; char buffer[MAX_LEN] = { 0 }; while (fgets(buffer, MAX_LEN, fp)) { trim(buffer); // 跳过空行 if (buffer[0] == '\0') { continue; } // 用临时变量接收realloc结果,避免分配失败时丢失原内存 monster_s *temp = realloc(*monsters, (num_read + 1) * sizeof(monster_s)); if (temp == NULL) { perror("realloc failed"); // 释放已分配的部分内存,避免泄漏 free(*monsters); *monsters = NULL; return num_read; } *monsters = temp; // 解析当前行到对应的怪物结构体 parse_monster(*monsters + num_read, buffer); num_read++; } return num_read; }
修正后的main函数
// MAIN #include <stdio.h> #include <stdlib.h> #include "utils.h" int main(int argc, char *argv[]) { int num_monsters = 0; // 声明单个指针并初始化为NULL,让realloc可以正确启动(等同于malloc) monster_s *monsters = NULL; // 验证命令行参数 if (argc != 2) { printf("Must include a file name\n"); return 1; } // 打开文件并检查是否成功 FILE *fp = fopen(argv[1], "r"); if (fp == NULL) { perror("Failed to open file"); return 1; } // 加载所有数据 num_monsters = load_monsters_csv(&monsters, fp); // 打印数据验证 for(int i = 0; i < num_monsters; i++) { printf("%s (%s), %d HP, %d AC, %d STR, %d DEX, %d CON\n", monsters[i].name, monsters[i].type, monsters[i].hp, monsters[i].ac, monsters[i].str, monsters[i].dex, monsters[i].con); // 注意:如果parse_monster为name/type分配了堆内存,需在此单独free这些字段 } // 释放动态分配的怪物数组 free(monsters); fclose(fp); return 0; }
额外注意事项
如果parse_monster函数中为monster_s的字符串字段(如name、type)分配了堆内存,在释放monsters数组前,需要循环遍历每个元素,先释放这些字符串的内存,再释放数组本身,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Bethel Bezabeh
相关产品推荐
相关产品推荐

