3
gcc (GCC) 4.7.0
c89

你好,

我想知道我在这里的想法是否正确。当我使用 malloc 分配内存时。malloc 将返回一个指向内存大小的指针。

因此,在我分配内存之前,所有指针的值都将为 NULL。

使用此代码段:

struct address *db_row = NULL;

db_row = malloc(sizeof(struct address));
db_row->name = malloc(sizeof(char) * 10);
db_row->email = malloc(sizeof(char) *10);

free(db_row->name);
free(db_row->email);
free(db_row);

在分配内存之前,我已经在 db_row 的 gdb 调试器中完成了此操作:

(gdb) p db_row
$20 = (struct address *) 0x0
(gdb) p *db_row
Cannot access memory at address 0x0

这是正确的,因为没有分配内存地址。在我分配内存后,当我做同样的事情时,我会得到以下信息:

(gdb) p db_row
$25 = (struct address *) 0x602310
(gdb) p *db_row
$26 = {id = 0, set = 0, name = 0x0, email = 0x0}

但是,在我释放内存之后,我仍然得到相同的内存地址,在分配任何内存之前,它不应该像第一种情况那样为 NULL 吗?

释放内存后:

(gdb) p db_row
$28 = (struct address *) 0x602310
(gdb) p *db_row
$27 = {id = 6300480, set = 0, name = 0x602330 "", email = 0x602350 " #`"}

如您所见,它仍然指向相同的内存位置,这是正确的吗?

最后,我在最后添加了这个,看看我是否可以做双重免费:

if(db_row != NULL) {
    free(db_row);
}

if(db_row != NULL) {
    free(db_row);
}

我在第二次调用 free 时得到了堆栈转储。但是作为一项安全措施,您是否应该始终检查以确保您没有尝试进行双重免费?

释放指针后是否值得将指针设置为 NULL?

db_row = NULL;

非常感谢您的任何建议,

4

4 回答 4

5

但是作为一种安全措施,您是否应该始终检查以确保您没有尝试释放 NULL 指针?

free()使用指针调用NULL是安全的,不会发生任何事情。调用free()没有NULL指针,您可以显式执行此操作。NULL调用后的指针free()会阻止对同一指针变量的双重释放:

/* Assuming 'db_row' is referring to a valid address
   at this stage the following code will not result
   in a double free.*/
free(db_row);
db_row = NULL;
free(db_row);

如果另一个指针变量指向相同的地址并被传递给,free()那么仍然会发生双释放。

仅仅因为一个指针不是 -NULL并不能保证它指向一个有效的地址。确保free()不会出现 double 是程序员的责任。NULL在调用后对指针变量进行调用free()有助于但不提供保证,因为多个指针变量可以指向同一个地址。


但是作为一项安全措施,您是否应该始终检查以确保您没有尝试进行双重免费?

没有办法通过查询指针变量来确定它所持有的地址处的内存是否已经被free()d。一个指针变量保存一个地址,仅此而已。

于 2012-09-19T10:53:58.217 回答
3

null除非您位于变量范围的末尾,否则最好在释放指针后设置指针;free是的,不这样做是正常的。

如果指针是null,则调用它是安全的,并且对它的任何访问都将生成核心转储,这比使用未设置为 的释放指针时可能发生的free内存损坏或双倍更容易调试。freenull

于 2012-09-19T10:57:34.893 回答
2

释放内存后,我仍然获得相同的内存地址,在分配任何内存之前,它是否应该像第一种情况那样为 NULL?

因为free()只释放分配给你的内存。它不会将指针设置为NULL

但是作为一种安全措施,您是否应该始终检查以确保您没有尝试释放 NULL 指针?

如果传递给free()的指针是空指针,则不会发生任何操作(C99 第 7.20.3.2 节)。

NULL释放它们后值得设置指针吗?

这样做绝对没有任何好处,更多时候它会隐藏你的问题,这会以某种或其他形式抬起他们丑陋的头。

这是一种防御性和可疑的编程风格,以避免悬空指针或双重释放问题,其中你试图保护自己不free()同一个指针调用。实际上,当你使用不同的指针指向同一个指针时,双重释放问题通常会发生或不会发生内存和这些不同的指针被传递给free().

在第二种也是更常见的错误场景中,制作指针的做法NULL没有任何作用。所有这些情况只能通过编写程序、进行一些良好的思考和定期的代码审查来避免。

于 2012-09-19T10:52:38.987 回答
2

为了在这里澄清,我将引用 malloc 的手册页:

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

所以,回顾一下:

  1. Free 接受由内存分配函数返回的指针(NULL 或有效)
  2. 如果它为 NULL,则不会发生任何事情
  3. 如果它是一个有效的指针,它会释放内存

您会注意到这里它没有说明更改ptr指向的地址。那是你的事。所以这样做非常安全:

int *p = malloc(sizeof(int));
*p = 5;
printf("p=%d\n",*p);
free(p);
p = NULL;

现在你可以free()整天在指针 p 上打电话,你就没事了。如果您担心双重free()调用出现错误,在最新版本的 Linux libc(5.4.23 之后)和 GNU libc(2.x)上,有一个安全机制,称为MALLOC_CHECK_

您将看到如下消息,而不是堆栈崩溃: *** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b008 ***

您可以通过以下方式使用它:

  1. export MALLOC_CHECK_=0关闭 malloc 检查并(可能)让您的程序崩溃
  2. export MALLOC_CHECK_=1你会收到上面的警告信息
  3. export MALLOC_CHECK_=2将调用 abort(1) 并为您提供代码的回溯
  4. export MALLOC_CHECK_=3只是选项 1|2 一起
于 2012-09-19T11:59:00.063 回答