Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在指针上调用free两次_C_Pointers_Malloc_Free_Dynamic Memory Allocation - Fatal编程技术网

C 在指针上调用free两次

C 在指针上调用free两次,c,pointers,malloc,free,dynamic-memory-allocation,C,Pointers,Malloc,Free,Dynamic Memory Allocation,我在课堂上被教导,对指针调用两次free()是非常非常糟糕的。我知道,在释放指针之后立即将其设置为NULL,这是一种很好的做法 然而,我仍然没有听到任何关于这是为什么的解释。据我所知,按照malloc()的工作方式,它应该在技术上跟踪它分配给您使用的指针。那么,为什么它不知道它通过free()接收的指针是否已被释放 我很想了解,当您在以前已被释放的位置上调用free()时,内部会发生什么情况。当您使用malloc时,您是在告诉PC您想在堆上为您保留一些内存位置。计算机返回指向寻址空间的第一个字节

我在课堂上被教导,对指针调用两次
free()
是非常非常糟糕的。我知道,在释放指针之后立即将其设置为
NULL
,这是一种很好的做法

然而,我仍然没有听到任何关于这是为什么的解释。据我所知,按照
malloc()
的工作方式,它应该在技术上跟踪它分配给您使用的指针。那么,为什么它不知道它通过
free()
接收的指针是否已被释放


我很想了解,当您在以前已被释放的位置上调用
free()
时,内部会发生什么情况。

当您使用
malloc
时,您是在告诉PC您想在堆上为您保留一些内存位置。计算机返回指向寻址空间的第一个字节的指针

当您使用
free
时,实际上是在告诉计算机您不再需要该空间,因此它会将该空间标记为可用于其他数据


指针仍然指向该内存地址。此时,堆中的相同空间可以由另一个
malloc
调用返回。第二次调用
free
时,释放的不是以前的数据,而是新数据,这可能对您的程序不利;)

要回答您的第一个问题

那么,为什么它不知道它通过
free()
接收的指针是否已被释放

因为,C标准中的
malloc()
规范并不强制要求这样做。调用
malloc()
或函数族时,它会返回一个指针,并在内部存储分配给该指针的内存位置的大小。这就是
free()
不需要大小来清理内存的原因

而且,一旦
free()
-d,实际分配的内存将仍然依赖于实现。调用
free()。因此,此时跟踪分配的指针是非常不必要的。保留所有的回溯将是操作系统不必要的负担

然而,出于调试目的,一些库实现可以为您完成这项工作,比如DUMA或dmalloc,最后但并非最不重要的是Valgrind的memcheck工具

现在,从技术上讲,
C
标准没有指定在已经空闲的指针上调用
free()
时的任何行为。是的

C11
,第§7.22.3.3章,
free()
功能

[…]如果 参数与内存管理系统先前返回的指针不匹配 函数,或者如果已通过调用
free()
realloc()
释放空间,则 行为是未定义的


当您调用
malloc
时,会得到一个指针。运行库需要跟踪
malloc
ed内存。通常,
malloc
不存储与
malloc
ed内存分离的内存管理结构,而是存储在一个位置。因此x字节的
malloc
实际上需要x+n个字节,其中一种可能的布局是前n个字节包含一个链表结构,该链表结构带有指向下一个(可能是上一个)分配内存块的指针

当您
free
一个指针时,函数
free
可以遍历它的内部内存管理结构,并检查您传入的指针是否为
malloc
ed的有效指针。只有这样,它才能访问内存块的隐藏部分。但是做这个检查会非常耗时,特别是如果你分配了很多。所以
free
只是假设您传入了一个有效的指针。这意味着它直接访问内存块的隐藏部分,并假设那里的链表指针有效

如果您两次
释放
一个块,那么您可能会遇到这样的问题:有人执行了一个新的
malloc
,获得了刚才释放的内存,并覆盖了它,第二个
释放
从中读取无效指针


free
d指针设置为
NULL
是一种很好的做法,因为它有助于调试。如果访问
free
d内存,您的程序可能会崩溃,但它也可能只是读取可疑值,稍后可能会崩溃。找到根本原因可能很难。如果将
free
d指针设置为
NULL
,当您试图访问内存时,程序将立即崩溃。这在调试过程中有很大帮助。

C标准只规定对
malloc
及其家族函数返回的指针调用两次
free
,会调用未定义的行为。没有进一步解释为什么会这样。
但是,为什么它是坏的解释是:

两次释放同一块

要了解这种错误可能导致什么,我们应该记住内存管理器通常是如何工作的。通常,它会在内存中块本身之前存储所分配块的大小。如果我们释放了内存,这个内存块可能会被另一个
malloc()
请求再次分配,因此这个双重释放实际上会释放错误的内存块-导致我们在应用程序的其他地方有一个悬空指针。这样的bug往往比它们出现在代码中的地方晚得多。有时我们根本看不到它们,但它们仍然潜伏在我们周围,等待着一个机会来展示它们丑陋的脑袋

另一个可能出现的问题是,在释放的块与相邻的空闲块合并形成一个更大的空闲块,然后重新分配较大的块之后,将执行此双重空闲。在里面