我一直在研究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
似乎不知道我们将把什么类型放入分配的块中。
因此,感谢您的评论,我相信我现在已经了解了程序的行为。
答案在于指针算法。程序“知道” address
指针的类型为int
,因此向其添加1
(或通过address[1]
访问)会得到位于该块的地址前4
(sizeof(int)
)个字节。
如果我们真的想要,我们可以将address[0]
强制为address
,只移动一个字节,使char *
的值真正损坏,如{ {3}}
感谢所有人,尤其感谢@P__J__和@Blastfurnace!
答案 0 :(得分:2)
malloc通常分配的资源超出您的实际要求(所有系统/环境/ OS依赖),这就是为什么它在您的情况下(有时)可用的原因。但是,这仍然是未定义的行为,它实际上只能分配1个字节(并且您正在写入可能未分配的堆内存)。
答案 1 :(得分:2)
C并不要求对数组访问进行任何类型的边界检查,并且可能溢出存储并将其写入技术上不属于您的内存。只要您不破坏任何“重要”的东西,您的代码就会出现以达到预期的效果。
但是,缓冲区溢出的行为是 undefined ,因此结果通常是不可预测的或可重复的。