【问题标题】:C Casting a variable of type double to a variable of type char when freeing memoryC释放内存时将double类型的变量转换为char类型的变量
【发布时间】:2013-06-11 17:36:15
【问题描述】:

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

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

【问题讨论】:

  • 你不需要在 C 程序中强制转换 malloc 的返回值。
  • 无论char * 还是void *free_and_null 都是建立在所有指针具有相同大小和表示的假设之上的。这是马虎。我不会用它。
  • *(char**)(&x)=NULL 不是未定义的行为吗? (当 x 为 double* 时)

标签: c pointers char malloc


【解决方案1】:

我必须同意你的看法 - 代码有点奇怪。作者没有理由不能轻松地使用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;
    }
}

【讨论】:

  • 我怀疑很多 C 代码仍然受到 C 早期版本的严重影响,尤其是定义 K&R 的“早期”。因此,尽管现在定义了free(NULL),但这肯定不是保证行为,比如说,20 年前。当我第一次学习 C 时,void 构造的使用也少了很多,那是在遥远的过去。或者我的记忆已经褪色了。
  • 我同意这一点,除了这个函数的返回类型是void,所以这指向其他事情。我不确定free(NULL) 的行为何时标准化。
  • 实际上,代码应该检查ptr 不是NULL,而不是*ptr。如果传入 NULL 指针,然后代码尝试取消引用它,就会发生有趣的事情。
  • @StarPilot,这将是一个很好的检查,是的。鉴于 OP 显示的示例,这不可能发生,但一点安全也不会受到伤害。
  • 我收回了。在正文中,K&R 说,“释放不是通过调用malloccalloc 获得的东西是一个可怕的错误。”但是,附录 B 指出,“free 释放了由p 指向的空间;如果pNULL,它什么也不做。p 必须是指向先前由calloc、@987654345 分配的空间的指针@,或realloc。”显然,我的记忆是出于对第 1 句的恐惧,而不是第 2 句的现实。
【解决方案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。

【讨论】:

    【解决方案3】:

    另一种避免指向指针的方法是:

    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 危险的常见警告......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 2015-10-11
      • 2021-05-03
      • 1970-01-01
      • 2020-07-17
      • 1970-01-01
      相关资源
      最近更新 更多