怎么解决函数内申请内存,函数外释放的问题

现在我有个算法,需要动态决定生成的数组长度,如果我在函数内申请内存,然后返回未知长度的数组,就需要函数外来释放内存。但这种模式很不好,因为我只负责这个函数的实现,你不能要求别人帮你释放内存,应该怎么做合适??注意是C语言,不是C++。

就像计算一个信号的极值点,当你知道有多少个点,算法都已经做完了。

阅读 10.3k
8 个回答

设计一个生成数组的函数和销毁数组的函数,外部不应该关心数组怎么生成怎么销毁,应该都调用你包装好的函数进行生成销毁操作

这种情况下只能靠程序员自觉,可以说,只要你用了malloc分配了内存,谁也不能保证程序员会释放。
C没有办法解决这种问题,所以文档显的很重要,不懂看文档的人绝对写不到好的代码。
你不能要求别人帮你释放内存
也可以是我就是让你以我方式使用我的接口,如果你不释放内存,出了事情别找我。。

可以用 static 全局函数,如果不是多线程的话。

或者把流程拆开,先计算数组长度是多少,然后让别人申请内存递进算法里再让算法往数组里写数据,这样谁申请的内存就由谁释放。

回调函数是一种解决方案,不知有没更好的

大多数系统API的实践模式是,调用两次,第一次传入空指针,函数判断NULL,返回所需内存大小。外部分配内存后,才传入有效指针。
也可以提前约定一个足够大的内存空间大小(比如文件路径是MAX_PATH),确保能放下返回数据。
另外如果是一个程序里的话(不是跨DLL什么的),里面malloc,外面free也是可以的。free是自己知道内存块的大小的。

这种情况都是要求调用者来释放内存的,例子如 getline、asprintf。

写一个free()方法专门用于清理垃圾,写上注释,告诉别人这个类用完需要调它。

由于不同的编译器和库,其内部关于内存申请释放的实现不同,因此不能直接要求用户指定用某个函数释放内存,必须要单独自己封装一个释放的接口。有两种思路:

一是以指针作为参数得到数组地址,单独设计一个释放的函数,内部与你的获取数组函数内存管理函数一致。

BOOL CreateArray(int **pp)
{
    if (pp != NULL) {
        // 其他算法
        int *array = (int *)malloc(...);
        if (array != NULL) {
            *pp = array;
            return TRUE;
        }
    }
    return FALSE;
}
void CloseArray(int *p)
{
    if (p != NULL) {
        free(p);
    }
}
// 使用
int *array = NULL;
if (CreateArray(&array)) {
    // 创建成功,使用数组 arr
    // 使用完毕释放数组
    CloseArray(array);
}

二是学习微软,对外隐藏全部的结构,仅返回一个类似 HANDLE 这样的匿名类型,内部包装自己的数据结构,任何数据都通过这个 HANDLE 来访问。

// 声明自己的私有结构体
typedef struct {
    int *arr;
    // 其他成员变量
} EXAMPLE;

HANDLE CreateObject()
{
    EXAMPLE *handle = (EXAMPLE *)malloc(sizeof(EXAMPLE));
    if (handle != NULL) {
        // 其他算法
        handle->arr = (int *)malloc(...);
        if (handle->arr == NULL) {
            free(handle);
            handle = NULL;
        }
    }
    return (HANDLE)handle;
}
int *GetArray(HANDLE p)
{
    EXAMPLE *handle = (EXAMPLE *)p;
    if (handle != NULL) {
        return handle->arr;
    } else {
        return NULL;
    }
}
void CloseObject(HANDLE p)
{
    EXAMPLE *handle = (EXAMPLE *)p;
    if (handle != NULL) {
        if (handle->arr != NULL) {
            free(handle->arr);
        }
        free(handle);
    }
}
// 使用
HANDLE obj = CreateObject();
if (obj != NULL) {
    int *array = GetArray(obj);
    // 使用数组 arr
    CloseObject(obj);
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进