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;
非常感谢您的任何建议,
但是作为一种安全措施,您是否应该始终检查以确保您没有试图释放NULL指针?
使用NULL
指针调用free()
是安全的,不会发生任何事情。调用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()
。在调用free()
之后调用NULL
指针变量有帮助,但不能提供保证,因为多个指针变量可以指向同一地址。
但作为一项安全措施,你是否应该始终检查以确保你没有试图进行双重免费?
无法查询指针变量来确定其所在地址的内存是否已为free()
d。指针变量只包含地址。
最好在释放指针后将其设置为null
,除非您位于变量范围的末尾;是的,CCD_ 14不这样做是正常的。
如果指针是null
,则在其上调用free
是安全的,并且对其的任何访问都将生成核心转储,这比使用未设置为null
的释放指针时可能发生的内存损坏或双free
更容易调试。
释放内存后,我仍然会得到相同的内存地址,在分配内存之前,它是否应该像第一种情况一样为NULL
因为free()
只释放分配给您的内存。它不将指针设置为NULL
。
但是作为一种安全措施,您是否应该始终检查以确保您没有试图释放NULL指针
如果传递给free()
的指针为空指针,则不会发生任何操作(C99第7.20.3.2节)。
释放指针后,是否值得设置指向
NULL
的指针
这样做绝对没有任何好处,更常见的情况是,它最终会隐藏你的问题,这会以某种或其他形式引起他们丑陋的头脑。
这是一种防御性和可疑的编程风格,以避免悬挂指针或双自由问题,其中您试图保护自己免受free()
在相同指针上被调用的影响。实际上,当不同的指针指向同一内存,并且这些不同的指针被传递到free()
时,通常会出现双自由问题。
使指针NULL
的做法在第二个也是更常见的bug场景中没有任何作用。所有这些情况只能通过编写程序来避免,方法是投入一些好的思想和定期的代码审查。
为了在这里说清楚,我将引用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.
所以,概括一下:
- Free获取内存分配函数返回的指针(NULL或有效)
- 如果为NULL,则不会发生任何事情
- 如果它是一个有效的指针,它将释放内存
您会注意到,在这里,它对更改ptr
所指向的地址没有任何内容。这是您的责任。因此,这样做非常安全:
int *p = malloc(sizeof(int));
*p = 5;
printf("p=%dn",*p);
free(p);
p = NULL;
现在,你可以整天在指针p上调用free()
,你就可以了。如果你担心双free()
调用会出错,那么在最新版本的Linux libc(5.4.23之后)和GNU libc(2.x)上,有一种安全的机制,叫做MALLOC_CHECK_
您将看到以下消息,而不是出现堆栈崩溃:*** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b008 ***
您可以通过以下方式使用它:
export MALLOC_CHECK_=0
关闭malloc检查并(可能)让程序崩溃export MALLOC_CHECK_=1
您将收到上述警告信息export MALLOC_CHECK_=2
将调用abort(1)并返回代码export MALLOC_CHECK_=3
只是选项1|2