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

如何动态分配结构体指针数组并逐次传入单个结构体参数?

动态维护MenuLabels结构体指针数组的实现方案

看起来你已经搭好了初始化的架子,现在咱们把addit函数补全,顺便加上内存释放的逻辑,确保整个流程的内存管理是安全的。

首先先上完整的代码:

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

typedef struct _DROP_DOWN_MENU_LABELS {
    char *title;
    char **items;
} MenuLabels;

// 初始化结构体指针数组,初始分配2个指针位置(一个存数据,一个做NULL标记)
MenuLabels ** ml_init(void) {
    MenuLabels **ml;
    // 用calloc初始化,自动置0,最后一个指针自然是NULL
    ml = calloc(2, sizeof(MenuLabels*));
    return ml;
}

// 向数组中添加新的菜单标签项
void addit(MenuLabels **mlabels, char *title, ...) {
    if (!mlabels || !title) {
        fprintf(stderr, "Invalid input parameters\n");
        return;
    }

    // 第一步:先找到当前数组中已使用的元素个数,确定扩容位置
    int count = 0;
    while (mlabels[count] != NULL) {
        count++;
    }

    // 第二步:动态扩容数组——当前数组长度是count+1(含NULL标记),扩容后长度+1
    MenuLabels **temp = realloc(mlabels, (count + 2) * sizeof(MenuLabels*));
    if (!temp) {
        fprintf(stderr, "Realloc failed\n");
        return;
    }
    mlabels = temp;
    mlabels[count + 1] = NULL; // 新的末尾标记为NULL

    // 第三步:分配新的MenuLabels结构体空间
    mlabels[count] = malloc(sizeof(MenuLabels));
    if (!mlabels[count]) {
        fprintf(stderr, "Malloc for MenuLabels failed\n");
        return;
    }

    // 第四步:复制title字符串(避免直接指向原指针,防止原内存被释放出问题)
    mlabels[count]->title = malloc(strlen(title) + 1);
    if (!mlabels[count]->title) {
        free(mlabels[count]);
        fprintf(stderr, "Malloc for title failed\n");
        return;
    }
    strcpy(mlabels[count]->title, title);

    // 第五步:处理可变参数的items,先统计item数量
    va_list args;
    va_start(args, title);
    char *item;
    int item_count = 0;
    while ((item = va_arg(args, char*)) != NULL) {
        item_count++;
    }
    va_end(args);

    // 分配items数组空间(最后加一个NULL标记)
    mlabels[count]->items = calloc(item_count + 1, sizeof(char*));
    if (!mlabels[count]->items) {
        free(mlabels[count]->title);
        free(mlabels[count]);
        fprintf(stderr, "Malloc for items failed\n");
        return;
    }

    // 再次遍历可变参数,复制每个item字符串
    va_start(args, title);
    int i = 0;
    while ((item = va_arg(args, char*)) != NULL) {
        mlabels[count]->items[i] = malloc(strlen(item) + 1);
        if (!mlabels[count]->items[i]) {
            // 内存分配失败时,要释放已分配的item和结构体资源
            for (int j = 0; j < i; j++) {
                free(mlabels[count]->items[j]);
            }
            free(mlabels[count]->items);
            free(mlabels[count]->title);
            free(mlabels[count]);
            va_end(args);
            fprintf(stderr, "Malloc for item failed\n");
            return;
        }
        strcpy(mlabels[count]->items[i], item);
        i++;
    }
    va_end(args);
}

// 释放整个结构体指针数组的内存
void ml_free(MenuLabels **mlabels) {
    if (!mlabels) return;

    int count = 0;
    while (mlabels[count] != NULL) {
        // 释放title
        free(mlabels[count]->title);
        // 释放每个item
        int i = 0;
        while (mlabels[count]->items[i] != NULL) {
            free(mlabels[count]->items[i]);
            i++;
        }
        // 释放items数组
        free(mlabels[count]->items);
        // 释放结构体本身
        free(mlabels[count]);
        count++;
    }
    // 释放结构体指针数组
    free(mlabels);
}

// 测试用例
int main() {
    MenuLabels **menu = ml_init();
    addit(menu, "File", "New", "Open", "Save", "Exit", NULL);
    addit(menu, "Edit", "Cut", "Copy", "Paste", NULL);

    // 打印测试
    int i = 0;
    while (menu[i] != NULL) {
        printf("Title: %s\n", menu[i]->title);
        printf("Items:\n");
        int j = 0;
        while (menu[i]->items[j] != NULL) {
            printf("  - %s\n", menu[i]->items[j]);
            j++;
        }
        printf("\n");
        i++;
    }

    // 释放内存
    ml_free(menu);
    return 0;
}

关键细节说明

  • 动态扩容逻辑:每次添加元素前,先遍历数组找到当前已有的元素个数,然后用realloc扩容数组,始终保持最后一个指针为NULL,方便后续遍历和判断数组边界。
  • 字符串内存管理:所有字符串(title和items)都单独分配内存,避免直接复用传入的指针,防止原内存被释放后出现野指针问题。
  • 错误处理:每一步内存分配都做了失败判断,一旦分配失败,会释放已经分配的资源,避免内存泄漏。
  • 内存释放:专门写了ml_free函数,递归式地释放所有层级的内存(item字符串→items数组→MenuLabels结构体→结构体指针数组)。

你可以直接运行这个测试用例,看看效果是否符合你的预期。如果有其他需求,比如修改扩容策略(比如每次扩容固定大小而不是+1),可以调整realloc的参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:31:13