为何读取文件到结构体的while循环中出现segmentation fault(段错误)?
问题分析与修复
核心问题点
- 未初始化的数组指针:main函数里的
competitor* array仅声明指针,未分配有效内存,指向随机地址,直接写入会触发段错误。 - 结构体字符指针无有效内存:
competitor中的name、nationality等char*成员都是野指针,fscanf的%s会直接往野地址写数据,导致内存访问违规。 - 文件打开未做错误校验:若
fopen失败(如文件不存在),file为NULL,后续fscanf操作空指针必然崩溃。
修复后的代码
方案一:固定大小字符数组(适合已知字符串长度上限场景)
#include <stdio.h> #include <string.h> #include <stdlib.h> // 定义字符串最大长度,按需调整 #define MAX_STR_LEN 100 typedef struct competitor { int id; char name[MAX_STR_LEN]; char nationality[MAX_STR_LEN]; char sex[MAX_STR_LEN]; double weight; char event[MAX_STR_LEN]; }competitor; int sportolok_beolvas(char* filename, competitor* array, int max_count) { FILE* file = fopen(filename, "r"); if (!file) { perror("文件打开失败"); return -1; } int n = 0; // 限制读取数量,防止数组越界 while(n < max_count && fscanf(file, "%d %s %s %s %lf %s", &array[n].id, array[n].name, array[n].nationality, array[n].sex, &array[n].weight, array[n].event) == 6) { ++n; } fclose(file); return n; } #define MAX_COMPETITORS 100 int main() { // 分配固定大小的结构体数组 competitor array[MAX_COMPETITORS]; int i = sportolok_beolvas("sportolok.txt", array, MAX_COMPETITORS); if (i == -1) { return 1; } printf("读取到%d条数据\n", i); return 0; }
方案二:动态分配内存(适合数据量不确定场景)
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct competitor { int id; char* name; char* nationality; char* sex; double weight; char* event; }competitor; int sportolok_beolvas(char* filename, competitor** array) { FILE* file = fopen(filename, "r"); if (!file) { perror("文件打开失败"); return -1; } int n = 0; int capacity = 4; // 初始容量 // 初始化动态数组 *array = malloc(sizeof(competitor) * capacity); if (!*array) { perror("内存分配失败"); fclose(file); return -1; } int id; char name[100], nationality[100], sex[100], event[100]; double weight; // 先读取到临时数组,再分配内存复制 while(fscanf(file, "%d %s %s %s %lf %s", &id, name, nationality, sex, &weight, event) == 6) { // 容量不足时扩容 if (n >= capacity) { capacity *= 2; competitor* temp = realloc(*array, sizeof(competitor) * capacity); if (!temp) { perror("内存扩容失败"); // 释放已分配内存避免泄漏 for (int j = 0; j < n; j++) { free((*array)[j].name); free((*array)[j].nationality); free((*array)[j].sex); free((*array)[j].event); } free(*array); fclose(file); return -1; } *array = temp; } (*array)[n].id = id; (*array)[n].weight = weight; // 为每个字符串分配内存并复制 (*array)[n].name = malloc(strlen(name) + 1); strcpy((*array)[n].name, name); (*array)[n].nationality = malloc(strlen(nationality) + 1); strcpy((*array)[n].nationality, nationality); (*array)[n].sex = malloc(strlen(sex) + 1); strcpy((*array)[n].sex, sex); (*array)[n].event = malloc(strlen(event) + 1); strcpy((*array)[n].event, event); n++; } fclose(file); return n; } int main() { competitor* array = NULL; int i = sportolok_beolvas("sportolok.txt", &array); if (i == -1) { return 1; } printf("读取到%d条数据\n", i); // 释放动态分配的内存 for (int j = 0; j < i; j++) { free(array[j].name); free(array[j].nationality); free(array[j].sex); free(array[j].event); } free(array); return 0; }
关键修复说明
- 数组内存分配:要么用固定大小数组,要么用
malloc/realloc动态分配,杜绝未初始化指针。 - 字符串内存处理:使用
char*时必须先分配足够内存再写入;或直接用固定大小char数组,简化内存管理。 - 错误校验:对文件打开、内存分配操作做失败检查,避免后续操作非法指针。
- 动态内存释放:动态分配的内存使用完毕后必须释放,防止内存泄漏。
内容的提问来源于stack exchange,提问作者kristof
相关产品推荐
相关产品推荐

