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

C语言嵌套结构体内存分配方法及代码实现疑问咨询

解决C语言结构体内存分配与物品添加的问题

看起来你在处理嵌套结构体的内存分配时,被指针逻辑绕晕了,我来帮你梳理现有代码的问题,再给出清晰的修正方案~

现有代码的核心错误

  • 指针成员访问混乱:在add_item里你直接用items访问,但items是inventory结构体的成员,必须通过invp->items来操作;而且不存在items->new_item这种成员,要先为单个item分配内存,再把它放到items数组里。
  • 内存分配语法错误:items->new_item->name = (strlen(buffer) + 1, sizeof(char));是完全错误的逗号表达式,实际应该用calloc/malloc为字符串分配对应长度的内存。
  • 结构体类型不匹配:create_character里c->Inventory = calloc(1, sizeof(inventory));是错的,因为Inventory是inventory结构体(不是指针),不能直接赋值指针类型,要初始化它的成员变量。
  • 返回值逻辑错误:add_item最后返回items完全不符合预期,应该返回修改后的inventory指针invp。

正确的内存分配步骤

  1. 初始化Character的Inventory:
    因为character里的Inventory是结构体(而非指针),创建角色时要把它的num_items设为0,items设为NULL,这样后续添加物品时能正确判断是否需要首次分配内存。

  2. 为Inventory的Items数组扩容:
    inventory里的items是item**(动态数组),每次添加物品时:

    • 如果是首次添加(num_items == 0),用calloc分配1个item*的空间;
    • 如果已有物品,用realloc扩容数组,增加1个item*的空间;
    • 然后为新的item单独分配内存,再填充物品的属性。

修正后的代码实现

先补充必要的宏和辅助函数

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

#define buf 256

// 辅助函数:移除字符串末尾的换行符
void remove_newline(char *str) {
    size_t len = strlen(str);
    if (len > 0 && str[len-1] == '\n') {
        str[len-1] = '\0';
    }
}

// 你定义的结构体
typedef struct{
    char *name;
    int price;
    double weight;
}item;
typedef struct{
    item **items;
    int num_items;
}inventory;
typedef struct{
    char *name;
    int level;
    long xp;
    inventory Inventory;
}character;

修正后的create_character函数

character *create_character(character *c) {
    if (c == NULL) {
        char buffer[buf] = {0};
        // 为角色分配内存,calloc会自动初始化0值
        character *new_char = calloc(1, sizeof(character));
        if (!new_char) { // 检查内存分配是否成功
            perror("Failed to allocate character");
            return NULL;
        }

        printf("Enter character name: ");
        fgets(buffer, buf, stdin);
        remove_newline(buffer);
        // 为角色名字分配内存
        new_char->name = calloc(strlen(buffer) + 1, sizeof(char));
        if (!new_char->name) {
            perror("Failed to allocate character name");
            free(new_char); // 分配失败要释放已分配的内存
            return NULL;
        }
        strcpy(new_char->name, buffer);

        printf("Enter level: ");
        scanf("%d", &new_char->level);
        while(getchar() != '\n'); // 清除输入缓冲区的残留换行

        printf("Enter XP: ");
        scanf("%ld", &new_char->xp);
        while(getchar() != '\n');

        // 初始化角色的背包:物品数为0,物品数组为空
        new_char->Inventory.num_items = 0;
        new_char->Inventory.items = NULL;

        return new_char;
    } else {
        printf("ERROR: Character Already Exist.\n");
        return c; // 返回原角色指针
    }
}

修正后的add_item函数

inventory *add_item(inventory *invp) {
    // 如果传入的背包为空,先创建一个新背包
    if (invp == NULL) {
        invp = calloc(1, sizeof(inventory));
        if (!invp) {
            perror("Failed to allocate inventory");
            return NULL;
        }
        invp->num_items = 0;
        invp->items = NULL;
    }

    // 扩容物品数组:增加一个item指针的空间
    item **temp_items = realloc(invp->items, (invp->num_items + 1) * sizeof(item*));
    if (!temp_items) {
        perror("Failed to reallocate items array");
        return invp; // 分配失败返回原背包,避免内存泄漏
    }
    invp->items = temp_items;

    // 为新物品分配内存
    item *new_item = calloc(1, sizeof(item));
    if (!new_item) {
        perror("Failed to allocate item");
        // 扩容失败,把物品数组缩回原来的大小
        invp->items = realloc(invp->items, invp->num_items * sizeof(item*));
        return invp;
    }
    // 把新物品放到数组的末尾
    invp->items[invp->num_items] = new_item;

    // 输入物品属性
    char buffer[buf] = {0};
    printf("Enter item name: ");
    fgets(buffer, buf, stdin);
    remove_newline(buffer);
    new_item->name = calloc(strlen(buffer) + 1, sizeof(char));
    if (!new_item->name) {
        perror("Failed to allocate item name");
        free(new_item);
        // 缩容物品数组
        invp->items = realloc(invp->items, invp->num_items * sizeof(item*));
        return invp;
    }
    strcpy(new_item->name, buffer);

    printf("Enter item price: ");
    scanf("%d", &new_item->price);
    while(getchar() != '\n');

    printf("Enter item weight: ");
    scanf("%lf", &new_item->weight); // 注意是%lf,对应double类型
    while(getchar() != '\n');

    // 物品数量加1
    invp->num_items++;

    return invp;
}

使用示例

int main() {
    character *my_char = create_character(NULL);
    if (my_char) {
        // 给角色添加物品
        add_item(&my_char->Inventory);
        
        // 后续可以添加查看角色和物品的函数,记得用完要释放内存
        // 释放顺序:先释放每个物品的name,再释放物品本身,然后释放物品数组,最后释放角色的name和角色
    }
    return 0;
}

额外提示

  • 内存泄漏检查:使用完结构体后一定要逐层释放内存,比如遍历背包里的每个物品,先free(item->name),再free(item),然后free(invp->items),最后free(character->name)和free(character)。
  • 错误处理:每次内存分配后都要检查是否返回NULL,避免程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:45:57