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

C语言中使用realloc动态分配结构体数组触发SIGTRAP崩溃的原因

问题分析与修复方案

你的代码存在多个触发崩溃的问题,逐一拆解并修复:

1. 参数传递错误

函数参数User *users是值传递,函数内对users的地址修改不会同步到外部调用者。需要改用指针的指针(User **users),让外部能获取到重新分配后的内存地址。

2. 内存分配大小错误

你用sizeof(struct user *)分配内存,这是在分配指针的大小(通常4/8字节),而非User结构体本身的大小。正确写法是sizeof(User)或sizeof(struct user)。

3. feof循环条件的陷阱

!feof(file)作为循环条件会导致多读一次:当读到文件末尾时,feof不会立刻置位,直到下一次读取失败才会标记,这会让循环多执行一次,触发越界访问。应该用fgets的返回值作为循环终止条件。

4. realloc的安全问题

realloc可能返回NULL(内存分配失败),直接赋值给users会丢失原有内存地址,造成内存泄漏。必须先用临时变量接收结果,检查成功后再赋值。

5. 缺失关键错误检查

  • fopen失败后未终止函数,后续操作NULL指针会直接崩溃。
  • strtok可能返回NULL(比如行格式不符合预期),直接访问会触发空指针引用,需要每次检查tok是否有效。

修复后的代码

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

// 补全代码依赖的结构体定义(根据原代码推断)
typedef struct {
    int day;
    int month;
    int year;
} Date;

typedef struct user {
    char username[50];
    char name[50];
    char gender;
    Date birth_date;
    Date account_creation;
    char pay_method[20];
    char account_status[20];
} User;

void readsaveusers(char* filename, User **users, int *user_count) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("Error reading file\n");
        *users = NULL;
        *user_count = 0;
        return;
    }

    char line[200];
    *users = NULL;
    *user_count = 0;

    while (fgets(line, 200, file) != NULL) {
        // 去除行尾换行符,避免解析干扰
        size_t len = strlen(line);
        if (len > 0 && line[len-1] == '\n') {
            line[len-1] = '\0';
        }

        // 安全扩容:用临时变量接收realloc结果
        User *temp = realloc(*users, sizeof(User) * (*user_count + 1));
        if (temp == NULL) {
            printf("Memory allocation failed\n");
            free(*users); // 释放已分配内存,防止泄漏
            *users = NULL;
            *user_count = 0;
            fclose(file);
            return;
        }
        *users = temp;

        // 逐段解析并检查有效性
        char *tok = strtok(line, ";");
        if (tok == NULL) continue;
        strncpy((*users)[*user_count].username, tok, sizeof((*users)[*user_count].username)-1);
        (*users)[*user_count].username[sizeof((*users)[*user_count].username)-1] = '\0';

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        strncpy((*users)[*user_count].name, tok, sizeof((*users)[*user_count].name)-1);
        (*users)[*user_count].name[sizeof((*users)[*user_count].name)-1] = '\0';

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        (*users)[*user_count].gender = tok[0];

        tok = strtok(NULL, "/");
        if (tok == NULL) continue;
        (*users)[*user_count].birth_date.day = atoi(tok);

        tok = strtok(NULL, "/");
        if (tok == NULL) continue;
        (*users)[*user_count].birth_date.month = atoi(tok);

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        (*users)[*user_count].birth_date.year = atoi(tok);

        tok = strtok(NULL, "/");
        if (tok == NULL) continue;
        (*users)[*user_count].account_creation.day = atoi(tok);

        tok = strtok(NULL, "/");
        if (tok == NULL) continue;
        (*users)[*user_count].account_creation.month = atoi(tok);

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        (*users)[*user_count].account_creation.year = atoi(tok);

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        strncpy((*users)[*user_count].pay_method, tok, sizeof((*users)[*user_count].pay_method)-1);
        (*users)[*user_count].pay_method[sizeof((*users)[*user_count].pay_method)-1] = '\0';

        tok = strtok(NULL, ";");
        if (tok == NULL) continue;
        strncpy((*users)[*user_count].account_status, tok, sizeof((*users)[*user_count].account_status)-1);
        (*users)[*user_count].account_status[sizeof((*users)[*user_count].account_status)-1] = '\0';

        (*user_count)++;
    }

    printf("Saved %d users\n", *user_count);
    fclose(file);
}

// 调用示例
int main() {
    User *users;
    int count;
    readsaveusers("users.txt", &users, &count);

    // 使用完成后记得释放内存
    free(users);
    return 0;
}

额外优化说明

  • 改用strncpy替代strcpy,避免字符串过长导致缓冲区溢出。
  • 添加user_count参数,让外部能直接获取读取到的用户数量。
  • 处理fgets读取到的换行符,避免后续解析出错。
  • 内存分配失败时主动释放已分配内存,防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:15:38