Malloc (0)的意义何在?

我刚看到这个 密码:

artist = (char *) malloc(0);

我想知道为什么会有人这么做?

90819 次浏览

根据规范,Malloc (0)将返回“一个空指针或一个可以成功传递给 free ()的唯一指针”。

这基本上允许您不分配任何东西,但是仍然可以毫不担心地将“ Artist”变量传递给 free ()调用。出于实际目的,这几乎和做事情一样:

artist = NULL;

不确定,根据我找到的一些 随机 malloc 源随机 malloc 源代码,输入0将导致返回值为 NULL。因此,这是一种将艺术家指针设置为 NULL 的疯狂方法。

Http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html

C 标准(C177.22.3/1)说:

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

因此,malloc(0)可以返回 NULL或一个有效的指针 可能不会被取消引用。在任何一种情况下,对它调用 free()都是完全有效的。

我真的不认为 malloc(0)有多大用处,除了在例如在循环中调用 malloc(n)的情况下,而且 n可能为零。

看看链接中的代码,我相信作者有两个误解:

  • 返回一个有效的指针 一直都是,并且
  • free(0)不好。

因此,他确保 artist和其他变量总是有一些“有效”的值。这条评论说的一样多: // these must always point at malloc'd data

Malloc (0)行为是特定于实现的。这个库可以返回 NULL 或者具有常规的 malloc 行为,不分配任何内存。不管它做什么,肯定在什么地方被记录下来了。

通常,它返回一个有效和唯一的指针,但是不应该取消引用。还要注意,它可以消耗内存,即使它实际上没有分配任何东西。

可以重新分配一个非空的 malloc (0)指针。

但是一字不差地使用 malloc (0)并没有多大用处。它主要用于动态分配为零字节且不需要验证的情况。

malloc(0)对我来说没有任何意义,除非代码依赖于特定于实现的行为。如果代码是可移植的,那么它必须考虑这样一个事实,即从 malloc(0)返回 NULL 不是一个失败。那么,为什么不把 NULL 赋值给 artist呢,因为这是一个有效的成功结果,而且代码更少,而且不会让维护程序员花时间去解决这个问题呢?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)malloc(some_variable_which_might_be_zero)也许有它们的用途,但是如果返回值为0,那么您必须格外小心,不要将 NULL 返回值视为失败,但是0大小应该是可以的。

不可否认,我以前从未见过这种情况,这是我第一次见到这种语法,可以说,这是一种典型的函数过度使用的情况。结合 Reed 的回答,我想指出,有一个类似的东西,它看起来像一个重载的函数 realloc:

  • Foo 是非空的,大小为零,realloc(foo, size);。当您传入一个非 NULL 指针和大小为0的 realloc 时,realloc 的行为就像调用 free (...)一样
  • Foo 为 NULL,size 为非零且大于1,realloc(foo, size);。当您传入一个 NULL 指针并且 size 为非零时,realloc 的行为就好像您调用了 malloc (...)

希望这对你有帮助, 最好的问候, 汤姆。

实际回答提出的问题: 没有理由这么做

Malloc (0)将返回 NULL 或一个可以正确传递给 free 的有效指针。虽然它所指向的内存看起来是无用的,或者它不能被写入或读取,但这并不总是正确的。:)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

我们期待一个内存区段错误在这里,但令人惊讶的是,这打印100!这是因为当我们第一次调用 malloc 时,malloc 实际上需要一个巨大的内存块。之后每次调用 malloc 都会使用那个大块的内存。只有在这个大块结束之后,才需要新的内存。

使用 malloc (0) : 如果您希望后续的 malloc 调用速度更快,那么调用 malloc (0)就可以了(边缘情况除外)。

malloc(0)将返回一个有效的内存地址,其范围取决于被分配内存的指针的类型。还可以为内存区域赋值,但这应该在所使用的指针类型的范围内。您还可以释放分配的内存。我将用一个例子来解释这一点:

int *p=NULL;
p=(int *)malloc(0);
free(p);

上面的代码在 Linux 机器上的 gcc编译器中可以很好地工作。如果您有一个32位编译器,那么您可以提供整数范围内的值,即 -2147483648至2147483647。这同样适用于字符。请注意,如果声明的指针类型发生变化,那么无论 malloc类型转换如何,值的范围都会发生变化,即。

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

因为 p被声明为一个无符号整型,所以它的值从0到255为 char。

在这个页面的其他地方有一个以“ malloc (0)将返回一个有效的内存地址,其范围将取决于被分配内存的指针的类型”开头的答案。这种说法是不正确的(我没有足够的声誉直接评论这个答案,所以不能把这个评论直接放在下面)。

执行 malloc (0)将 没有自动分配正确大小的内存。Malloc 函数不知道要将其结果强制转换到什么。Malloc 函数完全依赖于作为参数给出的大小数。您需要执行 malloc (sizeof (int))来获得足够的存储空间来保存整型数据,例如,不是0。

这里有很多半真半假的答案,所以这里有一些确凿的事实。malloc()的手册页面显示:

如果 size 为0,那么 malloc ()返回 NULL,或者返回一个唯一的指针值,稍后可以返回 成功传给 free ()。

这意味着,绝对不能保证 malloc(0)的结果是唯一的或者不是 NULL。free()的定义提供了唯一的保证,下面是手册中的内容:

如果 ptr 为 NULL,则不执行任何操作。

因此,无论 malloc(0)返回什么,它都可以安全地传递给 free()

因此,写作 artist = malloc(0); 并不比写作好多少 artist = NULL;

在 Windows 中:

  • void *p = malloc(0);将在本地堆上分配一个零长度的缓冲区。返回的指针是一个有效的堆指针。
  • malloc最终使用默认的 C 运行时堆调用 HeapAlloc,然后调用 RtlAllocateHeap,等等。
  • free(p);使用 HeapFree释放堆上的0长度缓冲区。不释放它将导致内存泄漏。

你为什么不能这么做。

因为 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 validpoint”,这意味着 ptr不为空。

只是为了纠正一个错误的印象:

artist = (char *) malloc(0);永远不会返回 NULL,它与 artist = NULL;不同。编写一个简单的程序,比较 artistNULLif (artist == NULL)为假,if (artist)为真。

下面是运行后的分析与瓦尔霍恩内存检查工具。

==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 (事实上非常频繁)都有这种行为。