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

为何读取文件到结构体的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;
}

关键修复说明

  1. 数组内存分配:要么用固定大小数组,要么用malloc/realloc动态分配,杜绝未初始化指针。
  2. 字符串内存处理:使用char*时必须先分配足够内存再写入;或直接用固定大小char数组,简化内存管理。
  3. 错误校验:对文件打开、内存分配操作做失败检查,避免后续操作非法指针。
  4. 动态内存释放:动态分配的内存使用完毕后必须释放,防止内存泄漏。

内容的提问来源于stack exchange,提问作者kristof

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:40:25