内存缩小时的realloc()行为

S. *_*rma 4 c realloc dynamic-memory-allocation

手册页中realloc()说:

realloc()函数将指向的存储块的大小更改ptrsize字节。从区域开始到新旧大小的最小值之间的内容将保持不变。如果新的大小大于旧的大小,则不会初始化添加的内存。

但是,手册页没有说明如果新大小小于旧大小会发生什么。例如,如果我有以下代码:

ptr = realloc(ptr, nsize); // Where nsize < the original size and ptr is of type void **
Run Code Online (Sandbox Code Playgroud)

如果原始大小为size,是否表示ptr + nsize + 1仍包含分配的条目?

任何帮助表示赞赏。

Jea*_*bre 8

首先,您可能是说:

void **ptr = malloc(nsize*2);
Run Code Online (Sandbox Code Playgroud)

然后

ptr = realloc(ptr, nsize);
Run Code Online (Sandbox Code Playgroud)

还是安全的方法:

void **ptr2 = realloc(ptr, nsize);
if (ptr2 != NULL)
{
   ptr = ptr2;
} // else failure
Run Code Online (Sandbox Code Playgroud)

因为realloc(ptr,nsize)用于设置的值ptr是未定义的行为,并且可能会崩溃。

现在,系统按照“减少内存大小”中的说明进行操作,是否可以假设以较小的大小调用realloc将释放剩余的空间?

现在您的问题是:

如果原始大小为size,是否表示ptr + nsize + 1仍包含分配的条目?

您无法保证。这是ptr + nsize尚未定义的行为(感谢Sourav)。

为什么?该区域不再属于您的程序。

您可能会有错误读取新的较小数组,如果存在旧数据,这将产生有效结果,这可能是正确的,但是:

  • 系统可以保留相同的内存位置,但立即将此块重用于其他数据
  • 系统可以新数据移动到另一个存储位置(旧数据与新数据ptr不同ptr,因此某些人会忽略返回值并“起作用”直到崩溃),在这种情况下,后面是完整的无关数据。

如果以上两个条件都没有发生,则数据很可能不变。realloc不会将不应使用的某些内存设置为0。一些调试框架(我不记得的那些调试框架)在释放内存时放了一个模式,因此,如果您在程序中偶然发现此模式,则很明显地表明您正在读取未分配/未初始化的内存,但是它有开销,因此默认情况下未完成。您也可以自己“超载”内存分配功能。

无论如何,请确保您没有读过新数组,因为不能保证您会找到所得到的内容。


Sou*_*osh 5

首先,

 void **ptr = realloc(ptr, nsize); 
Run Code Online (Sandbox Code Playgroud)

是错误的,因为您使用的是ptr未初始化的(在此处定义),并且根据§7.22.3.5章中的realloc()功能描述C11

如果ptrnull指针,则该realloc函数的行为类似于malloc指定大小的函数。否则,如果ptr内存管理函数先前返回的指针不匹配,或者如果通过调用free或reallocfunction 释放了空间 ,则该行为是不确定的。[...]

因此,当您传递包含不确定值的指针时,您的代码将调用未定义的行为。

但是,考虑到您的情况是

void **ptr = malloc(size);
assert (ptr);
ptr = realloc(ptr, nsize);
Run Code Online (Sandbox Code Playgroud)

这是一种非常糟糕的用法,以防万一realloc失败(它不会更改原始内存并返回NULL),您最终也将丢失实际的指针。使用中间变量来存储验证返回的指针,然后根据需要将其分配回原始变量。

也就是说,重新检查报价(重点是我的

realloc()函数将指向的存储块的大小更改ptr为size字节。从区域开始到新旧大小的最小值之间的内容将保持不变。如果新的大小大于旧的大小,则不会初始化添加的内存。

所以,要回答

如果原始大小为size,是否表示ptr + nsize + 1仍包含分配的条目?

不,我们不能说。realloc()通话成功后,我们最多只能访问ptr + nsize - 1。尝试读/写ptr + nsize及后续操作未定义,因为该内存位置不再属于您的进程,并且该内存位置为“无效”。

无论如何,您都不需要去烦恼其他内容ptr + nsize - 1