内存缩小时的realloc()行为

时间:2019-03-13 13:01:26

标签: c dynamic-memory-allocation realloc

realloc()的{​​{3}}页显示:

  

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

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

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

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

感谢您的帮助。

2 个答案:

答案 0 :(得分:8)

首先您可能是说:

void **ptr = malloc(nsize*2);

然后

ptr = realloc(ptr, nsize);

或安全方式:

void **ptr2 = realloc(ptr, nsize);
if (ptr2 != NULL)
{
   ptr = ptr2;
} // else failure

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

现在,系统按照Can I assume that calling realloc with a smaller size will free the remainder?

中所述减小内存大小

现在您的问题是:

  

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

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

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

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

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

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

无论如何,请确保您没有读过新数组,因为并不能保证找到的结果。

答案 1 :(得分:5)

首先

 void **ptr = realloc(ptr, nsize); 

是错误的,因为您使用的是未初始化的ptr(在此处定义),并且根据realloc()的{​​{1}}函数说明,第7.22.3.5章

  

如果C11空指针,则ptr函数的行为类似于realloc函数,   指定的大小。否则,如果malloc之前由内存返回的指针不匹配   管理功能,或者是否已通过调用free或   ptr函数,其行为未定义。 [...]

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

但是,考虑到您的情况是

realloc

如果void **ptr = malloc(size); assert (ptr); ptr = realloc(ptr, nsize); 失败(它不会更改原始内存并返回realloc),这将是非常糟糕的用法,您最终也将丢失实际的指针。使用中间变量来存储验证返回的指针,然后根据需要将其分配回原始变量。

也就是说,重新检查引号(强调我的

  

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

所以,回答

  

如果原始大小为ptr,是否意味着size仍包含分配的条目?

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

无论如何,您都无需为ptr + nsize以外的内容而烦恼。