C Language 释放记忆


可以通过调用free()来释放动态分配的内存。

int *p = malloc(10 * sizeof *p); /* allocation of memory */
if (p == NULL) 
{
    perror("malloc failed");
    return -1;
}

free(p); /* release of memory */
/* note that after free(p), even using the *value* of the pointer p
   has undefined behavior, until a new value is stored into it. */

/* reusing/re-purposing the pointer itself */
int i = 42;
p = &i; /* This is valid, has defined behaviour */

p指向的内存在调用free()之后被回收(由libc实现或底层OS free() ,因此通过p访问该释放的内存块将导致未定义的行为 。引用已释放的存储器元素的指针通常称为悬空指针 ,并存在安全风险。此外,C标准规定即使访问悬空指针的值也有未定义的行为。请注意,指针p本身可以重新使用,如上所示。

请注意,您只能在直接从malloc()calloc()realloc()aligned_alloc()函数返回的指针上调用free() ,或者文档告诉您已经以这种方式分配了内存(函数)像strdup ()是值得注意的例子)。释放一个指针,

  • 通过对变量使用&运算符获得,或
  • 在分配的块的中间,

禁止。这样的错误通常不会被编译器诊断出来,但会导致程序在未定义的状态下执行。

有两种常见的策略可以防止这种未定义行为的实例。

第一个也是最好的很简单 - 当不再需要时, p本身就不再存在,例如:

if (something_is_needed())
{

    int *p = malloc(10 * sizeof *p);
    if (p == NULL) 
    {
        perror("malloc failed");
        return -1;
    }

    /* do whatever is needed with p */

    free(p);
}

通过在包含块结束之前直接调用free() (即} ), p本身不再存在。编译器将在任何尝试使用p之后给出编译错误。

第二种方法是在释放指向它的内存后使指针本身无效:

free(p);
p = NULL;     // you may also use 0 instead of NULL

这种方法的论据:

  • 在许多平台上,尝试取消引用空指针将导致即时崩溃:分段错误。在这里,我们至少得到一个指向被释放后使用的变量的堆栈跟踪。

    如果没有将指针设置为NULL我们就有悬空指针。该程序很可能仍然会崩溃,但后来,因为指针指向的内存将无声地被破坏。这些错误很难追踪,因为它们可能导致与初始问题完全无关的调用堆栈。

    因此,这种方法遵循快速失败的概念

  • 释放空指针是安全的。 C标准指定 free(NULL)无效:

    free函数导致ptr指向的空间被释放,即可用于进一步分配。如果ptr是空指针,则不执行任何操作。否则,如果参数与之前由callocmallocrealloc函数返回的指针不匹配,或者如果通过调用freerealloc释放了空间,则行为未定义。

  • 有时第一种方法不能使用(例如,内存在一个函数中分配,并且在一个完全不同的函数中稍后释放)