分配内存并释放它们。我们应该将它们设置为NULL吗?

时间:2012-09-19 10:50:54

标签: c malloc free

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);
}

我在第二次免费电话会议上得到一个堆栈转储。但是作为安全措施,你应该经常检查以确保你没有尝试双重免费吗?

在释放它们之后,值得将指针设置为NULL吗?

db_row = NULL;

非常感谢任何建议,

4 个答案:

答案 0 :(得分:5)

  

但是作为安全措施,你应该经常检查以确保你没有尝试释放空指针吗?

使用free()指针调用NULL是安全的,不会发生任何事情。调用free()不会NULL指针,您可以明确地执行此操作。调用NULLfree()指针会阻止相同指针变量上的双重释放:

/* 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()。调用NULLfree()指针变量有助于但不提供保证,因为多个指针变量可以指向同一地址。


  

但是作为安全措施,你应该经常检查以确保你没有尝试双重免费吗?

无法查询指针变量以确定其保存的地址处的内存是否已为free() d。指针变量只保存一个地址。

答案 1 :(得分:3)

最好在释放它之后设置指向null的指针,除非你在变量范围的末尾;是的,free不这样做是正常的。

如果指针是null,则在其上调用free是安全的,对它的任何访问都将生成核心转储,这比内存损坏或双{{1}更容易调试如果使用未设置为free的释放指针,则可能发生这种情况。

答案 2 :(得分:2)

  

在释放内存之后,我仍然得到相同的内存地址,如果在分配任何内存之前不是第一种情况下它不是NULL?

因为free()仅释放分配给您的内存。它没有将指针设置为NULL

  

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

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

  

在释放后,是否值得设置NULL的指针?

这样做绝对没有任何价值,更常见的是它会隐藏你的问题,这些问题会以某种形式或其他形式引起丑陋。

这是一种防御性和可疑的编程风格,可避免悬空指针或双重免费问题,其中您试图保护自己免受{{1>}在 相同上的调用 指向同一个内存的 指针并且这些不同的指针被传递给free()时,更常出现双重自由问题。

指针free()的做法在第二个更常见的错误场景中没有任何作用。所有这些情况都只能通过编写一些好的思想和定期的代码审查来编写程序来避免。

答案 3 :(得分: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. 如果它是一个有效的指针,它会释放内存
  4. 你会在这里注意到没有关于更改ptr指向的地址。这是你要做的。所以这样做非常安全:

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

    现在你可以整天在指针p上打电话给free(),你就可以了。如果你担心双free()次调用会出错,那么在Linux libc(晚于5.4.23)和GNU libc(2.x)的最新版本中,有一个名为{{1}的安全机制。 }

    您不会看到堆栈崩溃,而是会看到如下消息: MALLOC_CHECK_

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

    1. *** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b008 ***关闭malloc检查并(可能)让您的程序崩溃
    2. export MALLOC_CHECK_=0您将收到上述警告信息
    3. export MALLOC_CHECK_=1将调用abort(1)并为您提供代码的回溯
    4. export MALLOC_CHECK_=2只是选项1 | 2