提问人:jldupont 提问时间:1/8/2010 最后编辑:wovanojldupont 更新时间:8/23/2023 访问量:100135
malloc(0) 的意义何在?
What's the point of malloc(0)?
答:
根据规范,malloc(0) 将返回“一个空指针或一个可以成功传递给 free()的唯一指针”。
这基本上可以让你不分配任何内容,但仍然将 “artist” 变量传递给对 free() 的调用,而无需担心。出于实际目的,这与执行以下操作几乎相同:
artist = NULL;
评论
不确定,根据我发现的一些随机 malloc 源代码,输入 0 会导致返回值为 NULL。因此,这是将艺术家指针设置为 NULL 的一种疯狂方式。
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
C 标准 (C17 7.22.3/1) 说:
如果请求的空间大小为零,则行为由实现定义: 要么返回 null 指针,要么行为就好像大小是 非零值,但返回的指针不应用于访问对象。
因此,可以返回或可能未取消引用的有效指针。无论哪种情况,调用它都是完全有效的。malloc(0)
NULL
free()
我真的认为没有多大用处,除非在循环中被调用,并且可能为零。malloc(0)
malloc(n)
n
看链接中的代码,相信作者有两个误区:
malloc(0)
始终返回有效指针,并且free(0)
很糟糕。
因此,他确保和其他变量始终具有一些“有效”值。评论说了很多:.artist
// these must always point at malloc'd data
评论
malloc(0)
malloc()
NULL
0
malloc
ENOMEM
malloc(0)
errno==ENOMEM
realloc
malloc(0)
realloc((char*)NULL)
malloc(0) 行为是特定于实现的。该库可以返回 NULL 或具有常规的 malloc 行为,而不分配内存。无论它做什么,它都必须记录在某个地方。
通常,它返回一个有效且唯一的指针,但不应取消引用。另请注意,即使它实际上没有分配任何内容,它也可以消耗内存。
可以重新分配一个非空的 malloc(0) 指针。
不过,逐字使用 malloc(0) 没有多大用处。它主要用于动态分配为零字节且您不关心验证它的情况。
评论
malloc()
必须将“内务信息”保存在某个地方(例如,分配的块的这个大小,以及其他辅助数据)。因此,如果 does not return ,它将使用内存来存储该信息,如果不返回,则构成内存泄漏。malloc(0)
NULL
free()
malloc()
NULL
malloc(0)
realloc(ptr, 0)
ptr
malloc(0)
对我来说没有任何意义,除非代码依赖于特定于实现的行为。如果代码是可移植的,那么它必须考虑以下事实:NULL 返回不是失败的。那么,为什么不直接将 NULL 分配给它,因为这是一个有效的成功结果,而且代码更少,并且不会导致您的维护程序员花时间弄清楚它呢?malloc(0)
artist
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
或者可能有它们的用途,尽管如果值为 0,您必须再次格外小心,不要将 NULL 返回视为失败,但 0 大小应该是可以的。malloc(some_variable_which_might_be_zero)
诚然,我以前从未见过这种情况,这是我第一次看到这种语法,可以说是函数矫枉过正的经典案例。结合 Reed 的回答,我想指出有一个类似的东西,它看起来像一个重载函数:realloc
- foo 为非 NULL,大小为零,.当您将非 NULL 指针和大小为零的指针传递给 realloc 时,realloc 的行为就像您调用了 free(...)
realloc(foo, size);
- foo 为 NULL,大小为非零且大于 1, 。当您传入 NULL 指针并且大小不为零时,realloc 的行为就像您调用了 malloc(...)
realloc(foo, size);
希望这会有所帮助, 此致敬意 汤姆。
实际上回答提出的问题:没有理由这样做
malloc(0) 将返回 NULL 或一个可以正确传递给 free 的有效指针。尽管它所指向的内存似乎是无用的,或者无法写入或读取,但这并不总是正确的。:)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
我们预计这里会出现分段错误,但令人惊讶的是,这打印了 100!这是因为当我们第一次调用 malloc 时,malloc 实际上需要大量的内存。之后对 malloc 的每次调用都会使用该大块的内存。只有在那一大块结束后,才会要求新的内存。
使用 malloc(0):如果您希望后续的 malloc 调用更快,那么调用 malloc(0) 应该可以为您完成(边缘情况除外)。
评论
*i
malloc(0)
void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
malloc(0)
malloc(0)
将返回一个有效的内存地址,其范围将取决于分配内存的指针类型。此外,您可以为内存区域赋值,但这应该在所使用的指针类型的范围内。您还可以释放分配的内存。我将用一个例子来解释这一点:
int *p=NULL;
p=(int *)malloc(0);
free(p);
上面的代码可以在 Linux 机器上的编译器中正常工作。如果您有 32 位编译器,则可以提供整数范围内的值,即 -2147483648 到 2147483647。这同样适用于角色。请注意,如果声明的指针类型发生了变化,则无论类型转换如何,值范围都会发生变化,即gcc
malloc
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
将采用 char 的 0 到 255 的值,因为它被声明为无符号 int。
评论
malloc()
malloc(0)
本页其他地方有一个答案,开头是“malloc(0) 将返回一个有效的内存地址,其范围将取决于分配内存的指针类型”。这种说法是不正确的(我没有足够的声誉直接评论这个答案,所以不能直接把这个评论放在那里)。
执行 malloc(0) 不会自动分配正确大小的内存。malloc 函数不知道您将其结果转换为什么。malloc 函数完全依赖于您给出的大小编号作为其参数。您需要执行 malloc(sizeof(int)) 来获得足够的存储空间来保存 int,例如,不是 0。
这里有很多半真半假的答案,所以这里有确凿的事实。的手册页说:malloc()
如果 size 为 0,则 malloc() 返回 NULL 或以后可以返回的唯一指针值 成功传递给 free()。
这意味着,绝对不能保证的结果是唯一的或不是 NULL。唯一的保证是由 的定义提供的,同样,这是手册页所说的:malloc(0)
free()
如果 ptr 为 NULL,则不执行任何操作。
因此,无论返回什么,都可以安全地传递给 .但指针也可以。malloc(0)
free()
NULL
因此,写作绝不比写作好artist = malloc(0);
artist = NULL;
评论
malloc(0)
free()
man
也可以记录 *nix 中使用的实现定义形式。在这种情况下,它没有,但它仍然不是一般 C 的规范来源。
在 Windows 中:
void *p = malloc(0);
将在本地堆上分配一个长度为零的缓冲区。返回的指针是有效的堆指针。malloc
最终使用默认的 C 运行时堆调用,然后调用 ,等等。HeapAlloc
RtlAllocateHeap
free(p);
用于释放堆上长度为 0 的缓冲区。不释放它将导致内存泄漏。HeapFree
为什么你不应该这样做......
由于 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 编码标准中的此安全编码页面,我以上面的示例进行进一步阅读。
根据 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
评论
只是为了纠正这里的错误印象:
artist = (char *) malloc(0);
再也不会回来了;它与 不同。编写一个简单的程序并与之进行比较。 是假的,也是真的。NULL
artist = NULL;
artist
NULL
if (artist == NULL)
if (artist)
评论
这是使用 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,依此类推。
评论
它实际上非常有用,并且(显然恕我直言),返回 NULL 指针的允许行为被破坏了。动态指针不仅对它所指向的内容有用,而且因为它的地址是唯一的。返回 NULL 将删除第二个属性。我编程的所有嵌入式 mallocs(实际上很常见)都具有这种行为。
评论
malloc(1)
malloc
编写代码的人可能希望您将其视为要向其添加值的空初始化数组 ()。虽然无论 malloc(0)
返回 NULL
还是实际指针,这都有效,但它会产生误解:malloc(0)
realloc()
如果没有实施意识,您将无法分辨通过手段返回的潜力。这可能意味着内存不足,但也可能意味着实现决定为大小为 0 的分配返回内存。即使这与你的代码所做的事情无关紧要,它也会引起一些人的注意。NULL
malloc(0)
这意味着这是编写更具可读性的代码的尝试。但是,由于它涉及特定于实现的行为,在此过程中丢失了信息,因此可能会引起混淆。除非您特别要求特定于实现的行为的结果,否则不要使用它。malloc(0)
评论
malloc(0)
malloc(0)
malloc()
NULL
malloc(0)
malloc(0)
NULL
malloc(0)
realloc
评论