3

在处理库时,在提供的示例源代码中,我找到了以下代码:

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 语言的了解仍然有限,但无论如何,任何人都可以解释为什么这样做以及这是否是一个好的做法。

4

3 回答 3

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;
    }
}
于 2013-06-11T17:39:33.977 回答
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 **这将是一个更合适的签名。您经常看到人们将 C 代码char*用作“通用”类型的指针类型——这是错误的,在这种情况下没有充分的理由使用 char。

于 2013-06-11T17:40:00.163 回答
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 危险的常见警告......

于 2013-06-13T10:40:37.643 回答