malloc(0)返回什么?
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; }
其他人已经回答了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中,非NULL
ptr
realloc(ptr, 0)
不等于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)
, realloc()
基本上给你一个新的缓冲区,其大小为1024, ptr
变为无效。 符合的实现可以返回与ptr
已经存在的地址相同的地址。 所以,你的条件可能会返回true。 (但是请注意,在realloc(ptr, 1024)
之后查看ptr
的值可能是未定义的行为。)
现在你问的问题: malloc(0) == realloc(malloc(0), 1024)
。 在这种情况下,我们假设LHS和RHS上的malloc(0)
返回非NULL
。 那么,他们保证是不同的。 此外,LHS上的malloc()
的返回值还没有free()
d,所以其他malloc()
, calloc()
或realloc()
可能不会返回该值。 这意味着如果你写下你的条件为:
if (malloc(0) == realloc(malloc(0), 1024) puts("possible");
你将不会看到possible
的输出(除非malloc()
和realloc()
失败并返回NULL
)。
#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; }
在OS X上,我的代码在运行时没有输出任何内容。 在Linux上,它可以打印possible, OK
。
malloc(0)
是实现定义就C99而言。
从C99 [第7.20.3节]
没有指定通过连续调用calloc,malloc和realloc函数分配的存储顺序和连续性。 如果分配成功,返回的指针被适当地alignment,以便它可以被分配给任何types的对象的指针,然后用来访问分配的空间中的这样的对象或这样的对象的数组(直到空间被明确地解除分配) 。 分配对象的生命周期从分配延伸到释放。 每个这样的分配应该产生一个指向与任何其他对象不相交的对象的指针。 指针返回指向分配空间的开始(最低字节地址)。 如果空间不能分配,则返回空指针。 如果请求空间的大小为零,则行为是实现定义的 :或者返回一个空指针,或者行为就好像大小是非零值一样,除了返回的指针不能用于访问一个对象。
在C89中,malloc(0)是依赖于实现的 – 我不知道C99是否已经解决了这个问题。 在C ++中,使用:
char * p = new char[0];
定义明确 – 你得到一个有效的非空指针。 当然,你不能使用指针来访问它指向的内容,而不会调用未定义的行为。
至于为什么存在这个问题,对于一些algorithm来说是很方便的,并且意味着你不需要用零值的testing来抛弃你的代码。
C99标准
如果不能分配空间,则返回一个空指针。 如果请求空间的大小为零,则行为是实现定义的:或者返回一个空指针,或者行为就好像大小是非零值,除了返回的指针不能用于访问一个对象。
comp.lang.c常见问题解答 如下 :
ANSI / ISO标准说可能做, 行为是实现定义的(见问题11.33)。 可移植代码必须注意不要调用malloc(0),或者准备好返回null的可能性。
所以,最好避免使用malloc(0)
。
见C99,第7.20.3节:
如果所请求空间的大小为零,则行为是实现定义的:或者返回一个空指针,或者行为就像大小是非零值一样,除了返回的指针不能用于访问一个对象。
这对所有三个分配函数(即calloc()
, malloc()
和realloc()
)都是有效的。
有一点没人关心,在你的第一个程序中,长度为0的realloc
和free
是一样的。
从Solaris手册页:
realloc()
函数将ptr
指向的块的大小更改为字节size
并返回指向(可能已移动的)块的指针。 内容将保持不变,最新的和旧的尺寸较小。 如果ptr
为NULL
,则对于指定的大小,realloc()
行为与malloc()
。 如果size
是0
,ptr
不是空指针,则指向的空间可供应用程序进一步分配,但不会返回给系统。 内存仅在应用程序终止时返回给系统。
如果有人不知道它可能是一个不好的惊喜的来源(发生在我身上)。
我认为这取决于。 我检查了Visual Studio 2005源代码,并在_heap_alloc函数中看到了这一点:
if (size == 0) size = 1;
我认为在很多情况下,您可能需要一个有效的指针,即使在询问零字节时也是如此。 这是因为这种一致的行为使得更容易检查你的指针,因为:如果你有一个非NULL指针, 如果你有一个NULL指针,你可能有一个问题。 这就是为什么我认为大多数实现将返回一个有效的指针,即使在询问零字节。
如果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
)。
我们已经为embedded的代码实现了malloc结构,并带有一个头(和可选的预告片)。 头文件可以包含额外的debugging信息,比如分配给它的任务句柄。 另外,我喜欢有像0xA5A5A5A5和0x5A5A5A5A这样的标志/边界来帮助检测某个地方是否覆盖了内存分配的边界。 通过保留可用块和已用块的列表,还可以定期检查堆的完整性,并防止可能导致事情“爆炸”的操作(如未分配内存的空闲())。