man的realloc()
页面说:
realloc()
函数将ptr
指向的内存块的大小更改为size
字节。内容将在从区域开始到新旧尺寸的最小范围内保持不变。如果新大小大于旧大小,则不会初始化添加的内存。
但是,如果新大小小于旧大小,则手册页不会说明会发生什么。例如,如果我有以下代码:
ptr = realloc(ptr, nsize); // Where nsize < the original size and ptr is of type void **
如果原始大小是size
,这是否意味着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?中所述的内存大小
现在你的问题是:
如果原始大小是
size
,这是否意味着ptr + nsize + 1
仍然包含分配的条目?
你无法保证。这是来自ptr + nsize
的未定义行为(感谢Sourav)。
为什么?此区域不再属于您的程序。
你可能有错误读取新的较小的数组,如果旧的数据在那里会产生有效的结果,这很可能是真的,但是:
ptr
将与新的ptr
不同,因此一些人忽略的返回值并且它“工作”直到它崩溃),在这种情况下,背后的是完全无关的数据。如果上述两个条件都没有发生,则数据很可能不变。 realloc
不会将某些不应该使用的内存设置为0。一些调试框架(我不记得的那些)在释放内存时放置了一个模式,所以如果你在程序中偶然发现这个模式,这清楚地表明你正在读取一个未分配/未初始化的内存,但它有开销,所以它是默认情况下没做。你可以“重载”内存分配函数来自己做。
无论如何,确保你没有读过新阵列,因为你找不到保证。
首先,
void **ptr = realloc(ptr, nsize);
是错误的,因为你正在使用ptr
未初始化(这里定义),并且根据realloc()
的C11
函数描述,章节§7.22.3.5
如果
ptr
是空指针,则realloc
函数的行为类似于指定大小的malloc
函数。否则,如果ptr
与先前由内存管理函数返回的指针不匹配,或者如果通过调用free或realloc
函数释放了空间,则行为未定义。 [...]
因此,当您传递包含不确定值的指针时,您的代码会调用未定义的行为。
但是,考虑到你的情况是这样的
void **ptr = malloc(size);
assert (ptr);
ptr = realloc(ptr, nsize);
这是一个非常糟糕的用法,如果realloc
失败(它不会改变原始内存并返回NULL
),你最终也会丢失实际的指针。使用中间变量来存储验证返回的指针,然后根据需要将其分配回原始变量。
那说,重新检查报价(强调我的)
realloc()
函数将ptr
指向的内存块的大小更改为size字节。内容将在从区域开始到新旧尺寸的最小范围内保持不变。如果新大小大于旧大小,则不会初始化添加的内存。
所以,回答
如果原始大小是
size
,这是否意味着ptr + nsize + 1
仍然包含分配的条目?
不,我们可以说。成功的realloc()
电话后,我们只允许访问ptr + nsize - 1
。尝试读取/写入ptr + nsize
及其以后是未定义的,因为该内存位置不再属于您的进程,并且内存位置“无效”。
无论如何,你不应该对ptr + nsize - 1
以外的内容感到烦恼。