我想将使用malloc()
分配的pointers
存储在array
中,然后在之后free
所有这些。但是,即使该程序不抱怨,它也不起作用。下面的cleanMemManager()
实际上不会free
内存,因为当在内部测试时main()
字符*pointer
没有NULL
,它会打印???
。
法典:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void **ptrList = NULL;
void tfree(void** ptr)
{
free(*ptr);
*ptr = NULL;
}
void* talloc(int size)
{
void* ptr = malloc(size);
ptrList[0] = ptr; ///No clue if this actually does what I think it does
return ptrList[0];
}
void initMemManager()
{
ptrList = (void**)malloc(sizeof(void**) * 3);
memset(ptrList, 0, sizeof(void**) * 3);
}
void cleanMemManager()
{
tfree(&ptrList[0]); //Doesn't free the right pointer it seems
}
int main()
{
initMemManager();
char* ptr = (char*)talloc(3);
cleanMemManager();
if (ptr != NULL) //This will trigger and I'm not expecting it to
printf("???");
getchar();
return 0;
}
我不明白用于此目的的语法,指针实际上根本没有被触摸吗?既然它不会抛出任何错误,那么它释放了什么呢?
在main
中,char *ptr = (char*)talloc(3);
声明ptr
是一个局部变量。它包含talloc
返回的值的副本,并且您的子例程都不知道ptr
或它在哪里。所以它们都不会改变ptr
的值。因此,当你达到if (ptr != NULL)
时,ptr
的值没有改变。
此外:
-
在
initMemManager
中,您应该在两个有sizeof(void**)
的地方使用sizeof(void *)
。在这些位置,您分配和复制的是对象void *
而不是void **
对象。 -
看起来您正在尝试实现一种智能内存管理器,该管理器可以在释放指针时自动设置指向
NULL
的指针。要在 C 中做到这一点,你必须放弃拥有指针的副本。例如,ptr
是ptrList[0]
的副本,但tfree
只设置它传递给NULL
的任何副本。我们可以为构建这样一个系统提供建议,但它很快就会变得很麻烦 - 您的内存管理器需要保留一个指针及其副本的数据库(以及从它们派生的指针,如通过数组算术)。或者你必须通过该ptrList
数组间接引用所有内容,这会给你的源代码增加一些混乱。不幸的是,C 不是一种好的语言。
释放不保证指向已分配块的指针将设置为 NULL。如果你真的尝试做
if (ptrList[0] != NULL)
printf("ptrList[0] != NULL");
您将看到程序不会输出,如果删除cleanMemManager()
函数调用,它将输出。这意味着tfree
函数按预期工作,它正在释放分配的内存。
现在至于为什么ptr
变量没有设置为 NULL,这仅仅是因为ptr
仍在存储旧地址。cleanMemManager()
无法改变变量ptr
。这通常称为悬空指针或释放后使用。
此外,free()
没有清理/清零分配的空间,该块只是标记为"空闲"。数据很可能会在内存中保留片刻,直到空闲块被另一个malloc
请求覆盖。