代码之家  ›  专栏  ›  技术社区  ›  timetowonder

为什么当我只为一个整数分配一个字节时,C会正确地输出它?[副本]

  •  0
  • timetowonder  · 技术社区  · 6 年前

    我一直在研究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认为原因是 马洛克 实际上,由于跨平台的差异,分配的比传递的要多。

    • @评论里说 address[1] 由于某些原因,指向下一个sizeof(int)字节,而不是下一个字节。但我不明白是什么控制了这种行为,因为 马洛克 似乎不知道我们将在分配的块中放入什么类型。

    编辑2

    多亏了这些评论,我相信我现在理解了程序的行为。 答案在于指针算法。程序“知道”一个 address 指针类型为 int ,因此添加 1 到它(或通过 地址[1] )给出所在块的地址 4 ( sizeof(int) )前方字节。

    如果我们真的想,我们可以移动一个字节 腐败的 价值 地址[0] 通过强迫 地址 char * 如中所述 this answer

    感谢所有人,特别是感谢@p_u j_u和@blastfurth!

    2 回复  |  直到 6 年前
        1
  •  2
  •   Mini    6 年前

    malloc的分配常常比您实际要求的要多(所有系统/环境/操作系统都依赖),这就是它在您的场景中工作的原因(有时)。但是,这仍然是未定义的行为,它实际上只能分配1个字节(并且您正在写入可能未分配的堆内存)。

        2
  •  2
  •   John Bode    6 年前

    C不要求对数组访问进行任何类型的边界检查,而且有可能溢出存储并写入技术上不属于您的内存。只要你不破坏任何“重要”的东西,你的代码就会 出现 按计划工作

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

    推荐文章