malloc(0) 的意义何在?

What's the point of malloc(0)?

提问人:jldupont 提问时间:1/8/2010 最后编辑:wovanojldupont 更新时间:8/23/2023 访问量:100135

问:

我刚刚看到这个代码:

artist = (char *) malloc(0);

...我想知道为什么要这样做?

c 马洛克

评论

0赞 shodanex 1/8/2010
相关新闻 :stackoverflow.com/questions/1073157/zero-size-malloc

答:

155赞 Reed Copsey 1/8/2010 #1

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

这基本上可以让你不分配任何内容,但仍然将 “artist” 变量传递给对 free() 的调用,而无需担心。出于实际目的,这与执行以下操作几乎相同:

artist = NULL;

评论

66赞 Reed Copsey 1/8/2010
就个人而言,我认为设置为 NULL 是一种更好的跨平台策略,因为 free() 可以保证(按规范)在 NULL 作为输入上正常工作。
3赞 Reed Copsey 1/8/2010
正如 C. Ross 所提到的,从技术上讲,某些平台可能会在这里返回一个指针(即“可以传递给 free 的唯一指针”),但如果你将其视为 char*,这可能会给你一个无效的、未终止的 char。在跨平台情况下依赖它可能很危险。
14赞 hanshenrik 7/13/2015
真的希望规格也会说“安全传递到 realloc”-.-
1赞 chux - Reinstate Monica 9/13/2016
@NSAddict“空结构,其中sizeof将返回0”,请提供一个示例,听起来像一个语言扩展。
6赞 glglgl 4/3/2019
@hanshenrik 谁说你不能?realloc() 允许您传递 返回的任何有效指针。应该足够了。malloc()
-2赞 Doug T. 1/8/2010 #2

不确定,根据我发现的一些随机 malloc 源代码,输入 0 会导致返回值为 NULL。因此,这是将艺术家指针设置为 NULL 的一种疯狂方式。

http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html

60赞 Alok Singhal 1/8/2010 #3

C 标准 (C17 7.22.3/1) 说:

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

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

我真的认为没有多大用处,除非在循环中被调用,并且可能为零。malloc(0)malloc(n)n

看链接中的代码,相信作者有两个误区:

  • malloc(0)始终返回有效指针,并且
  • free(0)很糟糕。

因此,他确保和其他变量始终具有一些“有效”值。评论说了很多:.artist// these must always point at malloc'd data

评论

12赞 1/8/2010
它依赖于实现的事实使它或多或少完全无用——这是 C 标准中最糟糕的部分之一,相当多的标准委员会(例如 P.J. Plauger)对此抱怨不已。
10赞 Alok Singhal 1/8/2010
我同意。如果返回一个有效的指针,则返回始终意味着“失败”,并且不再是特例,这更一致。malloc(0)malloc()NULL0
1赞 R.. GitHub STOP HELPING ICE 9/6/2011
由于无法获取内存的情况是由实现定义的,因此实现可以简单地定义大小 0 分配始终无法满足 (),现在返回 0 (with ) 是一致的。:-)mallocENOMEMmalloc(0)errno==ENOMEM
7赞 Braden Best 8/8/2016
你能返回一个指针吗?你能吗?reallocmalloc(0)realloc((char*)NULL)
4赞 chux - Reinstate Monica 9/13/2016
@Braden 对两者都最好是。
13赞 Coincoin 1/8/2010 #4

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

通常,它返回一个有效且唯一的指针,但不应取消引用。另请注意,即使它实际上没有分配任何内容,它也可以消耗内存。

可以重新分配一个非空的 malloc(0) 指针。

不过,逐字使用 malloc(0) 没有多大用处。它主要用于动态分配为零字节且您不关心验证它的情况。

评论

10赞 Alok Singhal 1/8/2010
malloc()必须将“内务信息”保存在某个地方(例如,分配的块的这个大小,以及其他辅助数据)。因此,如果 does not return ,它将使用内存来存储该信息,如果不返回,则构成内存泄漏。malloc(0)NULLfree()
0赞 user7116 1/8/2010
Malloc 实现执行记录保存,这可能会在请求的大小之上添加每个返回的指针一定数量的数据。
1赞 Coincoin 1/8/2010
消耗的内存和分配的内存并不意味着一回事。在这种情况下,大多数实现将返回一个唯一的指针。这意味着需要为该指针牺牲一部分地址空间。根据分配器的不同,这实际上可能意味着它将分配 1 个字节或更多字节。
1赞 Alok Singhal 1/8/2010
库可以做任何它想做的事情 - 好吧,它可以返回一个没有其他人会返回的唯一指针,或者返回 .malloc()NULL
1赞 Medinoc 4/12/2018
@jldupont:至少 Microsoft C 运行时库返回 的唯一指针。但是,在标准 C 库的相同实现中,释放并返回 NULL。malloc(0)realloc(ptr, 0)ptr
3赞 Steve Jessop 1/8/2010 #5

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

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)或者可能有它们的用途,尽管如果值为 0,您必须再次格外小心,不要将 NULL 返回视为失败,但 0 大小应该是可以的。malloc(some_variable_which_might_be_zero)

2赞 t0mm13b 1/26/2010 #6

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

  • foo 为非 NULL,大小为零,.当您将非 NULL 指针和大小为零的指针传递给 realloc 时,realloc 的行为就像您调用了 free(...)realloc(foo, size);
  • foo 为 NULL,大小为非零且大于 1, 。当您传入 NULL 指针并且大小不为零时,realloc 的行为就像您调用了 malloc(...)realloc(foo, size);

希望这会有所帮助, 此致敬意 汤姆。

-1赞 Paolo 1/24/2013 #7

实际上回答提出的问题:没有理由这样做

-3赞 Sagar Bhosale 1/1/2014 #8

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

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

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

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

评论

2赞 John Dvorak 1/1/2014
在你的情况下,写信可能不会崩溃,但它仍然是未定义的行为。当心鼻妖!*i
1赞 Sagar Bhosale 1/2/2014
是的。这是真的。它是特定于实现的。我已经在 MaxOS X 和一些 Linux 发行版上验证了它。我没有在其他平台上尝试过。话虽如此,我所描述的概念已经在 Brain Kernighan 和 Dennis Ritchie 的《The C programming language》一书中进行了描述。
0赞 Jesse Chisholm 2/25/2017
我知道:对这个问题的评论超级晚。但有时没有提到它的用途。在那些返回非 NULL 值的实现中,尤其是在 DEBUG 构建中,它分配的 MORE 可能比您要求的要多,并为您提供指向其内部标头的指针。这使您可以了解实际的内存使用情况,如果您在一系列分配之前和之后获得此内存。例如:或类似的东西。malloc(0)void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
0赞 Андрей Беньковский 10/15/2017
我读了 Brain Kernighan 和 Dennis Ritchie 的“The C programming language”,我不记得它说过什么。你能说说你也指的是哪一章吗?提供准确的报价也很好。malloc(0)
0赞 Andrew Henle 5/26/2023
但令人惊讶的是,这打印了 100 个!哎哟。你怎么知道你的简单玩具程序没有以一种在分配给无效指针后立即退出的程序中不明显的方式破坏堆?
-9赞 Suryakant Tiwari 1/15/2014 #9

malloc(0)将返回一个有效的内存地址,其范围将取决于分配内存的指针类型。此外,您可以为内存区域赋值,但这应该在所使用的指针类型的范围内。您还可以释放分配的内存。我将用一个例子来解释这一点:

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

上面的代码可以在 Linux 机器上的编译器中正常工作。如果您有 32 位编译器,则可以提供整数范围内的值,即 -2147483648 到 2147483647。这同样适用于角色。请注意,如果声明的指针类型发生了变化,则无论类型转换如何,值范围都会发生变化,即gccmalloc

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

p将采用 char 的 0 到 255 的值,因为它被声明为无符号 int。

评论

5赞 cmaster - reinstate monica 4/17/2014
克雷兰指出这个答案是错误的,这是对的:对演员一无所知(这在 C 语言中实际上是完全多余的)。取消引用 的返回值将调用未定义的行为。malloc()malloc(0)
7赞 Krellan 4/17/2014 #10

本页其他地方有一个答案,开头是“malloc(0) 将返回一个有效的内存地址,其范围将取决于分配内存的指针类型”。这种说法是不正确的(我没有足够的声誉直接评论这个答案,所以不能直接把这个评论放在那里)。

执行 malloc(0) 不会自动分配正确大小的内存。malloc 函数不知道您将其结果转换为什么。malloc 函数完全依赖于您给出的大小编号作为其参数。您需要执行 malloc(sizeof(int)) 来获得足够的存储空间来保存 int,例如,不是 0。

6赞 cmaster - reinstate monica 4/17/2014 #11

这里有很多半真半假的答案,所以这里有确凿的事实。的手册页说:malloc()

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

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

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

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

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

评论

1赞 Todd Lehman 8/21/2015
太糟糕了,不允许实现返回非 null、非唯一指针。这样一来,就可以返回,比如说,0x1,并且可以像0x0一样对0x1进行特殊情况检查。malloc(0)free()
1赞 Lundin 1/28/2019
man也可以记录 *nix 中使用的实现定义形式。在这种情况下,它没有,但它仍然不是一般 C 的规范来源。
1赞 cmaster - reinstate monica 1/29/2019
@Lundin真的。但是手册页比 C 标准更容易访问,GNU/Linux 系统上的手册页通常很好地记录了实现遵循的标准。以及哪些部件符合哪个标准的信息,如果它们不同。我有一种感觉,他们都想精确一点,并宣传GNU扩展的每一点......
1赞 sam msft 2/12/2015 #12

在 Windows 中:

  • void *p = malloc(0);将在本地堆上分配一个长度为零的缓冲区。返回的指针是有效的堆指针。
  • malloc最终使用默认的 C 运行时堆调用,然后调用 ,等等。HeapAllocRtlAllocateHeap
  • free(p);用于释放堆上长度为 0 的缓冲区。不释放它将导致内存泄漏。HeapFree
3赞 auselen 2/13/2015 #13

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

由于 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 编码标准中的此安全编码页面,我以上面的示例进行进一步阅读。

-7赞 Neal 9/2/2015 #14

根据 Reed Copsey 的回答和 malloc 的手册页,我写了一些示例来测试。我发现 malloc(0) 总是会给它一个唯一的值。 请看我的例子:

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

输出将为“Got a valid pointer”,这意味着不为 null。ptr

评论

2赞 klutt 8/28/2020
仅仅因为你总是得到一个有效的指针并不意味着它是有保证的。
-7赞 ALFRED OKORONKWO 10/23/2015 #15

只是为了纠正这里的错误印象:

artist = (char *) malloc(0);再也不会回来了;它与 不同。编写一个简单的程序并与之进行比较。 是假的,也是真的。NULLartist = NULL;artistNULLif (artist == NULL)if (artist)

评论

1赞 klutt 3/9/2023
C 标准允许它返回 NULL,但不要求它。
-3赞 Shubhesh Swain 7/13/2017 #16

这是使用 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,依此类推。

评论

2赞 Shipof123 1/1/2021
其实现取决于
-2赞 Scott Franco 5/12/2019 #17

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

评论

1赞 klutt 3/9/2023
您能举例说明这在什么时候有用吗?
0赞 wovano 3/9/2023
那你为什么不呢?这将返回一个唯一的地址(至少在分配对象的生命周期内是唯一的)。malloc(1)
0赞 wovano 3/9/2023
PS:我怀疑你的用例在“发明”的时代是否是一个现实的用例。malloc
0赞 Zyl 5/25/2023 #18

编写代码的人可能希望您将其视为要向其添加值的空初始化数组 ()。虽然无论 malloc(0) 返回 NULL 还是实际指针,这都有效,但它会产生误解:malloc(0)realloc()

如果没有实施意识,您将无法分辨通过手段返回的潜力。这可能意味着内存不足,但也可能意味着实现决定为大小为 0 的分配返回内存。即使这与你的代码所做的事情无关紧要,它也会引起一些人的注意。NULLmalloc(0)

这意味着这是编写更具可读性的代码的尝试。但是,由于它涉及特定于实现的行为,在此过程中丢失了信息,因此可能会引起混淆。除非您特别要求特定于实现的行为的结果,否则不要使用它。malloc(0)

评论

1赞 Andrew Henle 5/26/2023
那么,如果您调用,如何可移植地处理检查失败?如果完全使用,则返回将失去作为错误条件的所有特殊含义。这与“高级语言程序员”完全相反——你的代码丢失了信息,你现在必须编写额外的代码来写在纸上。malloc(0)malloc(0)malloc()NULL
1赞 ad absurdum 5/26/2023
这似乎是个坏主意。这样使用是不惯用的。我不确定“转移责任”的意义何在;使用 result of 并不能完全分配适当的值,而不是赋值(由于赋值是 实现定义的,因此更不完全是赋值),并且肯定会将检查分配错误的责任转移到以后可能对 的调用。我没有看到任何“更高层次”的东西;这似乎是一团糟。malloc(0)malloc(0)NULLmalloc(0)realloc
1赞 Zyl 5/26/2023
我重写了我的回答以反映您的批评。请注意,我希望答案脱颖而出,因为它描绘了基于开发人员特质的推理路线,而不是代码的实际作用。