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

C语言结构体指针数组打印第3个元素异常求助

结构体动态数组读取文件时元素打印异常的问题修复

读取文件内容到结构体动态数组时,第3个元素打印异常,输出结果为host0host1♥host3,输入文件内容如下:

0 host0
1 host1
2 host2
3 host3
4 host4


问题根源分析

核心错误:内存分配计算逻辑错误

代码中realloc的参数计算存在运算符优先级问题:

local_name = realloc(local_name, total + 1 * sizeof(*local_name));

C语言中乘法*优先级高于加法+,实际计算结果为 total + (1 * sizeof(*local_name)),而非预期的(total + 1) * sizeof(*local_name)。这导致每次循环仅额外分配单个结构体的字节数,而非扩容为能容纳total+1个结构体的完整内存空间。当total增长到2时,内存空间不足以存储第3个结构体,访问local_name[2]触发内存越界,造成数据损坏,最终打印异常。

其他潜在问题

  • 使用全局变量total,破坏代码模块化,易引发变量污染
  • 未检查realloc、malloc的返回值,内存分配失败会直接导致程序崩溃
  • 主函数未关闭打开的文件,造成系统资源泄漏

修正后的完整代码

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

struct names
{
    int number;
    char *name;
};

void readNames(FILE *fpN, struct names **name, int *total)
{
    char sentence[512];
    struct names *local_name = *name;
    *total = 0; // 初始化计数

    while (fgets(sentence, sizeof(sentence), fpN))
    {
        // 修正内存分配计算,确保分配(total+1)个结构体的空间
        struct names *temp = realloc(local_name, (*total + 1) * sizeof(*local_name));
        if (temp == NULL) {
            perror("realloc failed");
            // 清理已分配内存,避免泄漏
            for (int i = 0; i < *total; i++) {
                free(local_name[i].name);
            }
            free(local_name);
            *name = NULL;
            *total = 0;
            return;
        }
        local_name = temp;

        char *token = strtok(sentence, " ");    // 提取数字
        if (token == NULL) {
            fprintf(stderr, "Invalid line format\n");
            continue;
        }
        local_name[*total].number = atoi(token);

        token = strtok(NULL, " \n"); // 提取名称
        if (token == NULL) {
            fprintf(stderr, "Missing name in line\n");
            continue;
        }

        // 分配名称内存并检查分配结果
        local_name[*total].name = malloc(strlen(token) + 1);
        if (local_name[*total].name == NULL) {
            perror("malloc failed");
            // 清理已分配资源
            for (int i = 0; i < *total; i++) {
                free(local_name[i].name);
            }
            free(local_name);
            *name = NULL;
            *total = 0;
            return;
        }
        strcpy(local_name[*total].name, token);

        (*total)++;
    }
    *name = local_name;

    // 测试打印所有元素
    for (int i = 0; i < *total; i++) {
        printf("%s ", local_name[i].name);
    }
    printf("\n");
}

int main(int argc, char **argv)
{
    FILE *fpN = NULL;

    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    fpN = fopen(argv[1], "r");
    if (fpN == NULL)
    {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }

    struct names *name = NULL;
    int total = 0;
    readNames(fpN, &name, &total);

    // 使用完毕后释放所有动态分配的内存
    for (int i = 0; i < total; i++) {
        free(name[i].name);
    }
    free(name);

    fclose(fpN); // 关闭文件,释放系统资源
    return EXIT_SUCCESS;
}

关键修改说明

  1. 修复内存分配计算:将total + 1 * sizeof(*local_name)改为(total + 1) * sizeof(*local_name),确保每次扩容能容纳足够数量的结构体。
  2. 替换全局变量:将total改为指针传递,避免全局变量的副作用,提升代码模块化程度。
  3. 添加内存分配检查:对realloc和malloc的返回值进行校验,分配失败时清理已分配资源,避免内存泄漏。
  4. 完善资源管理:主函数中添加文件关闭操作,程序结束前释放所有动态分配的内存。
  5. 增加格式校验:对strtok的返回值进行检查,处理格式错误的输入行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 01:15:46