这是我正在尝试运行的代码。 malloc
函数分配800个字节。
void DynamicMemoryAllocationUsingMalloc()
{
int* p,i;
if((p = (int*) malloc(800)) == NULL)
{
printf("\n Out of Memory \n");
exit(0);
}
for(i =0;i < 800;i++)
{
printf(" 0x%x", (p + i));
printf(" %d\n", *(p + i));
}
}
但是在打印地址的for循环中,我能够安全地跳过800个内存位置(使用整数指针p
),每个4字节长(整数的大小),相当于3200字节。这是怎么可能的,或者我很幸运没有得到访问冲突错误,即使我实际上进入了我尚未分配给我的程序的内存区域?我看到垃圾写在所有内存位置的原因显而易见,因为我没有将这些内存位置设置为任何内容。
注意:这是在Windows 7上运行的C程序。
答案 0 :(得分:5)
这是怎么可能的,或者我很幸运没有得到访问冲突错误,即使我真的进入了我尚未为我的程序分配的内存区域?
当代码到达printf(" %d\n", *(p + 200));
时,试图读取外部分配的内存。那是未定义的行为 UB。
UB是UB。它可能每天都会发生,或者在下次运行时更改。
你不幸运。幸运的是你的代码会在那里停止。
即使阅读未初始化的int
数据,也是UB。所以代码只要printf(" %d\n", *(p + 0));
就有UB(或者可能是实现定义的)。 IAC,代码可以在那里停止。
我的malloc函数分配的次数超过了我的意图吗?
这是棘手的一点。调用UB的代码会产生可疑的结果。没有UB的代码没有标准的方法来测试问题。确定这一点的唯一非UB方式是库是否提供了具有答案的函数。
printf("True size %lu\n", (unsigned long) True_size(p));
注意:OP断言int
是4个字节。
答案 1 :(得分:5)
它的工作可能是因为您没有达到目前为该过程分配的内存范围。现代系统通常将内存分配给4千字节的进程。您的第一次分配可能在页面的开头,而您正在侦听的内存可能位于该第一页的未分配的剩余部分中。
操作系统无法检测到无效的内存访问,除非它们超出了为您的进程分配的内存范围。就操作系统而言,它为您的流程提供了页面和流程正在使用它。它并不关心你的进程使用的malloc例程是否说过你的程序&#34;拥有&#34;那个记忆呢。
在获得访问冲突之前,查看您可以阅读的内容可能是一个有趣的实验。在尝试阅读之前,只需将每个地址循环并打印出来。
答案 2 :(得分:2)
但是在我打印地址的for循环中,我能够安全地跳过800个内存位置(使用整数指针p),每个4字节长(整数大小),相当于3200字节。
我猜“安全”你的意思是程序不会崩溃。当应用于航空旅行时,这是一个正确的定义,但不适合计算机程序。
这是怎么可能的,或者我很幸运没有得到访问冲突错误,即使我真的进入了我尚未为我的程序分配的内存区域?
通过访问未分配的内存,您的程序会显示未定义的行为。认识到这个问题,你会受到赞扬。但是,引用@KerrekSB,“未定义的行为是未定义的”。一般来说,您不能假设未定义行为的任何特定表现。
例如,如果您的程序确实发生崩溃,并且存在访问冲突,那么您可以确定它已经展示了未定义的行为,因为C没有定义任何产生该行为的方法。但仅仅因为它似乎做了你所期望的并不意味着它的行为是定义的。如果没有定义,那么一般来说,你也不能确信它是否一致。
所以基本上,是的,你很幸运。或者也许不走运。我自己,我宁愿让程序崩溃,以便我收到警报。
答案 3 :(得分:1)
这是未定义行为的示例。 从逻辑上讲,这个程序应该打破。但它并不是因为过程映像有一些额外的空间,你可以在没有操作系统发送段错误的情况下溢出。我的意思是,不是去800,而是上升到1000,10000,等等。最终,您将在任意数量的迭代中获得段错误。
你可以这么高的原因是因为你的程序在ram中有很多开销,这个开销被允许溢出。
答案 4 :(得分:-3)
C标准答案:访问超出分配范围的内存会导致未定义的行为。
真实世界的答案:您的程序使用malloc()分配内存,malloc()从操作系统(在本例中为Windows)中提供内存。但是,每次malloc()调用都不会导致对操作系统的调用。实际上,Malloc通常会分配比现在需要的内存更多的内存,然后将中断至少是您请求的大小的块。这是出于性能原因而完成的,因为每次调用操作系统都会产生一些开销。此外,还有一个最小“页面大小”,它是可以从操作系统分配的最小内存单元。 4096字节是典型的页面大小。
因此,在您的情况下,您正在访问malloc已从系统配置但尚未分配使用的内存。你应该避免这种情况,因为下一次调用malloc可能会导致内存被分配用于其他目的。