Nov*_*vak 7 c memory-management realloc
如果做下一个:
int* array = malloc(10 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
他们使用realloc:
array = realloc(array, 5 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
在第二行(并且只有它),它可以返回NULL吗?
Mic*_*rny 11
是的,它可以.没有实现保证realloc(),即使收缩也可以返回不同的指针.
例如,如果特定实现对不同的对象大小使用不同的池,realloc()则实际上可以在池中为较小的对象分配新块,并在池中释放较大对象的块.因此,如果较小对象的池已满,则它将失败并返回NULL.
或者它可能只是决定移动块更好
我刚刚使用以下程序来获取glibc实际分配内存的大小:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int n;
for (n = 0; n <= 10; ++n)
{
void* array = malloc(n * sizeof(int));
size_t* a2 = (size_t*) array;
printf("%d -> %zu\n", n, a2[-1]);
}
}
Run Code Online (Sandbox Code Playgroud)
并且对于n <= 6,它分配32个字节,而对于7-10,它是48.
所以,如果萎缩int[10]到int[5],分配的规模将缩小,从48到32,可以有效提供16个免费字节.由于(因为它已被注意到)它不会分配少于32个字节的任何内容,因此丢失了这16个字节.
如果它将块移动到其他位置,则将释放整个48个字节,并且实际上可以放入其中的某些内容.当然,这只是一个科幻故事,而不是一个真正的实现;).
C99标准中最相关的引用(7.20.3.4 realloc函数):
返回
4该
realloc函数返回指向新对象的指针(可能与指向旧对象的指针具有相同的值),如果无法分配新对象,则返回空指针.
'May'是关键词.它没有提到可能发生的任何特定情况,所以你不能依赖它们中的任何一个,即使它们乍一看听起来很明显.
顺便说一句,我认为你可以考虑realloc()稍微弃用.如果你看一下C++,那么新的内存分配接口(new/ delete和分配器)甚至不支持这样的东西.他们总是希望你分配一个新的块.但这只是一个松散的评论.
其他答案已经解决了这个问题,但是假设您知道该realloc呼叫是“修剪”,则可以将其包装为:
void *safe_trim(void *p, size_t n) {
void *p2 = realloc(p, n);
return p2 ? p2 : p;
}
Run Code Online (Sandbox Code Playgroud)
返回值将始终指向一个size的对象n。
无论如何,由于的实现realloc知道对象的大小,因此可以确定它是“修剪”的对象,因此从实现质量的角度来看,如果不在内部执行上述逻辑,这在病理上是不好的。但是由于realloc不需要这样做,因此您应该自己进行操作,或者使用上述包装程序或在调用时使用类似的内联逻辑realloc。