我的malloc函数的分配是否超出了我的预期

我的malloc函数的分配是否超出了我的预期,c,C,这是我试图运行的代码。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%

这是我试图运行的代码。
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));

    }
}
void DynamicMemoryAllocationUsingMalloc()
{
int*p,i;
如果((p=(int*)malloc(800))==NULL)
{
printf(“\n内存不足\n”);
出口(0);
}
对于(i=0;i<800;i++)
{
printf(“0x%x”,(p+i));
printf(“%d\n”,*(p+i));
}
}
但是在for循环中,当我打印地址时,我能够安全地跳过800个内存位置(使用整数指针
p
),每个4字节长(整数大小),总计3200字节。这是怎么可能的,或者我很幸运,即使我实际上正在进入一个尚未分配给我的程序的内存区域,也没有收到访问冲突错误?我看到所有内存位置都写入了垃圾,原因很明显,因为我没有将这些内存位置设置为任何值


注意:这是一个在Windows 7上运行的C程序。

C标准答案:访问超出分配的内存会导致未定义的行为

真实世界答案:您的程序使用malloc()分配内存,malloc()从操作系统(本例中为Windows)提供内存。但是,每个malloc()调用不会导致对操作系统的调用。事实上,Malloc通常会分配比现在需要多一点的内存,然后会断开一个至少是您请求的大小的块。这样做是出于性能原因,因为对操作系统的每次调用都有一点开销。此外,还有一个最小的“页面大小”,即可以从操作系统分配的最小内存单元。4096字节是一个典型的页面大小


因此,在您的情况下,您正在访问malloc从系统中提供但尚未分配使用的内存。您应该避免这种情况,因为下一次调用malloc可能会导致内存被分配用于其他目的。

这是一个未定义行为的示例。 从逻辑上讲,这个程序应该中断。但这不是因为进程映像有一些额外的空间,您可以在操作系统不发送segfault的情况下将其溢出。我的意思是,不是去800,而是去1000,10000,等等。最终,您将在任意次数的迭代中得到一个segfault

之所以可以这么高,是因为您的程序在ram中有很多开销,这些开销被允许溢出到内存中

这是怎么可能的,或者我很幸运,即使我实际上正在进入一个尚未分配给我的程序的内存区域,也没有收到访问冲突错误

当代码到达
printf(“%d\n”*(p+200))正在尝试读取已分配内存之外的内容。这是未定义的行为

UB是UB。这种情况可能每天都会发生,也可能在下次跑步时发生变化


你不走运。幸运的是你的代码就停在那里

即使读取未初始化的
int
数据也很困难。所以只要
printf(“%d\n”*(p+0)),代码就有UB(或者可能定义了实现)。IAC,代码可能就停在那里了


我的malloc函数的分配是否超出了我的预期

这是棘手的一点。调用UB的代码会产生有问题的结果。没有UB的代码没有测试问题的标准方法。确定这一点的唯一非UB方法是库是否提供带有答案的函数

printf("True size %lu\n", (unsigned long) True_size(p));
注:OP断言
int
为4字节

但是在for循环中,当我打印地址时,我能够安全地跳过800个内存位置(使用整数指针p),每个4字节长(整数大小),总计3200字节

我猜“安全”是指程序不会崩溃。当应用于航空旅行时,这是一个确定的定义,但不太适合于计算机程序

这是怎么可能的,或者我很幸运,即使我实际上正在进入一个尚未分配给我的程序的内存区域,也没有收到访问冲突错误

通过访问未分配的内存,程序表现出未定义的行为。你认识到这个问题,应该受到表扬。然而,引用@KerrekSB,“未定义的行为是未定义的”。一般来说,您不能假设未定义行为的任何特定表现形式

如果您的程序确实发生了崩溃,例如访问冲突,那么您可以确定它显示了未定义的行为,因为C没有定义任何产生该行为的方法。但仅仅因为它似乎做了你所期望的,并不意味着它的行为是被定义的。如果没有定义,那么一般来说,你也不能确信它是一致的


所以基本上,是的,你只是幸运而已。或者可能不走运。就我自己而言,我更希望程序崩溃,以便提醒我这个问题。

它工作可能是因为您没有达到当前分配给进程的内存范围。现代系统通常以4KB的页面为进程分配内存。您的第一次分配可能在一页的开头,而您正在窥探的内存可能在第一页未分配的剩余部分

操作系统无法检测无效内存访问,除非它们超出为进程分配的内存范围。就操作系统而言,它为您的进程提供了该页面,而进程正在使用它。它并不关心进程使用的malloc例程是否表示程序“拥有”了该内存


这可能是一个有趣的实验,看看你能读多远,然后你得到一个访问违规。只需循环并打印出每个地址,然后再尝试读取。

未定义的行为是未定义的。@KeithNicholas,不,编译器不一定能产生一致性