内存收缩时 `realloc()` 的行为

Behavior of `realloc()` when the memory is shrunk

realloc()man 页说:

The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized.

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

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

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

感谢任何帮助。

首先,

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

是错误的,因为您使用的是未初始化的 ptr(此处已定义),并且根据 C11realloc() 函数描述,第 7.22.3.5 章

If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined. [...]

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

但是,考虑到您的情况类似于

void **ptr = malloc(size);
assert (ptr);
ptr = realloc(ptr, nsize);

这是一个非常糟糕的用法,如果 realloc 失败(它不会改变原始内存和 return NULL),你最终会失去实际的指针也是。使用中间变量存储验证 returned 指针,然后根据需要将其分配回原始变量。

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

The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized.

所以,回答

If the original size is size, does that mean ptr + nsize + 1 still contains allocated entries?

不,我们不能说。 realloc() 调用成功后,我们最多只能访问 ptr + nsize - 1。尝试 read/write ptr + nsize 及以后是未定义的,因为该内存位置不再属于您的进程并且该内存位置是 "invalid"。

无论如何,您不需要为 ptr + nsize - 1 以外的内容操心。

首先你的意思可能是:

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?

所述

现在你的问题是:

If the original size is size, does that mean ptr + nsize + 1 still contains allocated entries?

你不能保证这一点。这已经是 ptr + nsize 的未定义行为(感谢 Sourav)。

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

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

  • 系统可以保留相同的内存位置,但立即将此块重新用于其他数据
  • 系统可以移动新数据到另一个内存位置(所以旧的ptr与新的ptr不同,因此return 一些人忽略的值,它 "works" 直到它崩溃),在这种情况下,后面是完全不相关的数据。

如果以上两种情况都没有发生,很可能是数据没有变化。 realloc 不会将一些不应该使用的内存设置为 0。一些调试框架(我不记得是哪个)在释放内存时设置了一个模式,所以如果你在你的程序中偶然发现这个模式,这清楚地表明你正在读取 unallocated/uninitialized 内存,但它有开销,所以它不是默认完成的。您也可以 "overload" 内存分配函数来自己做。

无论如何,请确保您没有阅读新数组,因为无法保证您会找到什么。