malloc(0)
返回什么? realloc(malloc(0),0)
的答案是否相同?
#include<stdio.h>
#include<malloc.h>
int main()
{
printf("%p\n", malloc(0));
printf("%p\n", realloc(malloc(0), 0));
return 0;
}
linux gcc的输出:
manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$
每次malloc(0)
的输出都会不断变化。这是标准答案吗?除了学术研究之外,为什么有人会对获得这样的指针感兴趣?
修改
如果malloc(0)
返回虚拟指针,那么后续工作原理如何:
int main()
{
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
return 0;
}
修改
以下代码为每次迭代输出“可能”。为什么不能失败?
#include<stdio.h>
#include<malloc.h>
int main()
{
int i;
void *ptr;
printf("Testing using BRUTE FORCE\n");
for (i=0; i<65000; i++)
{
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
printf("Iteration %d: possible\n", i);
else
{
printf("Failed for iteration %d\n", i);
break;
}
}
return 0;
}
答案 0 :(得分:44)
其他人已回答malloc(0)
的工作原理。我会回答你提出的一个尚未回答的问题(我认为)。问题是关于realloc(malloc(0), 0)
:
malloc(0)
返回什么?realloc(malloc(0),0)
的答案是否相同?
标准说明了realloc(ptr, size)
:
ptr
为NULL
,则其行为类似malloc(size)
,ptr
不是NULL
),它将旧对象指针解除分配给ptr
并返回指向新分配缓冲区的指针。但如果size
为0,则C89表示效果等同于free(ptr)
。有趣的是,我无法在C99草案(n1256或n1336)中找到该声明。在C89中,在这种情况下返回的唯一合理值是NULL
。所以,有两种情况:
malloc(0)
会在实施时返回NULL
。然后,您的realloc()
来电相当于realloc(NULL, 0)
。这相当于上面的malloc(0)
(在这种情况下是NULL
)。malloc(0)
返回非NULL
。然后,该呼叫相当于free(malloc(0))
。在这种情况下,malloc(0)
和realloc(malloc(0), 0)
不等于请注意,这里有一个有趣的案例:在第二种情况下,当malloc(0)
成功时返回非NULL
时,它仍可能会返回NULL
来表示失败。这会产生如下调用:realloc(NULL, 0)
,相当于malloc(0)
,可能会或可能不会返回NULL
。
我不确定C99中的遗漏是否属于疏忽,或者是否意味着在C99中,非realloc(ptr, 0)
NULL
的{{1}}不等同于ptr
。我刚刚使用free(ptr)
尝试了此操作,上述内容相当于gcc -std=c99
。
编辑:我想我明白你的困惑是什么:
让我们看一下示例代码中的代码段:
free(ptr)
上述内容与ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
不同。在第二个中,malloc(0) == realloc(malloc(0), 1024)
调用两次,而在第一个调用中,您将先前分配的指针传递给malloc()
。
让我们先分析第一个代码。假设realloc()
在成功时未返回malloc(0)
,NULL
具有有效值。执行ptr
时,realloc(ptr, 1024)
基本上会为您提供一个大小为1024的新缓冲区,realloc()
将变为无效。符合要求的实现可以返回与ptr
中已有的地址相同的地址。因此,您的ptr
条件可能会返回true。 (请注意,在if
之后查看ptr
的值可能是未定义的行为。)
现在你问的问题是:realloc(ptr, 1024)
。在这种情况下,我们假设LHS和RHS上的malloc(0) == realloc(malloc(0), 1024)
都返回非malloc(0)
。然后,他们保证是不同的。此外,LHS上NULL
的返回值尚未malloc()
,因此任何其他free()
,malloc()
或calloc()
可能不会返回那个价值。这意味着,如果您将条件写为:
realloc()
您不会在输出中看到if (malloc(0) == realloc(malloc(0), 1024)
puts("possible");
(除非possible
和malloc()
都失败并返回realloc()
)。
NULL
在OS X上,我的代码在运行时没有输出任何内容。在Linux上,它打印#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *p1;
void *p2;
p1 = malloc(0);
p2 = realloc(p1, 1024);
if (p1 == p2)
puts("possible, OK");
/* Ignore the memory leaks */
if (malloc(0) == realloc(malloc(0), 1024))
puts("shouldn't happen, something is wrong");
return 0;
}
。
答案 1 :(得分:33)
malloc(0)
实施定义。
来自 C99 [第7.20.3节]
通过连续调用 calloc分配的存储顺序和连续性, malloc和realloc函数未指定。如果分配则返回指针 适当地对齐成功,以便可以将其指定给指向任何类型对象的指针 然后用于在分配的空间中访问此类对象或此类对象的数组 (直到空间被明确解除分配)。分配对象的生命周期延长 从分配到解除分配。每个这样的分配都应该产生一个指针 对象与任何其他对象不相交。返回的指针指向开始(最低字节 地址)分配的空间。如果无法分配空间,则为空指针 回。 如果请求的空间大小为零,则行为是实施 - 定义:返回空指针,或者行为就像大小一样 非零值,但返回的指针不得用于访问对象。
答案 2 :(得分:15)
在C89中,malloc(0)依赖于实现 - 我不知道C99是否已修复此问题。在C ++中,使用:
char * p = new char[0];
定义良好 - 你得到一个有效的非空指针。当然,如果不调用未定义的行为,就不能使用指针来访问它所指向的内容。
至于为什么存在这种情况,对于某些算法来说很方便,并且意味着您不需要使用零值测试来丢弃代码。
答案 3 :(得分:5)
C99标准
如果空间无法分配,a 返回nullpointer。如果大小 要求的空间是零, 行为是实现定义的: 要么返回空指针,要么 行为就像大小一样 一些非零值,除了 返回的指针不得用于 访问一个对象。
答案 4 :(得分:5)
comp.lang.c FAQ有the following说:
ANSI / ISO标准说它可能 做任何一个;行为是 实现定义(见问题 11.33)。可移植代码必须注意不要调用malloc(0),否则 为null的可能性做好准备 返回。
因此,最好避免使用malloc(0)
。
答案 5 :(得分:3)
见C99,第7.20.3节:
如果要求的空间大小是 零,行为是 implementationdefined:要么为null 返回指针,或行为 好像大小有点非零 值,但返回的除外 指针不得用于访问 对象
这对所有三个分配函数都有效(即calloc()
,malloc()
和realloc()
)。
答案 6 :(得分:3)
还有一点没人关心,在你的第一个程序中,长度为0的realloc
与free
是一样的。
:
realloc()
函数会更改指向的块的大小 到ptr
到size
个字节并返回指向(可能移动的)块的指针。内容将保持不变 较小的新旧尺寸。如果ptr
为NULL
,realloc()
对于指定的大小,行为类似于malloc()
。如果size
为0
并且ptr
不是空指针,指向的空间是 但是,可供应用程序进一步分配 没有返回系统。内存返回系统 只有在申请终止时才会。
如果一个人不知道它可能是一个不好的惊喜(发生在我身上)。
答案 7 :(得分:2)
我认为这取决于。 我检查了Visual Studio 2005源代码并在_heap_alloc函数中看到了这个:
if (size == 0)
size = 1;
我认为在许多情况下,即使要求零字节,您也可能需要一个有效的指针。 这是因为这种一致的行为使得检查指针变得更容易,因为:如果你有一个非NULL指针就可以了;如果你有一个NULL指针,你可能有一个问题。 这就是为什么我认为大多数实现都会返回一个有效的指针,即使在请求零字节时也是如此。
答案 8 :(得分:0)
如果malloc(0)返回虚拟指针,那么后续工作原理如何:
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
我不知道“虚拟指针”是什么意思。如果malloc(0)
返回非NULL,则ptr
是指向大小为零的内存块的有效指针。 malloc
实现以特定于实现的方式保存此信息。 realloc
知道(特定于实现)的方法,以确定ptr
指向大小为零的内存块。
(malloc
/ realloc
/ free
如何执行此操作是特定于实现的。一种可能性是分配比请求多4个字节并在内存块之前存储大小。在这种情况下,((int *)ptr)[-1]
会给出内存块大小,即0
。您不应该从代码中执行此操作,它仅供realloc
和free
使用。