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

使用fscanf()读取文件时为何发生段错误?

段错误原因分析与修复方案

你的代码触发段错误主要有以下几个核心问题,对应修复步骤如下:

1. 文件打开未做错误检查

如果./hw3.data不存在、路径错误或者没有读取权限,fopen会返回NULL,后续调用fscanf操作空指针直接触发段错误。必须在每次调用fopen后立刻检查返回值:

FILE *data = fopen("./hw3.data", "r");
if (data == NULL) {
    perror("Failed to open file");
    exit(EXIT_FAILURE);
}

2. 错误使用feof()判断循环终止

feof()只有在读取操作尝试越过文件末尾后才会返回真,这会导致你的scan()函数在文件读完后,还会多执行一次fscanf(此时读取失败,但size仍会被错误累加),后续malloc的空间如果超出实际需要,或者读取失败时操作非法内存,都会引发段错误。

正确的做法是用fscanf的返回值判断读取是否成功:fscanf返回成功匹配并读取的参数个数,你的格式串对应4个参数,返回值等于4时说明读取有效。修改scan()函数:

int scan(void) {
    int size = 0;
    FILE *data = fopen("./hw3.data", "r");
    if (data == NULL) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }
    
    struct data temp; // 改用局部变量,避免全局变量污染
    int ret;
    while ((ret = fscanf(data, "%19s %f %d %19s", temp.name, &temp.floatNum,
               &temp.intNum, temp.color)) == 4) {
        size++;
    }
    fclose(data); // 别忘了关闭文件,避免资源泄漏
    return size;
}

3. 未限制字符串读取长度,存在缓冲区溢出风险

如果文件中name或color字段的长度超过结构体定义的20字节,fscanf会写入超出缓冲区的内存,破坏程序的内存布局,触发段错误。必须限制字符串读取长度:

// %19s 表示最多读取19个字符,留1个字节给字符串结束符'\0'
fscanf(data, "%19s %f %d %19s", ...);

4. 其他细节问题

  • load()函数同样需要检查文件打开状态、限制字符串读取长度,并且读取后关闭文件。
  • malloc可能返回NULL(内存不足),必须检查分配是否成功,使用完内存后要调用free释放。

完整修复后的代码

#include <stdlib.h>
#include <stdio.h>

struct data {
    char name[20];
    float floatNum;
    int intNum;
    char color[20];
};

int scan(void) {
    int size = 0;
    FILE *data = fopen("./hw3.data", "r");
    if (data == NULL) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }
    
    struct data temp;
    int ret;
    while ((ret = fscanf(data, "%19s %f %d %19s", temp.name, &temp.floatNum,
               &temp.intNum, temp.color)) == 4) {
        size++;
    }
    
    fclose(data);
    return size;
}

void load(int size, struct data autos[]) {
    int i;
    FILE *data = fopen("./hw3.data", "r");
    if (data == NULL) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }
    
    for (i = 0; i < size; i++) {
        int ret = fscanf(data, "%19s %f %d %19s", autos[i].name, &autos[i].floatNum,
               &autos[i].intNum, autos[i].color);
        if (ret != 4) {
            fprintf(stderr, "Error reading line %d\n", i+1);
            exit(EXIT_FAILURE);
        }
    }
    fclose(data);
}

int main() {
    int size;
    struct data *autos;
    size = scan();
    autos = malloc(size * sizeof(struct data));
    if (autos == NULL) {
        perror("Failed to allocate memory");
        exit(EXIT_FAILURE);
    }
    load(size, autos);
    
    free(autos);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:16:21