56

返回什么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;
}
4

9 回答 9

44

其他人已经回答了如何malloc(0)工作。我将回答您提出的尚未回答的问题之一(我认为)。问题是关于realloc(malloc(0), 0)

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

该标准对以下内容进行了说明realloc(ptr, size)

  • 如果ptr是,NULL它的行为就像malloc(size)
  • 否则 ( ptris not NULL),它将释放指向 by 的旧对象指针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)for non-NULL 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)realloc()基本上会给你一个大小为 1024 的新缓冲区,并且ptr变得无效。一个符合要求的实现可能会返回与已经存在的地址相同的地址ptr。因此,您的if条件可能会返回 true。(但是请注意,查看ptrafter的值realloc(ptr, 1024)可能是未定义的行为。)

现在你问的问题:malloc(0) == realloc(malloc(0), 1024)。在这种情况下,我们假设malloc(0)LHS 和 RHS 上的 都返回 non- NULL。然后,保证它们是不同的。此外,malloc()LHS 上的返回值尚未free()d,因此任何其他malloc(),calloc()realloc()可能不会返回该值。这意味着如果您将条件写为:

if (malloc(0) == realloc(malloc(0), 1024)
    puts("possible");

您不会possible在输出中看到(除非同时出现malloc()and realloc()fail 和 return 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.

于 2010-01-25T20:16:54.627 回答
34

malloc(0)就 C99 而言,是实现定义的。

C99 [第 7.20.3 节]

连续调用 calloc、malloc 和 realloc 函数分配的存储顺序和连续性是未指定的。如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问已分配空间中的此类对象或此类对象的数组(直到空间被显式释放) . 已分配对象的生命周期从分配一直延伸到解除分配。每个这样的分配都应产生一个指向与任何其他对象不相交的对象的指针。返回的指针指向分配空间的开始(最低字节地址)。如果无法分配空间,则返回空指针。 如果请求的空间大小为零,则行为由实现定义:要么返回空指针,要么行为就好像大小是某个非零值,但返回的指针不应用于访问对象.

于 2010-01-25T12:53:23.797 回答
15

在 C89 中, malloc(0) 依赖于实现 - 我不知道 C99 是否已修复此问题。在 C++ 中,使用:

char * p = new char[0];

定义明确 - 你得到一个有效的非空指针。当然,如果不调用未定义的行为,您就不能使用指针访问它所指向的内容。

至于为什么存在这种情况,这对某些算法来说很方便,这意味着您不需要在代码中乱扔零值测试。

于 2010-01-25T12:49:10.140 回答
5

C99标准

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

于 2010-01-25T12:50:33.460 回答
5

comp.lang.c 常见问题解答有以下内容

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

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

于 2010-01-25T12:51:51.310 回答
4

没人愿意谈论的一点,在您的第一个程序中,realloc长度为 0 与free.

来自 Solaris 手册页:

realloc()函数将所指向的块的大小更改ptrsize字节,并返回指向(可能已移动的)块的指针。内容将保持不变,直至新旧尺寸中的较小者。如果ptrNULL,则realloc() 行为类似于malloc()指定大小。如果size0ptr不是空指针,则指向的空间可供应用程序进一步分配,但不会返回给系统。只有在应用程序终止时,内存才会返回给系统。

如果一个人不知道这可能是一个糟糕的惊喜的来源(发生在我身上)。

于 2010-01-25T15:41:29.580 回答
3

参见 C99,第 7.20.3 节:

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

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

于 2010-01-25T12:53:29.263 回答
2

我认为这取决于。我检查了 Visual Studio 2005 的源代码,并在 _heap_alloc 函数中看到了这一点:

if (size == 0)
    size = 1;

我认为在许多情况下,即使请求零字节,您也可能需要一个有效的指针。这是因为这种一致的行为使检查指针变得更容易,因为:如果你有一个非 NULL 指针,那没关系;如果你有一个 NULL 指针,你可能有问题。这就是为什么我认为大多数实现都会返回一个有效的指针,即使是在请求零字节时也是如此。

于 2010-01-25T12:54:20.143 回答
0

如果 malloc(0) 返回虚拟指针,那么以下如何工作:

void *ptr = malloc(0);

printf("%p\n", realloc(ptr, 1024));

我不知道您所说的“虚拟指针”是什么意思。如果malloc(0)返回非 NULL,ptr则为指向大小为零的内存块的有效指针。malloc实现以特定于实现的方式保存此信息 。realloc知道(特定于实现的)方法来找出ptr指向大小为零的内存块。

(如何malloc//这样做是特定于实现的。一种可能性是分配比请求多 4 个字节并将大小存储在内存块之前。在这种情况下,将给出内存块大小,即. 你不应该这样做从您的代码中,它仅供and使用)。reallocfree((int *)ptr)[-1]0reallocfree

于 2010-01-25T13:37:17.963 回答