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

C语言嵌套结构体添加、删除函数实现错误排查

已定义的基础结构

当前定义了3个业务结构体,代码如下:

typedef struct {
    char *name; // allocated
    int commonality;
    int weight;
} monster;

typedef struct {
    char *name; // allocated
    char *description; // allocated
    double area;
    int monsters;
    monster **monsters; // allocated
} region;
typedef struct {
    char *name; // allocated
    double diameter;
    int regions;
    region **regions; // allocated
} planet;

目前已经实现了怪物实例创建函数:

monster *new_monster(char *name, int commonality, int weight);

需要实现两个功能函数:

void add_monster_to_region(region *r, char *mname, int mcommonality, int weight);
void delete_region_from_planet(planet *p, char *rname);

当前编写的add_monster_to_region逻辑存在问题,代码如下:

void add_monster_to_region(region *r, char *mname, int mcommonality, int mweight) 
{
    
    for (int i = 0; i < mcommonality; i++)
    {
        if (strcmp(mname, r->monsters[i]->name) == 0)
        {
            r->monsters[i]->name = mname;
        }

    }
}
现有代码错误说明

当前编写的add_monster_to_region存在以下核心问题:

  • 循环边界逻辑完全错误:遍历区域内怪物时,循环上限错误使用了传入的参数mcommonality(怪物常见度),正确的遍历上限应该是区域结构体中存储的现有怪物数量r->monsters。这个错误会导致两种严重问题:如果mcommonality大于当前区域怪物总数,会越界访问r->monsters数组触发内存崩溃;如果mcommonality小于现有怪物数,会漏遍历部分怪物。
  • 没有实现「新增怪物」的核心逻辑:函数整体只有遍历匹配同名怪物的分支,完全没有处理“怪物不存在时,扩容数组、创建新怪物实例、更新区域怪物计数”的新增逻辑,根本没有完成add的功能。
  • 同名匹配后的操作逻辑错误:就算匹配到同名怪物,代码直接将r->monsters[i]->name指针指向传入的mname,既没有释放name字段之前已分配的堆内存(造成内存泄漏),也没有更新怪物的commonality、weight属性;同时直接引用外部传入的字符串指针,一旦外部字符串被释放就会产生野指针。
  • 缺少入参合法性校验:没有判断传入的区域指针r、怪物名指针mname是否为空,空指针传入时会直接触发崩溃。
修正后参考实现

修正后的add_monster_to_region

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

void add_monster_to_region(region *r, char *mname, int mcommonality, int mweight) 
{
    // 空指针直接返回
    if (r == NULL || mname == NULL) return;

    // 先遍历现有怪物列表,检查是否存在同名怪物
    for (int i = 0; i < r->monsters; i++) {
        if (strcmp(mname, r->monsters[i]->name) == 0) {
            // 存在同名怪物直接更新属性即可,无需重复新增
            r->monsters[i]->commonality = mcommonality;
            r->monsters[i]->weight = mweight;
            return;
        }
    }

    // 未找到同名怪物,执行新增逻辑
    // 给怪物指针数组扩容,多存储1个怪物指针
    r->monsters = realloc(r->monsters, sizeof(monster*) * (r->monsters + 1));
    // 调用已实现的构造函数创建怪物实例
    monster *new_m = new_monster(mname, mcommonality, mweight);
    // 将新怪物存入数组末尾,更新怪物计数
    r->monsters[r->monsters] = new_m;
    r->monsters++;
}

配套delete_region_from_planet参考实现

void delete_region_from_planet(planet *p, char *rname)
{
    if (p == NULL || rname == NULL || p->regions == 0) return;

    int target_idx = -1;
    // 查找待删除区域的下标
    for (int i = 0; i < p->regions; i++) {
        if (strcmp(rname, p->regions[i]->name) == 0) {
            target_idx = i;
            break;
        }
    }
    // 未找到对应区域直接返回
    if (target_idx == -1) return;

    // 释放待删除区域的所有关联内存:先释放区域内的怪物,再释放区域自身
    region *del_r = p->regions[target_idx];
    for (int i = 0; i < del_r->monsters; i++) {
        free(del_r->monsters[i]->name);
        free(del_r->monsters[i]);
    }
    free(del_r->monsters);
    free(del_r->name);
    free(del_r->description);
    free(del_r);

    // 移动数组元素,覆盖被删除的位置
    for (int i = target_idx; i < p->regions - 1; i++) {
        p->regions[i] = p->regions[i+1];
    }
    // 更新区域计数,缩容数组
    p->regions--;
    if (p->regions == 0) {
        free(p->regions);
        p->regions = NULL;
    } else {
        p->regions = realloc(p->regions, sizeof(region*) * p->regions);
    }
}

说明:以上实现默认new_monster函数内部已经完成了怪物结构体内存分配、name字段的字符串堆拷贝逻辑,和代码注释中标注的各指针为“已分配”的约定一致。如果new_monster没有做字符串拷贝,需要在创建怪物时自行用strdup(mname)给name字段分配独立堆内存,避免野指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:36:48