我正在使用OS X.我已编写了一个简单的代码,如
pTest = (char*)malloc(sizeof(char) * 3);
pTest[0] = 0;
pTest[1] = 1;
pTest[2] = 2;
pTest = (char*)realloc(pTest, sizeof(char) * 2);
printf("%d %d %d %d\n", pTest[0], pTest[1], pTest[2], pTest[3]);
pTest[3] = 100; // memory access violation.
如果此代码不会导致访问冲突,为什么realloc需要?尽管我们在堆段中分配了一小块内存,但我们所要做的就是访问另一个索引,例如pTest[100]
,pTest[2048]
和pTest[65536]
。
有人可以解释为什么不会导致访问冲突?
答案 0 :(得分:4)
void *realloc(void *ptr, size_t size);
realloc()
函数将ptr指向的内存块的大小更改为size bytes。内容将在从区域开始到最小的范围内保持不变旧的和新的尺寸。
你缩小了尺寸:
pTest = (char*)realloc(pTest, sizeof(char) * 2);
^
|
changed size of array to two chars only
此最大索引值可以1
为pTest[1]
。
任何索引值> 1,导致内存冲突 - 非法内存访问 - 运行时未定义的行为。
答案 1 :(得分:3)
你在做什么是未定义的行为。它'可能'是accvio,它可能是段错误。另一方面,它可能会发送电子邮件给你的猫。您不能依赖未定义的行为,因为它未定义。
答案 2 :(得分:0)
首先,您使用mealloc
在堆中有一个内存存储0,1,2
。
然后你使用realloc(pTest sizeof(char )*2)
;它削减了内存,现在只有0,1
。
当您打印pTest[3],
时,您已经从已释放的内存中读取数据。可能内存仍然没有使用,只是保留旧值,但这不安全。
然后你给pTest[3]
一个值。但是你意识到你只有一个阵列大小2 吗?你只能使用pTese[0] and pTest[1]!
我修复了你的代码:
pTest = (char*)malloc(sizeof(char) * 3);
pTest[0] = 0;
pTest[1] = 1;
pTest[2] = 2;
pTest = (char*)realloc(pTest, sizeof(char) * 4);// at lest 4
printf("%d %d %d \n", pTest[0], pTest[1], pTest[2]);// pTest[3]) is still unkonw;
pTest[3] = 100; //it is ok now
答案 3 :(得分:0)
未定义访问已分配内存之外的内容。在达到某种分段边界之前,通常不会获得访问冲突。否则,如上所述,行为未定义。
使用数组时,请保持在索引边界内。如果您需要数组索引值的访问冲突警告,则必须自己添加它们。
此外,你的realloc只是给内存管理器一个线索,你不需要你最初分配的最后一个字节。存储器管理器可以返回相同的指针值或一些其他新的指针值。您唯一关心的是您不要超过内存分配。如果这样做,那么将导致未定义的行为,有时候在应用程序的后期很晚。
答案 4 :(得分:0)
它完全取决于内存分配器占用内存的位置和大小。
通常,内存取自“普通”堆空间的末尾,根据需要进行扩展。在释放之后,存在一定的滞后现象,以便不立即释放所有可能的内容,以便最小化对OS的调用次数。
此外,如果内存在堆末尾不,则释放的内存将仅添加到malloc()
可用的内存区域。它可能会更改其内容以便成为管理可用内存的链接列表的一部分,但读取访问将成功,因为它是分配给该进程的内存的一部分。
Onliy如果我在堆的末尾有相当大的部分,其free()
导致堆实际收缩,或者内存块太大以至于它是通过mmap()
分配的, free()
之后访问它实际上会导致访问冲突。