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

C 分配内存并释放它们。我们应该将它们设置为NULL吗?,c,malloc,free,C,Malloc,Free,你好, 我想知道我的想法是否正确。当我使用malloc分配内存时。malloc将返回指向内存中某个大小的指针 因此,在分配内存之前,所有指针的值都将为NULL 使用此代码段: gcc (GCC) 4.7.0 c89 在分配内存之前,我已在db_行的gdb调试器中完成了此操作: struct address *db_row = NULL; db_row = malloc(sizeof(struct address)); db_row->name = malloc(sizeof(char)

你好,

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

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

使用此代码段:

gcc (GCC) 4.7.0
c89
在分配内存之前,我已在db_行的gdb调试器中完成了此操作:

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);
这是正确的,因为没有分配内存地址。 分配内存后,当我执行相同操作时,会得到以下结果:

(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}
正如您所看到的,它仍然指向相同的内存位置,这是正确的吗

最后,我在结尾添加了这个,以查看是否可以进行双重免费:

(gdb) p db_row
$28 = (struct address *) 0x602310
(gdb) p *db_row
$27 = {id = 6300480, set = 0, name = 0x602330 "", email = 0x602350 " #`"}
我在第二次调用free时得到一个堆栈转储。但是,作为一项安全措施,你是否应该经常检查以确保你没有试图做双重自由

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

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

if(db_row != NULL) {
    free(db_row);
}
非常感谢您的建议

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

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

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

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

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

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

这是一种防御性的、可疑的编程风格,以避免指针悬空或双重自由问题,即试图保护自己免受
free()
相同的指针上被调用。实际上,当不同的指针指向同一内存,并且这些不同的指针被传递到
free()
时,往往会出现双自由问题

在第二个也是更常见的bug场景中,使指针
NULL
无效的做法没有任何作用。所有这些情况都只能通过编写程序来避免,方法是进行一些好的思考和定期的代码检查

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

使用
NULL
指针调用
free()。调用
free()
不会
NULL
指针,您可以显式执行此操作
NULL
调用
free()
后调用指针将阻止对同一指针变量执行双自由:

db_row = NULL;
如果另一个指针变量指向同一地址,并被传递到
free()
,则仍然会出现双自由。

指针不为空并不保证它指向有效地址。程序员有责任确保不会出现双重
free()
s
NULL
调用
free()
后调用指针变量有帮助,但不能提供保证,因为多个指针变量可以指向同一地址


但是,作为一项安全措施,你是否应该经常检查以确保你没有试图做双重自由


无法查询指针变量以确定其所在地址的内存是否已被
free()
d。指针变量保存地址,仅此而已。

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


如果指针为
null
,则在其上调用
free
是安全的,并且对它的任何访问都将生成一个内核转储,这比使用未设置为
null

的已释放指针尝试清除此处的内存损坏或双重
free
更容易调试,我将引用malloc的手册页:

free()函数释放ptr指向的内存空间,该内存空间必须由先前对malloc()、calloc()或realloc()的调用返回。否则,或者如果之前已经调用了free(ptr),则会发生未定义的行为。如果ptr为NULL,则不执行任何操作。

因此,总结一下:

  • Free接受内存分配函数返回的指针(NULL或valid)
  • 如果为NULL,则不会发生任何事情
  • 如果它是有效指针,则会释放内存
  • 您会注意到,这里没有关于更改
    ptr
    指向的地址的内容。那由你来做。因此,这样做非常安全:

    /* 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);
    
    现在你可以整天用指针p调用
    free()
    ,你就没事了。如果您担心在最近版本的Linux libc(5.4.23之后)和GNU libc(2.x)上进行双重
    free()
    调用时出现错误,那么有一种安全机制,称为
    MALLOC\u CHECK

    您将看到如下消息,而不是堆栈崩溃:
    ***glibc检测到***./a.out:free():无效指针:0x0804b008***

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

  • 导出MALLOC\u CHECK\u=0
    关闭MALLOC CHECK并(可能)让程序崩溃
  • 导出MALLOC\u CHECK\u=1
    您将收到上述警告消息
  • export MALLOC\u CHECK\u2
    将调用abort(1)并返回代码跟踪
  • 导出MALLOC\u CHECK\u3
    只是选项1|
    int *p = malloc(sizeof(int));
    *p = 5;
    printf("p=%d\n",*p);
    free(p);
    p = NULL;