当我只为它分配1个字节时,为什么C会正确输出整数?

时间:2019-03-08 20:09:17

标签: c malloc heap-memory

我一直在研究C语言中的内存分配和指针。给我的印象是,如果您没有为一个值分配足够的内存,然后尝试将该值放入该内存单元中,程序将崩溃或崩溃。行为不正确。 但是我得到的是看似正确的输出,而我期望其他输出。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    // Here we intentionally allocate only 1 byte,
    // even though an `int` takes up 4 bytes
    int * address = malloc(1);

    address[0] = 16777215; // this value surely takes more than 3 bytes. It cannot fit 1 byte.
    address[1] = 1337; // just for demo, let's put a random other number in the next memory cell.

    printf("%i\n", address[0]); // Prints 16777215. How?! Didn't we overwrite a part of the number?

    return 0;
}

为什么这样做? malloc实际分配的字节数是否超过传递给它的字节数?

编辑

感谢您的评论!但我想指出的是,能够写入未分配的内存并不是令我惊讶的部分,而且也不是问题的一部分。我知道写是有可能的,这是“未定义的行为”。

对我来说,意外的部分是,行address[1] = 1337;不会以任何方式破坏int处的address[0]值。

似乎对此的解释也有所不同。

  • @Mini建议这样做的原因是,由于跨平台的差异,malloc实际上分配了比所传递的更多的资源。

  • 注释中的
  • @P__J__说address[1]出于某种原因指向下一个sizeof(int)字节,而不是下一个字节。但是我不认为那时候可以控制这种行为,因为malloc似乎不知道我们将把什么类型放入分配的块中。

编辑2

因此,感谢您的评论,我相信我现在已经了解了程序的行为。 答案在于指针算法。程序“知道” address指针的类型为int,因此向其添加1(或通过address[1]访问)会得到位于该块的地址前4sizeof(int))个字节。

如果我们真的想要,我们可以将address[0]强制为address,只移动一个字节,使char *的值真正损坏,如{ {3}}

感谢所有人,尤其感谢@P__J__和@Blastfurnace!

2 个答案:

答案 0 :(得分:2)

malloc通常分配的资源超出您的实际要求(所有系统/环境/ OS依赖),这就是为什么它在您的情况下(有时)可用的原因。但是,这仍然是未定义的行为,它实际上只能分配1个字节(并且您正在写入可能未分配的堆内存)。

答案 1 :(得分:2)

C并不要求对数组访问进行任何类型的边界检查,并且可能溢出存储并将其写入技术上不属于您的内存。只要您不破坏任何“重要”的东西,您的代码就会出现以达到预期的效果。

但是,缓冲区溢出的行为是 undefined ,因此结果通常是不可预测的或可重复的。