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

C语言自定义文件读取函数触发段错误的原因与解决

C语言配置读取函数段错误的原因与解决方法

问题背景与现象

我正在用C语言开发个人视频游戏项目,因硬编码值日益增多,决定将配置数据存入文本文件动态读取。自行实现了一个返回void指针的读取函数,通过Return_Type枚举指定返回类型,但调用时触发段错误。

预期配置文件为每行变量名=值的格式,示例:

name=main_character
money=1000
damage_multiplier=1.2

使用的枚举类型:

typedef enum{integer, string, floating,struct_limb,struct_attributes}Return_Type;

待读取的生物配置文件内容:

species=0
name=Short-faced bear
representation=a
id=0
limb_count=7
limbs=[[0,0,100,100],[1,0,100,100],[2,0,100,100],[2,0,100,100],[3,0,100,100],[3,0,100,100],[4,0,100,100]]
weight=900
height=3.4
attributes=[12,12,12,12,12,12,12,12]
max_health=100
max_carry=100
preferred_attack_type=1

读取函数(仅保留整数类型处理逻辑):

void *ir_readin_data(char *file_path, char *variable, Return_Type expected_type){
void *value;
FILE *fp = fopen(file_path, "r");
char * line = NULL;
size_t len = 0;
while((getline(&line, &len, fp)) != -1){
  char *variable_pointer = strstr(line, variable);
  if(variable_pointer != NULL){
    char *value_as_str = strtok(strchr(line, '=')+1, "\n");
   if(expected_type == integer){
    int value_as_integer = atoi(value_as_str);
    value = &value_as_integer;
    fclose(fp);
    return value;
   }
  }
 }
}

调用方式:

*(int *)ir_readin_data(creature_file_path,"species", integer);

运行触发段错误,尝试过传入void指针、返回char指针、使用union等方法均无效。

问题根源

段错误的核心原因是返回了栈上局部变量的地址:函数内的value_as_integer是栈内存中的局部变量,当函数执行完成返回后,对应的栈帧会被销毁,该地址变为野指针,后续访问时会触发非法内存操作,导致段错误。

解决方案

改用malloc在堆内存中分配存储空间,堆内存不会随函数返回而释放,调用者可安全访问数据,使用完毕后需手动调用free释放内存,避免内存泄漏。

修改后的读取函数(完善整数类型处理逻辑):

void *ir_readin_data(char *file_path, char *variable, Return_Type expected_type){
void *value = NULL; // 初始化指针,避免未定义行为
FILE *fp = fopen(file_path, "r");
if (!fp) { // 处理文件打开失败的情况
    return NULL;
}
char *line = NULL;
size_t len = 0;
ssize_t read;

while((read = getline(&line, &len, fp)) != -1){
  char *variable_pointer = strstr(line, variable);
  if(variable_pointer != NULL){
    char *equals_pos = strchr(line, '=');
    if (!equals_pos) { // 处理无等号的无效行
        continue;
    }
    char *value_as_str = strtok(equals_pos + 1, "\n");
    if(expected_type == integer){
      int *ptr = malloc(sizeof(int));
      if (!ptr) { // 处理内存分配失败的情况
          fclose(fp);
          free(line);
          return NULL;
      }
      *ptr = atoi(value_as_str);
      value = ptr;
      break; // 找到目标变量后跳出循环,提升效率
    }
  }
 }
fclose(fp);
free(line); // 释放getline分配的内存
return value;
}

正确调用方式(记得释放内存):

int *species = (int *)ir_readin_data(creature_file_path, "species", integer);
if (species != NULL) {
    printf("Species: %d\n", *species);
    free(species); // 使用完毕后释放堆内存
}

额外优化建议

  1. 添加错误处理:原代码未处理文件打开失败、无等号行、内存分配失败等情况,完善后提升代码健壮性
  2. 释放getline内存:getline动态分配的内存必须手动free,避免内存泄漏
  3. 提前终止循环:找到目标变量后立即跳出循环,减少不必要的文件读取操作
  4. 扩展其他类型:后续支持字符串、浮点数、结构体时,同样需使用堆内存分配(如字符串用strdup或malloc+strcpy)

内容的提问来源于stack exchange,提问作者Anton Nørgaard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:15:42