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。
正确的内存分配步骤
初始化Character的Inventory:
因为character里的Inventory是结构体(而非指针),创建角色时要把它的num_items设为0,items设为NULL,这样后续添加物品时能正确判断是否需要首次分配内存。为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
相关产品推荐
相关产品推荐

