在处理库时,在提供的示例源代码中,我找到了以下代码:
x = (double *) malloc (narcs * sizeof (double));
dj = (double *) malloc (narcs * sizeof (double));
pi = (double *) malloc (nnodes * sizeof (double));
slack = (double *) malloc (nnodes * sizeof (double));
我发现这里没什么特别的,但在释放内存时,源代码示例执行以下操作:
free_and_null ((char **) &x);
free_and_null ((char **) &dj);
free_and_null ((char **) &pi);
free_and_null ((char **) &slack);
free_and_null代码是:
static void
free_and_null (char **ptr)
{
if ( *ptr != NULL ) {
free (*ptr);
*ptr = NULL;
};
};
我的问题不是为什么,当释放先前分配的内存时,它会对char双指针进行转换。我的问题是为什么这样做是这样的,使用自定义函数释放内存以及为什么选择char **
作为此函数的参数。
我知道当然这个问题正在发生,因为我对C语言的了解仍然有限,但无论如何,任何人都可以解释为什么要这样做,如果这是一个很好的做法。
答案 0 :(得分:9)
我必须同意你的看法 - 代码有点奇怪。作者没有理由不能轻易地使用void **
。
此外,if (*ptr != NULL)
检查是不必要的,因为free(NULL)
完全合法。大括号后的;
字符也不是必需的。
更简单的版本可能如下所示:
static void free_and_null(void **ptr)
{
free(*ptr);
*ptr = NULL;
}
此函数存在的原因是确保释放的指针设置为NULL
,这有助于检测释放后使用的错误并完全避免双重错误。
编辑:正如StarPilot在下面建议的那样,检查ptr
本身不是NULL可能是个好主意:
static void free_and_null(void **ptr)
{
if (ptr)
{
free(*ptr);
*ptr = NULL;
}
}
答案 1 :(得分:2)
额外的间接级别(**
)的原因是因为这允许free_and_null的作者将指针设置为NULL。如果他们只是传递*或x,他们就会得到一个按值传递的指针副本。
static void
free_and_null (char *ptr)
{
if ( ptr != NULL ) {
free (ptr);
// *ptr = NULL; CAN'T DO THIS NOW
};
};
在释放已分配的内存后将指针重置为NULL并不是一个坏主意,因为它可以帮助检测内存泄漏。我不会完全遵循上面作者的风格,但我认为这可以帮助你理解基本原理。正如卡尔指出void **
本来是一个更合适的签名。你经常看到人们使用char*
作为“通用”类型的指针类型的C代码 - 这是错误的,在这种情况下没有充分的理由使用char。
答案 2 :(得分:0)
避免指向指针的另一种方法就是:
void *free_and_null_back(void *p) {
free(p);
return NULL;
}
用法:
p = free_and_null(p);
或者,对于#define
粉丝:
#define free(p) free(p);(p)=null;
显然,关于#define的危险,所有常见的警告......