为什么malloc(1)用于存储4字节整数?

根据我的理解,malloc(x)返回一个x字节长的内存块。

所以要存储一个4字节的整数,我会这样做:

int *p = (int *)malloc(4); *p = 100; 

因为sizeof(int)为我返回4。

但是,如果我这样做:

  int *p = (int *)malloc(1); *p = 100; 

它似乎工作完全相同,没有存储值的问题。

为什么malloc()请求的内存量似乎不重要? 4字节整数不应该需要malloc(4)吗?

如果这适用于您的情况,它只是偶然工作,并不保证工作。 它是未定义的行为(比较这个SO问题 ),一切都可能发生。

你期望发生什么? 你的程序崩溃了?

如果你更频繁地调用mallocfree一些,那么这可能仍会发生。 malloc通常比请求多占用一些字节,并使用额外的空间进行管理(所有内存块的链表,内存块的大小)。 如果你在分配的块之前或之后写了一些字节,那么你很可能会混淆内部管理结构,随后的malloc会崩溃。

如果malloc内部总是分配最少n个字节,那么如果访问字节n + 1,程序可能只会崩溃。 此外,操作系统通常仅基于页面保护存储器。 如果一个页面的大小为512字节,并且你的malloc-ed字节位于页面的中间,那么你的进程可能能够读写页面的其余部分,并且只有在访问下一个内存页面时才会崩溃。 但要记住:即使这有效,也是未定义的行为。

C编程语言使您能够用脚射击自己。

它故意给程序员带来负担,他们应该知道他们在做什么。 从广义上讲,原因是要实现性能,可读性和可移植性。

代码的行为未定义 。 如果要求1个字节,则期望只返回一个可用字节。 事实上,操作系统和C运行时库似乎给你的回馈多一点,这只不过是一种奇怪的特性。

在其他情况下,编译器可能只是吃你的猫。

最后,在调用malloc使用sizeof而不是硬编码int类型的大小:在许多系统上, sizeof(int)是2,4,这是常见的,标准允许所有大于1的值。 在您的情况下,可以使用sizeof(int)sizeof(*p) 。 有些人喜欢后者,因为那时你并没有在sizeof调用中硬编码变量的sizeof ,所以要防止可能的变量类型更改。 (注意, sizeof(*p)是编译时可评估的并且使用静态类型信息;因此如果你理解了它,它可以在p本身“存在”之前使用。)

它似乎工作完全相同,没有存储值的问题。

您使用代码调用未定义的行为,因此您无法确定它是否有效。 为了为整数分配内存,你应该这样做:

 int *p; p = malloc(sizeof (*p) ); //you can use sizeof(*p) as p is already declared and here you use the size of its content, which is actually the size of an int if (p != NULL) *p = 100; 

通常, malloc的实现方式是它分配的内存大小不小于段落大小等于16字节的大小。 所以当你需要例如4字节的内存时, malloc实际上分配了16个字节。 但是,此行为未在C标准中描述,您可能不会依赖它。 因此,这意味着您显示的程序具有未定义的行为。

我认为这是因为填充,即使你正在调用malloc(1)填充字节随内存而来。 请查看此链接http://www.delorie.com/gnu/docs/glibc/libc_31.html

malloc因为来自C运行时或OS内核的所有内存块分配函数都针对内存访问和对象对齐进行了优化。

此外, malloc具体地在分配的空间前分配隐藏的控制块以跟踪分配(所需空间,分配空间等)。

malloc还必须保证分配的内存地址适合任何存储对象 ,这意味着该块将在8,16,32或甚至64或128字节边界上启动,具体取决于处理器和硬件(通常是硬件)特殊MMU)。 边界也取决于访问速度,某些处理器具有不同的行为,具有不同的存储器访问(1,2,4,8,…字节)和地址边界。 此约束驱动malloc代码规范和分配器逻辑内存块分区。

在实际的一面让我们考虑一个X86处理器的分配器,它通常会返回一个在8字节边界(32位代码)上对齐的块,这对于int,float和even double非常有用。 为此, malloc将可用内存区域划分为最小分配空间的“块”。 当您分配甚至1个字节时,该函数至少分配一个块。 最终这个块可以承载一个整数,甚至是一个double, 但它依赖于实现,并且你不能认为它是确定性的 ,因为在同一函数的未来版本中,行为可以改变。

现在,我希望,这很清楚,因为你的代码似乎有效,请记住这是Undefined-Behavior,你必须保留它 。 IT现在可以工作,而不是下一次修订,它可能会在某些硬件上崩溃,而不会在另一台处理器或机器上崩溃。