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

如何优雅处理连续内存分配中的内存分配失败问题?

内存分配失败的简洁处理方案

针对你遇到的多段内存分配时错误处理繁琐的问题,这里提供三种实用且简洁的解决思路:

方案一:使用goto统一清理点(C语言通用方案)

把所有内存释放逻辑集中到一个标签位置,每次分配失败后直接跳转到该位置执行清理,避免重复编写释放代码。这种方式是C语言中处理此类问题的标准做法,逻辑清晰且代码简洁。

修改后的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#define HASH_MAXSIZE  193
#define HASH_NODE_MAXSIZE  65535

struct code_info
{
    char infos[256];
    uint8_t code;
};

struct hash_node
{
    struct code_info* infos;
    struct hash_node* next;
};

struct hash_table
{
    struct hash_node* table;
};

struct myobject
{
    struct hash_table* code_table;
    struct hash_node* node_buffer;
    struct code_info* info_buffer;
};

int main(int argc, char** argv)
{
    struct myobject * my = NULL;
    int ret = EXIT_SUCCESS;

    // 分配myobject并初始化指针为NULL,避免野指针
    my = malloc(sizeof(struct myobject));
    if (!my) {
        fprintf(stderr, "分配myobject失败: %s\n", strerror(errno));
        ret = EXIT_FAILURE;
        goto cleanup;
    }
    memset(my, 0, sizeof(struct myobject));

    my->code_table = malloc(HASH_MAXSIZE * sizeof(struct hash_table));
    if (!my->code_table) {
        fprintf(stderr, "分配code_table失败: %s\n", strerror(errno));
        ret = EXIT_FAILURE;
        goto cleanup;
    }

    my->node_buffer = malloc(HASH_NODE_MAXSIZE * sizeof(struct hash_node));
    if (!my->node_buffer) {
        fprintf(stderr, "分配node_buffer失败: %s\n", strerror(errno));
        ret = EXIT_FAILURE;
        goto cleanup;
    }

    my->info_buffer = malloc(HASH_NODE_MAXSIZE * sizeof(struct code_info)); 
    if (!my->info_buffer) {
        fprintf(stderr, "分配info_buffer失败: %s\n", strerror(errno));
        ret = EXIT_FAILURE;
        goto cleanup;
    }

    // 这里编写正常业务逻辑

cleanup:
    // 按分配逆序释放,避免依赖问题
    if (my && my->info_buffer) free(my->info_buffer);
    if (my && my->node_buffer) free(my->node_buffer);
    if (my && my->code_table) free(my->code_table);
    if (my) free(my);
    return ret;
}

方案二:封装分配与清理函数

将内存分配的错误检查封装成通用函数,同时编写专门的清理函数负责释放所有资源,主代码只需调用封装后的函数,错误处理逻辑会更简洁。

示例代码:

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

#define HASH_MAXSIZE  193
#define HASH_NODE_MAXSIZE  65535

struct code_info
{
    char infos[256];
    uint8_t code;
};

struct hash_node
{
    struct code_info* infos;
    struct hash_node* next;
};

struct hash_table
{
    struct hash_node* table;
};

struct myobject
{
    struct hash_table* code_table;
    struct hash_node* node_buffer;
    struct code_info* info_buffer;
};

// 安全分配函数,失败时打印错误并返回NULL
static void* xmalloc(size_t size) {
    void* ptr = malloc(size);
    if (!ptr) {
        fprintf(stderr, "内存分配失败: %s\n", strerror(errno));
    }
    return ptr;
}

// 统一清理myobject的所有资源
static void cleanup_myobject(struct myobject* my) {
    if (!my) return;
    free(my->info_buffer);
    free(my->node_buffer);
    free(my->code_table);
    free(my);
}

int main(int argc, char** argv)
{
    struct myobject * my = xmalloc(sizeof(struct myobject));
    if (!my) {
        return EXIT_FAILURE;
    }
    memset(my, 0, sizeof(struct myobject));

    my->code_table = xmalloc(HASH_MAXSIZE * sizeof(struct hash_table));
    if (!my->code_table) {
        cleanup_myobject(my);
        return EXIT_FAILURE;
    }

    my->node_buffer = xmalloc(HASH_NODE_MAXSIZE * sizeof(struct hash_node));
    if (!my->node_buffer) {
        cleanup_myobject(my);
        return EXIT_FAILURE;
    }

    my->info_buffer = xmalloc(HASH_NODE_MAXSIZE * sizeof(struct code_info)); 
    if (!my->info_buffer) {
        cleanup_myobject(my);
        return EXIT_FAILURE;
    }

    // 业务逻辑

    cleanup_myobject(my);
    return EXIT_SUCCESS;
}

方案三:一次性分配整块内存

如果所有需要的内存大小都是编译期确定的固定值,可以一次性分配足够的整块内存,再通过指针偏移拆分到各个成员。这种方式要么全部分配成功,要么全部失败,无需处理部分释放的情况,错误处理最简单。

示例代码:

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

#define HASH_MAXSIZE  193
#define HASH_NODE_MAXSIZE  65535

struct code_info
{
    char infos[256];
    uint8_t code;
};

struct hash_node
{
    struct code_info* infos;
    struct hash_node* next;
};

struct hash_table
{
    struct hash_node* table;
};

struct myobject
{
    struct hash_table* code_table;
    struct hash_node* node_buffer;
    struct code_info* info_buffer;
};

int main(int argc, char** argv)
{
    struct myobject * my = NULL;
    // 计算总内存大小:myobject + code_table + node_buffer + info_buffer
    size_t total_size = sizeof(struct myobject) 
                      + HASH_MAXSIZE * sizeof(struct hash_table)
                      + HASH_NODE_MAXSIZE * sizeof(struct hash_node)
                      + HASH_NODE_MAXSIZE * sizeof(struct code_info);

    // 一次性分配整块内存
    void* mem_block = malloc(total_size);
    if (!mem_block) {
        fprintf(stderr, "总内存分配失败: %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    // 拆分内存块到各个指针
    my = mem_block;
    my->code_table = (struct hash_table*)((char*)mem_block + sizeof(struct myobject));
    my->node_buffer = (struct hash_node*)((char*)my->code_table + HASH_MAXSIZE * sizeof(struct hash_table));
    my->info_buffer = (struct code_info*)((char*)my->node_buffer + HASH_NODE_MAXSIZE * sizeof(struct hash_node));

    // 初始化所有内存(可选,根据需求)
    memset(mem_block, 0, total_size);

    // 业务逻辑

    // 只需释放一次整块内存
    free(mem_block);
    return EXIT_SUCCESS;
}

方案选择建议

  • goto统一清理:适合绝大多数场景,是C语言社区公认的规范写法,避免重复代码且逻辑清晰。
  • 封装分配与清理函数:适合需要多次创建/销毁该对象的场景,将逻辑复用,主代码更简洁。
  • 一次性分配:适合所有内存大小固定的场景,内存管理成本最低,错误处理最简单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:07:17