malloc(0)有什么意义?


Answers:


121

根据规范,malloc(0)将返回“可以成功传递给free()的空指针或唯一指针”。

基本上,这让您什么都没分配,但是仍然不用担心将“ artist”变量传递给对free()的调用。出于实际目的,它与执行操作几乎相同:

artist = NULL;

51
就个人而言,我认为将NULL设置为更好的跨平台策略,因为按规范保证free()可以在NULL输入上正常工作。
Reed Copsey 2010年

2
正如C. Ross提到的,从技术上讲,某些平台可以在此处返回一个指针(这是“可以传递给free的唯一指针”),但是如果您将其视为char *,则可能会给您一个无效的非终止字符。在跨平台的情况下依赖于此可能很危险。
Reed Copsey 2010年

9
真希望规范也能说“安全地传递给重新分配” -.-
hanshenrik

1
@NSAddict“ sizeof将返回0的空结构”,请提供示例,听起来像是语言扩展。
chux-恢复莫妮卡

1
@hanshenrik谁说你不能?realloc()允许您传递由返回的任何有效指针malloc()。应该足够了。
glglgl

51

C标准(C17 7.22.3 / 1)指出:

如果请求的空间大小为零,则行为是由实现定义的:返回空指针,或者行为类似于该大小为某个非零值,不同之处在于返回的指针不得用于访问对象。

因此,malloc(0)可以返回NULL不能取消引用的有效指针。无论哪种情况,调用free()它都是完全有效的。

我真的认为malloc(0)没有什么用,除非在malloc(n)例如循环中被调用的情况下,以及n可能为零)。

通过查看链接中的代码,我相信作者有两个误解:

  • malloc(0)始终返回有效的指针,并且
  • free(0) 不好。

因此,他确保artist和其他变量始终在其中具有某些“有效”值。评论内容如下:// these must always point at malloc'd data


10
它依赖于实现的事实使它或多或少完全没用-这是C标准最糟糕的部分之一,并且相当多的标准委员会(例如PJ Plauger)对此抱怨不已。

10
我同意。如果malloc(0)返回有效指针,则malloc()返回NULL始终表示“失败”,并且0不再是特殊情况,这更加一致。
Alok Singhal'1

1
由于malloc无法获取内存的情况是由实现定义的,因此实现可以简单地定义size-0分配总是不满足(ENOMEM),而现在malloc(0)返回0(带有errno==ENOMEM)是一致的。:-)
R .. GitHub停止帮助ICE

6
您可以realloc返回一个指针malloc(0)吗?可以realloc((char*)NULL)
Braden Best,

3
@Braden Best都是。
chux-恢复莫妮卡

11

malloc(0)行为是特定于实现的。该库可以返回NULL或具有常规的malloc行为,而不分配任何内存。无论做什么,都必须在某处记录下来。

通常,它返回有效且唯一的指针,但不应取消引用。还要注意,即使它实际上没有分配任何东西,它也可能消耗内存。

可以重新分配非null的malloc(0)指针。

逐字使用malloc(0)并没有多大用处。当动态分配为零字节且您不希望验证它时,通常使用它。


9
malloc()必须在某处保留“客房整理信息”(例如,分配的块的大小以及其他辅助数据)。因此,如果malloc(0)不返回NULL,它将使用内存来存储该信息,如果不返回free()d,将构成内存泄漏。
Alok Singhal 2010年

Malloc实现执行记录保留,这可以在请求的大小之上为每个返回的指针添加一定数量的数据。
user7116 2010年

1
消耗的内存和分配的内存并不意味着同一件事。在这种情况下,大多数实现将返回唯一的指针。这意味着需要为该指针牺牲一部分地址空间。根据分配器,这实际上可能意味着它将分配1个字节或更多的字节。
Coincoin

1
该库可以做任何想做的事情 -好,它可以返回一个唯一的指针(没有其他指针malloc()会返回)或return NULL
Alok Singhal'1

1
@jldupont:至少Microsoft C运行时库返回的唯一指针malloc(0)。但是,在与标准C库完全相同的实现中,realloc(ptr, 0)释放ptr并返回NULL。
Medinoc

5

在此页上的其他地方,有一个答案开始于“ malloc(0)将返回有效的内存地址,其范围将取决于正在分配的内存的指针的类型”。这句话是不正确的(我没有足够的声誉来直接评论该答案,所以不能在下面直接发表此评论)。

进行malloc(0)不会自动分配正确大小的内存。malloc函数不知道将结果强制转换为什么。malloc函数纯粹依赖于您为其参数提供的大小数字。您需要执行malloc(sizeof(int))以获得足够的存储空间来容纳一个int,例如,不为0。


4

malloc(0)对我来说没有任何意义,除非代码依赖于特定于实现的行为。如果代码是可移植的,则必须考虑到NULL返回malloc(0)不是失败的事实。那么,为什么不直接将NULL赋值artist呢,因为这是一个有效的成功结果,并且代码更少,并且不会导致维护程序员花时间去弄清楚它?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)或者malloc(some_variable_which_might_be_zero)也许可以有其用途,但你又不得不格外小心,如果值是0,但0的大小应该是OK不治疗返回NULL为失败。


3

这里有很多正确的答案,所以这里有一些困难的事实。的手册页malloc()说:

如果size为0,则malloc()返回NULL或唯一的指针值,该值以后可以成功传递给free()。

这意味着,绝对不能保证的结果malloc(0)是唯一的或不是NULL。唯一的保证是由的定义free()再次提供的,这是手册页所说的内容:

如果ptr为NULL,则不执行任何操作。

因此,无论malloc(0)返回什么,它都可以安全地传递给free()。但是NULL指针也可以。

因此,写作 artist = malloc(0); 绝不比写作好 artist = NULL;


1
不幸的是,该实现不允许返回非空,非唯一指针。这样,malloc(0)可以返回0x1,并且free()可以像对0x0一样进行特殊情况下的0x1检查。
托德·雷曼

3
@Todd Lehman一个实现可以按照您的建议进行。C规范未指定结果必须为“ NULL或唯一指针”。。而不是“要么一个空指针或分配空间”有没有独特的要求OTOH,返回非唯一的特殊值可能会破坏代码的唯一值计数因此,也许一个角落情况的问题。
chux -恢复莫妮卡

man还可以记录* nix中使用的实现定义的形式。在这种情况下,它不是,但是仍然不是通用C的规范来源
。– Lundin

@Lundin真实。但是手册页比C标准更易于访问,并且GNU / Linux系统上的手册页通常很好地记录了实现遵循的标准。以及有关哪些部件遵循哪种标准的信息,它们是否也应有所不同。我感觉他们俩都希望精确,并宣传GNU扩展的每一点……
cmaster-恢复莫妮卡

3

为什么你不应该这样做...

由于malloc的返回值取决于实现,因此您可能会获得NULL指针或其他地址。如果错误处理代码无法同时检查大小和返回值,则最终可能导致堆缓冲区溢出,从而导致稳定性问题(崩溃)甚至更严重的安全问题。

考虑一下这个示例,其中进一步通过返回的地址访问内存将破坏堆,如果大小为零,并且实现返回一个非NULL值。

size_t size;

/* Initialize size, possibly by user-controlled input */

int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
  /* Continue processing list */
}

请参阅CERT编码标准中的此“安全编码”页面,该页面中,我以上面的示例作为进一步阅读。



2

诚然,我以前从未见过这种情况,这是我第一次看到这种语法,可以说这是函数过度杀伤的经典案例。结合Reed的回答,我想指出,有一个类似的东西,看起来像一个重载的函数realloc

  • foo为非NULL,大小为零,realloc(foo, size);。当您传递非零大小为零的非NULL指针时,重新分配的行为就好像您调用了free(…)一样
  • foo为NULL,大小为非零且大于1 realloc(foo, size);。当您传递NULL指针且大小不为零时,realloc的行为就像您已调用malloc(…)

希望这对您有所帮助,汤姆,谢谢。


1

要真正回答所提出的问题:没有理由这样做


0

malloc(0)将返回NULL或可以正确传递给free的有效指针。尽管看起来它指向的内存是无用的或无法写入或读取的,但这并不总是正确的。:)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

我们期望在这里出现分段错误,但是令人惊讶的是,它会打印100!这是因为当我们第一次调用malloc时,malloc实际上需要大量内存。之后,每次对malloc的调用都使用该大块中的内存。只有在那巨大的块结束之后,才需要新的内存。

使用malloc(0):如果您希望后续的malloc调用更快,则调用malloc(0)应该可以为您做到(边缘情况除外)。


1
*i在您的情况下,写入可能不会崩溃,但是仍然是未定义的行为。当心鼻恶魔!
John Dvorak 2014年

1
是。那是真实的。它是特定于实现的。我已经在MaxOS X和某些Linux发行版上对其进行了验证。我还没有在其他平台上尝试过。话虽如此,我所描述的概念已经在Brain Kernighan和Dennis Ritchie所著的“ C编程语言”一书中进行了描述。
Sagar Bhosale 2014年

我知道:对这个问题的最新评论。但是有时malloc(0)没有提到它的用途。在那些返回非NULL值的实现上,尤其是在DEBUG构建中,它可能分配的容量超出了您的要求,并且为您提供了指向其内部标头的指针。这可以让你得到一个感觉实际内存使用情况,如果你在这之前和之后的一系列分配得到。例如:void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;或类似的东西。
Jesse Chisholm

我读过Brain Kernighan和Dennis Ritchie的“ The C programming language”,但我不记得它说了什么malloc(0)。您能说一下您指的是哪一章吗?提供准确的报价也很好。
АндрейБеньковский

0

在Windows中:

  • void *p = malloc(0);将在本地堆上分配零长度缓冲区。返回的指针是有效的堆指针。
  • malloc最终HeapAlloc使用默认的C运行时堆进行调用RtlAllocateHeap,然后调用,等等。
  • free(p);用于HeapFree释放堆上的0长度缓冲区。不释放它会导致内存泄漏。

0

它实际上非常有用,并且(显然是恕我直言)打破了返回NULL指针的允许行为。动态指针不仅对它指向的内容有用,而且它的地址是唯一的。返回NULL将删除该第二个属性。我编程的所有嵌入式malloc(实际上很多时候)都具有此行为。



-2

这是使用valgrind内存检查工具运行后的分析。

==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740==     in use at exit: 0 bytes in 0 blocks
==16740==   total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible

这是我的示例代码:

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

int main()
{
   //int i;
   char *p1;

   p1 = (char *)malloc(0);
   printf("p1 = %p\n", p1);

   free(p1);

   return 0;

}

默认情况下,分配1024个字节。如果增加malloc的大小,则分配的字节数将增加1025,依此类推。


-3

根据Reed Copsey的回答和malloc的手册页,我编写了一些示例进行测试。而且我发现malloc(0)总是会赋予它唯一的值。看我的例子:

char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
    puts("Got a null pointer");
else
    puts("Got a valid pointer");

输出将是“获得有效的指针”,这意味着ptr不为null。


-6

malloc(0)将返回一个有效的内存地址,其范围将取决于分配给内存的指针的类型。另外,您可以为存储区分配值,但是该值应在所使用的指针类型的范围内。您还可以释放分配的内存。我将用一个示例对此进行解释:

int *p=NULL;
p=(int *)malloc(0);
free(p);

上面的代码gcc在Linux机器上的编译器中可以正常工作。如果您有32位编译器,则可以提供整数范围内的值,即-2147483648至2147483647。同样适用于字符。请注意,如果声明的指针类型改变,则值的范围将改变,而与malloc类型转换无关,即

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

p 因为它被声明为unsigned int,所以它将采用从0到255之间的char值。


5
Krellan指出这个答案是错误的是正确的:malloc()不了解任何有关强制转换的信息(实际上在C语言中完全多余)。取消引用的返回值malloc(0)将调用未定义的行为。
cmaster-恢复莫妮卡2014年

-6

此处只是为了纠正错误的印象:

artist = (char *) malloc(0);永远不会回来NULL; 与并不相同artist = NULL;。编写一个简单的程序,比较artistNULLif (artist == NULL)是错误的,if (artist)是真实的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.