C语言结构体指针数组打印第3个元素异常求助
结构体动态数组读取文件时元素打印异常的问题修复
读取文件内容到结构体动态数组时,第3个元素打印异常,输出结果为host0host1♥host3,输入文件内容如下:
0 host0
1 host1
2 host2
3 host3
4 host4
问题根源分析
核心错误:内存分配计算逻辑错误
代码中realloc的参数计算存在运算符优先级问题:
local_name = realloc(local_name, total + 1 * sizeof(*local_name));
C语言中乘法*优先级高于加法+,实际计算结果为 total + (1 * sizeof(*local_name)),而非预期的(total + 1) * sizeof(*local_name)。这导致每次循环仅额外分配单个结构体的字节数,而非扩容为能容纳total+1个结构体的完整内存空间。当total增长到2时,内存空间不足以存储第3个结构体,访问local_name[2]触发内存越界,造成数据损坏,最终打印异常。
其他潜在问题
- 使用全局变量
total,破坏代码模块化,易引发变量污染 - 未检查
realloc、malloc的返回值,内存分配失败会直接导致程序崩溃 - 主函数未关闭打开的文件,造成系统资源泄漏
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> struct names { int number; char *name; }; void readNames(FILE *fpN, struct names **name, int *total) { char sentence[512]; struct names *local_name = *name; *total = 0; // 初始化计数 while (fgets(sentence, sizeof(sentence), fpN)) { // 修正内存分配计算,确保分配(total+1)个结构体的空间 struct names *temp = realloc(local_name, (*total + 1) * sizeof(*local_name)); if (temp == NULL) { perror("realloc failed"); // 清理已分配内存,避免泄漏 for (int i = 0; i < *total; i++) { free(local_name[i].name); } free(local_name); *name = NULL; *total = 0; return; } local_name = temp; char *token = strtok(sentence, " "); // 提取数字 if (token == NULL) { fprintf(stderr, "Invalid line format\n"); continue; } local_name[*total].number = atoi(token); token = strtok(NULL, " \n"); // 提取名称 if (token == NULL) { fprintf(stderr, "Missing name in line\n"); continue; } // 分配名称内存并检查分配结果 local_name[*total].name = malloc(strlen(token) + 1); if (local_name[*total].name == NULL) { perror("malloc failed"); // 清理已分配资源 for (int i = 0; i < *total; i++) { free(local_name[i].name); } free(local_name); *name = NULL; *total = 0; return; } strcpy(local_name[*total].name, token); (*total)++; } *name = local_name; // 测试打印所有元素 for (int i = 0; i < *total; i++) { printf("%s ", local_name[i].name); } printf("\n"); } int main(int argc, char **argv) { FILE *fpN = NULL; if (argc != 2) { fprintf(stderr, "Usage: %s <filename>\n", argv[0]); exit(EXIT_FAILURE); } fpN = fopen(argv[1], "r"); if (fpN == NULL) { perror("Failed to open file"); exit(EXIT_FAILURE); } struct names *name = NULL; int total = 0; readNames(fpN, &name, &total); // 使用完毕后释放所有动态分配的内存 for (int i = 0; i < total; i++) { free(name[i].name); } free(name); fclose(fpN); // 关闭文件,释放系统资源 return EXIT_SUCCESS; }
关键修改说明
- 修复内存分配计算:将
total + 1 * sizeof(*local_name)改为(total + 1) * sizeof(*local_name),确保每次扩容能容纳足够数量的结构体。 - 替换全局变量:将
total改为指针传递,避免全局变量的副作用,提升代码模块化程度。 - 添加内存分配检查:对
realloc和malloc的返回值进行校验,分配失败时清理已分配资源,避免内存泄漏。 - 完善资源管理:主函数中添加文件关闭操作,程序结束前释放所有动态分配的内存。
- 增加格式校验:对
strtok的返回值进行检查,处理格式错误的输入行。
内容的提问来源于stack exchange,提问作者George Pettemeridis
相关产品推荐
相关产品推荐

