realloc()悬空指针和未定义的行为

时间:2014-09-27 08:19:27

标签: c pointers undefined-behavior realloc dangling-pointer

当你释放内存时,指向内存的指针会发生什么?他们立即变得无效吗?如果他们以后再次有效会怎么样?

当然,指针变为无效然后再次变为“有效”的通常情况是将某些其他对象分配到之前使用的内存,如果使用指针访问内存,那就是< em>显然未定义的行为。悬空指针记忆覆盖了第1课,差不多。

但是如果内存再次对同一个分配有效怎么办?只有一种标准方式可以实现:realloc()。如果你指向偏移malloc()的{​​{1}}'内存块中的某个位置,那么使用> 1将块缩小到小于偏移量,显然你的指针变得无效。如果然后再次使用realloc()增加块,至少覆盖悬空指针所指向的对象类型,并且在realloc()移动内存块的情况下,悬空指针是否再次有效?

这是一个极端的案例,我真的不知道如何解释C或C ++标准来解决它。以下是一个显示它的程序。

realloc()

3 个答案:

答案 0 :(得分:7)

  

当你释放内存时,指向内存的指针会发生什么?他们立即变得无效吗?

是的,当然。从C标准第6.2.4节开始:

  

对象的生存期是存储期间程序执行的一部分   保证为它保留。存在对象,具有常量地址并保留   它在其整个生命周期中的最后存储价值。如果一个对象被引用到它之外   一生,行为是不确定的。当指针变为不确定时,指针的值变得不确定   它指向(或刚刚过去)的对象到达其生命周期的末尾。

从第7.22.3.5节开始:

  

realloc函数释放ptr指向的旧对象并返回一个   指向具有size指定大小的新对象的指针。新内容   在解除分配之前,对象应与旧对象的对象相同,直到较小的对象   新旧尺寸。新对象中超出旧对象大小的任何字节都有   不确定的价值观。

请注意标准对旧对象新对象的引用,从realloc返回的是不同的对象比你以前的;它与执行free然后malloc没什么区别,并且无法保证两个对象具有相同的地址,即使新大小是&lt; =旧的大小......在实际实施中,他们经常会赢,因为不同大小的物体来自不同的自由列表。

  

如果他们以后再次有效会怎样?

没有这样的动物。有效性不是发生的事件,它是C标准所放置的抽象条件。你的指针可能恰好在某些实现中起作用,但是一旦释放了他们指向的内存,所有的赌注都会被取消。

  

但是如果内存再次对同一个分配有效怎么办?只有一种标准方式可以实现:realloc()

对不起,不,C标准不包含任何相关的语言。

  

如果你再使用realloc()再次将块增长回至至少覆盖悬空指针指向的对象类型,并且在任何情况下都没有realloc()移动内存块

你不知道它是否会......标准不保证任何此类事情。值得注意的是,当您重新分配到较小的大小时,大多数实现会在缩短的块之后立即修改内存;重新分配回原始大小将在添加的部分中有一些垃圾,它在缩小之前不会成为它。在一些实现中,一些块大小保持在该块大小的列表上;重新分配到不同的大小会给你完全不同的记忆。在具有多个线程的程序中,任何释放的内存都可以在两个realloc之间的不同线程中分配,在这种情况下,将强制将更大尺寸的realloc移动到另一个位置。

  

是悬空指针再次有效吗?

见上文;无效无效;没有回去。

  

这是一个极端的案例,我真的不知道如何解释C或C ++标准来解决这个问题。

它不是任何一种极端情况,我不知道你在标准中看到了什么,这很明显,释放的内存具有不确定的内容和任何指针的值进入或进入它也是不确定的,并且没有声称它们被后来的realloc神奇地恢复。

请注意,编写现代优化编译器是为了了解未定义的行为并利用它。一旦你重新分配字符串,overwrite就无效了,并且编译器可以随意删除它......例如,它可能位于编译器重新分配临时值或参数传递的寄存器中。无论是否有任何编译器执行此操作,都可以,正是因为标准非常清楚,当对象的生命周期结束时,对象的指针变得无效。

答案 1 :(得分:0)

  

如果你再使用realloc()再次将块增长回至至少覆盖悬空指针所指向的对象类型,并且在任何情况下都没有realloc()移动内存块,悬空指针是否再次有效? / p>

没有。除非realloc()返回空指针,否则调用将终止已分配对象的生命周期,这意味着指向它的所有指针都将变为无效。如果realloc()成功,则返回 new 对象的地址。

当然,它可能会发生与旧地址相同的地址。在这种情况下,使用指向旧对象的无效指针来访问新对象通常可以在C语言的非优化实现中使用。

但仍然是未定义的行为,并might actually fail积极优化编译器。

C语言不健全,通常由程序员来维护其不变量。如果不这样做将破坏与编译器的隐式契约,并可能导致生成错误的代码。

答案 2 :(得分:-1)

这取决于您对&#34;有效&#34;的定义。你已经完美地描述了这种情况。如果你想考虑&#34;有效&#34;,那么它是有效的。如果你不想考虑&#34;有效&#34;,那么它就无效了。