在C中重用已释放的指针

这个网站上有很多关于在使用后释放指针的问题,并且进一步将它们设置为NULL。 争论很激烈,主题看似平分。 例如: 这个问题 。 一般来说,我对释放指针很困惑。

想象一下,你有一个指向一些内存空间的指针。 使用空格后,释放指针但不将其设置为NULL。 稍后,你有另一个指针调用malloc()或一些模拟,它被分配内存,包括先前释放的内存(原始指针仍指向)。 如果这个新指针写入此内存块,会发生什么? 直觉上什么都不会发生,但早先提供的链接中的OP写道它会使程序崩溃。


所以我的问题是:

  1. 给定一个释放指针,是什么阻止您将指针重新分配给新的内存位置? 为什么重用已释放的指针是“坏”的做法? 如果调用free(ptr)只将此内存返回给操作系统,为什么不能重新分配指针以便其他内存位置并重用它?

     char *ptr = malloc(sizeof(*ptr)); //first allocation free(ptr); //release memory ptr = NULL; ptr = malloc(sizeof(*ptr)); //reallocate 
  2. 为什么写入以前释放的内存块,仍然有原始指针,导致程序崩溃? – 请参阅上面链接的问题的第一篇文章的第一段(如果我误解了本段的意图,请解释,因为不明确是否再次使用该指针来写入内存或创建新指针。)

给定一个释放指针,是什么阻止您将该指针重新分配给新的内存位置?

从技术上讲,没什么。 您甚至不需要在释放和重新分配指针之间设置ptr = NULL 。 但是,当释放和重新分配由其他代码行分隔时,将指针设置为NULL可能会略微提高可读性。

为什么写入以前释放的内存块,仍然有原始指针,导致程序崩溃?

只要您的程序不尝试取消引用该指针,只需按住指向可通过另一个指针访问的内存块的指针即可。 不幸的是,即使您取消引用释放的指针,它也不一定会导致程序崩溃:通常情况下,这种行为会被忽视。 但它仍然是一种未定义的行为。 程序的另一部分可能有与您期望的不兼容的书面数据,在这种情况下,您将看到极难找到或解释的错误。

  1. 由于原始指针现在再次指向已分配的空间,因此可以使用它。 但是,这样做是个坏主意; 分配内存的代码认为它具有对它的控制权,如果使用旧指针的代码修改数据,则会感到不安。 此外,新代码可能存储了旧指针所期望的不同类型的数据,因此使用旧指针的代码将无法理解正在发生的事情。

    在您的示例中,重用指针变量是一个非问题。 第二个malloc()返回的值可能与第一个返回的值相同,或者可能不同,但是(即使没有赋值NULL)重用指针就好了(只要你随后释放了第二次分配)。

  2. 如果空间被释放,则可能(尽管不太可能)空间未被O / S取消映射,并且不再是程序可用的有效地址的一部分。 更有可能的是,数据意味着什么会导致程序崩溃而不是将空间返回到操作系统,但这两种情况都是可能的。

简介:不要使用旧的指针值来访问重新分配的内存 – 这将导致不快乐。

“为什么写入以前释放的内存块,仍然有原始指针,导致程序崩溃? – 请参阅上面链接问题的第一篇文章的第一段(如果我错过解释的意图这一段,请解释一下,因为它没有明确表示是否再次使用该指针来写入内存或者是否创建了新指针。)“

我认为在它被释放后重复使用相同的内存空间等于“犯罪” ,至少基于Kmem(平板分配)的设计(我认为主要用于linux ..如果我错了就纠正我)。

要了解我们需要了解内部工作原理的原因(您可以跳过并在最后阅读结论):

  1. OS将整个动态可分配内存划分为页面。 这些页面中的每一个都被分配用于保存对象(以及一些用于管理这些对象和页面的对象)。 一个页面只能有一个内存大小的对象。 例如,如果页面大小是1024字节,并且页面将管理的对象是32字节。 然后将整个页面“CAN”分成最多1024/32个对象。

在简单的嵌入式系统中,存储器中的许多页面被分成通常大小为2 ^ y的对象(例如,8字节,16字节等)。 所以当你通过malloc请求z字节的内存时,在哪里

16

系统从具有自由对象的某个页面中保存的32字节对象池中返回一个对象。 在为此对象分配后,OS会对“slab”数据结构进行更改,并将给定地址处的对象标记为非空闲。

当你调用free()时,对象作为一个自由对象返回到slab池,如果发生其他malloc调用,操作系统可以重新分配它。 此调用可以由您的代码或在os中运行的其他组件进行。

**因此,如果您重用了之前为您的代码分配的免费内存。 然后你可能会写入一些可能使用的内存位置:

  1. 通过您的代码或
  2. OS中运行的其他一些组件**

此外,操作系统重新分配指针的其他组件也可能会覆盖您的数据。

这可能会导致严重的数据损坏。

此外,请确保不要通过malloc()请求向内存写入更多数据。 这样做可能会导致:

  1. 其他一些组件数据已损坏
  2. 或者某些内存管理数据结构被破坏(如slab,cache-managers等)。

你没有正确使用malloc()函数,请检查文档 ,这是正确的用法,因为它返回一个指针:

 char *b; b = (char *)malloc(42*sizeof(char)); 

还必须使用sizeof()来确定指针内容的大小(即char或其他),而不是指针本身的大小(除非你存储指针数组,这里不是这种情况)。

没有必要将释放的指针设置为NULL,它只是没有任何意义。 重新为释放指针分配空间也没有问题,因为malloc()将返回指向内存块的指针,并且您将先前释放的指针分配给返回我的malloc()指针。

请注意,如果要调整内存块的大小,请使用realloc()