malloc(0)返回什么?

时间:2010-01-25 12:47:03

标签: c linux pointers malloc realloc

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;
}

9 个答案:

答案 0 :(得分:44)

其他人已回答malloc(0)的工作原理。我会回答你提出的一个尚未回答的问题(我认为)。问题是关于realloc(malloc(0), 0)

  

malloc(0)返回什么? realloc(malloc(0),0)的答案是否相同?

标准说明了realloc(ptr, size)

  • 如果ptrNULL,则其行为类似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"); (除非possiblemalloc()都失败并返回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)

就C99而言,

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 FAQthe following说:

  

ANSI / ISO标准说它可能   做任何一个;行为是   实现定义(见问题   11.33)。可移植代码必须注意不要调用malloc(0),否则   为null的可能性做好准备   返回。

因此,最好避免使用malloc(0)

答案 5 :(得分:3)

见C99,第7.20.3节:

  

如果要求的空间大小是   零,行为是   implementationdefined:要么为null   返回指针,或行为   好像大小有点非零   值,但返回的除外   指针不得用于访问   对象

这对所有三个分配函数都有效(即calloc()malloc()realloc())。

答案 6 :(得分:3)

还有一点没人关心,在你的第一个程序中,长度为0的reallocfree是一样的。

来自Solaris手册页的

  

realloc()函数会更改指向的块的大小        到ptrsize个字节并返回指向(可能移动的)块的指针。内容将保持不变        较小的新旧尺寸。如果ptrNULLrealloc()        对于指定的大小,行为类似于malloc()。如果size0        并且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。您不应该从代码中执行此操作,它仅供reallocfree使用。