零大小的malloc

56

非常简单的问题,我写了下面这个程序:

#include <stdlib.h>
int main(int argc, char ** argv)
{
    void * ptr;
    ptr = malloc(0);
    free(ptr);
}

它在我的机器上没有段错误。这是stdlib中malloc和free的可移植行为,还是我在寻找麻烦?

编辑: 看起来不可移植的是malloc返回的值。问题是关于malloc(0) + free组合,而不是ptr的值。


2
请记住,如果这不起作用,就必须有很多特例代码。人们会根据变量或表达式一直malloc一定数量的字节,每次都必须检查零会很麻烦。 - David Thornley
相关的编程内容:https://dev59.com/JHI-5IYBdhLWcg3wFkOO - jldupont
我知道:对于这个已关闭的问题,我的评论来得非常晚。但是有时候使用malloc(0)是有用的,而这并没有被提到。在那些返回非NULL值的实现中,特别是在DEBUG版本中,它很可能会分配比您请求的更多的内存,并给您指向其内部标头之后的指针。如果您在一系列分配之前和之后获取此指针,则可以了解实际内存使用情况。 - Jesse Chisholm
7个回答

74

行为是实现定义的,您将接收到一个NULL指针或地址。然而,调用接收到的指针的free应该不会导致问题,因为:

  • free(NULL)没有问题,不执行任何操作
  • 如果地址是从malloc(或其他如calloc等)接收到的,则free(address)没有问题

如果返回一个地址,那么内存块的大小是多少? - Abhishek Jaiswal
@AbhishekJaiswal 这将会是零。 - Marco

36

可以返回NULL指针,也可以返回不能被解引用的非NULL指针,这两种方式都是标准允许的(参见7.20.3):

如果请求空间的大小为零,则行为是实现定义的:要么返回一个空指针,要么行为好像大小是一些非零值,除了返回的指针不应用于访问对象。


1
这并不是所问的问题。我不关心malloc返回的值,而是关于在指向malloc(0)返回的指针上调用free的问题。 - shodanex
8
这仍然是一个非常好的答案,因为它与Key的答案一起提供了完整的行为概述。 - schnaader
我认为应该是7.22.3,而不是7.20.3 - 好的,答案是在2009年写的, :) 我的意思是在C11中使用7.22.3。 - aqjune

4

抱歉给您带来麻烦,我应该先阅读man手册:

malloc() 分配大小为size的字节并返回指向分配内存的指针。内存不会被清除。如果size为0,则malloc()返回NULL或唯一指针值,稍后可以成功传递给free()。

free() 释放ptr指向的内存空间,该指针必须是之前调用malloc()、calloc()或realloc()返回的。否则,或者如果已经调用过free(ptr),就会发生未定义行为。如果ptr为NULL,则不执行任何操作。

至少对于gnu libc而言,这似乎是正确的。


4
“RTFM”是英文“Read The F***ing Manual”的缩写,意为“读那该死的手册”。它通常用于回答那些没有认真阅读相关文档或手册就问问题的人。 - Nick Dandoulakis

3
根据C标准,如果请求的空间大小为零,则行为是实现定义的:要么返回空指针,要么行为就像大小为非零值一样,但返回的指针不应用于访问对象。

0

这不是关于malloc(0)的结果,而是关于malloc(0) + free组合的问题。 - shodanex

-1

更新以考虑libt和Pax的评论:

调用malloc(0)的行为取决于实现,换句话说是不可移植的,并且未定义。

有关更多详细信息,请参阅CFaq问题的链接。


4
ISO标准非常清楚地区分了定义、实现定义和未定义。你也应该这样做。实现定义意味着它定义了,但是该实现的文档将告诉您它的作用。未定义意味着它可以做任何事情,包括但不限于彻底破坏宇宙。 - paxdiablo
感谢澄清(和点赞下降;-))。我在那里使用了“未定义”的术语,有些随意。我的错。 - Aditya Sehgal
给你一个赞,因为你改正了它 :-) - paxdiablo
很高兴看到这个答案改变了,+1。 - Johannes Schaub - litb
拥有实现定义行为并不会使代码无法移植。这段代码在一个平台上可能会将ptr设置为null,在另一个平台上则设置为非null,但只要不对其进行解引用操作,那么代码就是正确的,并且可以正常工作。 - M.M
显示剩余3条评论

-3
在我的经验中,我发现malloc(0)返回一个可以释放的指针。 但是,这会导致后续的malloc()语句出现SIGSEGV错误。 而且这种情况非常随机。
当我添加了一个检查,如果要分配的大小为零,则不调用malloc,我就解决了这个问题。
因此,我建议不要为大小为0的内存分配空间。
-Ashutosh

ISO C要求零大小的分配才能正常工作。它们可能会返回NULL,或者一个唯一的指针,稍后可以传递给free。如果没有最小可重现测试用例,并命名发生这种情况的确切环境:编译器版本、库、操作系统,则您的评论是无用的。 - Kaz
如果返回一个独特的指针,它将受到所有常规规则的约束。您不能访问其范围之外,这意味着指针不能被解引用:如果ptr来自malloc(size),那么((char *) ptr)]size]不是有效字节,在这种情况下,size为0。此外,您不能多次释放它。一旦您释放它,它就变得不确定;这些指针容易出现双重释放错误。假设malloc(0)的结果可以在两个或更多位置被释放的程序将在返回NULL的平台上运行,但在其他地方可能会失败。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接