malloc(0)有什么意义?

刚刚看到这个代码:

artist = (char *) malloc(0); 

我想知道为什么要这样做?

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

这基本上可以让你分配任何东西,但仍然可以通过“艺术家”variables来调用free()而不用担心。 出于实际的目的,它和做的几乎一样:

 artist = NULL; 

C标准说:

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

所以, malloc(0)可能会返回NULL或一个有效的指针,可能无法解除引用 。 无论哪种情况,在它上面调用free()是完全有效的。

我真的不认为malloc(0)有多大用处,除非在循环中调用malloc(n)时, n可能为零。

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

  • malloc(0) 总是返回一个有效的指针
  • free(0)不好。

所以,他确定artist和其他variables总是有一些“有效”的价值。 评论说:尽pipe// these must always point at malloc'd data

malloc(0)行为是特定于实现的。 该库可以返回NULL或具有常规的malloc行为,没有分配内存。 无论它做什么,都必须在某个地方logging下来。

通常,它返回一个有效且唯一的指针,但不应该被解除引用。 另外请注意,它可以消耗内存,即使它没有实际分配任何东西。

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

有一个malloc(0)逐字不是很多使用,虽然。 当dynamic分配是零字节时,它通常被使用,而您并不在意它是否被validation。

在这个页面的其他地方有一个答案,开始“malloc(0)将返回一个有效的内存地址,其范围将取决于正在分配内存的指针的types”。 这个陈述是不正确的(我没有足够的声望来直接评论这个答案,所以不能直接把这个评论放在那里)。

做malloc(0) 不会自动分配正确大小的内存。 malloc函数并不知道你要把结果转换成什么结果。 malloc函数完全依赖于你给出的参数大小。 你需要做malloc(sizeof(int))来获得足够的存储来存放int,例如不是0。

在这里有很多半正确的答案,所以这里是困难的事实。 malloc()的手册页说:

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

这意味着,绝对不能保证malloc(0)的结果是唯一的或不是NULL。 free()的定义提供了唯一的保证,这里是man-page所说的:

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

所以,无论malloc(0)返回,都可以安全的传递给free() 。 但是一个NULL指针也可以。

因此,写 artist = malloc(0); 没有比写作 artist = NULL; 更好的了 artist = NULL;

malloc(0)对我来说没有任何意义,除非代码依赖于特定于实现的行为。 如果代码是可移植的,那么它必须考虑到来自malloc(0)的NULL返回不是失败的事实。 那么为什么不直接给artist分配NULL呢,因为这是一个有效的成功结果,而且代码less了,不会让你的维护程序员花时间搞清楚了吗?

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

我知道这已经五年了,但我的回答可能会增加一些,我有一个声誉要维持。

malloc(0); 可以在你不知道将要发生什么的确切时间的情况下使用。 如果长度为零的结果也是可能的结果,那么从最小分配大小开始就没有用处。 例如,缓冲区。 如果从缓冲区可能增长的地方读取可变数量的字节。 你可以使用realloc()来增长缓冲区。 但是realloc需要一个指向已经malloccalloc内存的指针,然后是使用malloc(0);

 char* buffer = malloc(0); int bytesread = 0; do { //read n bytes from somewhere buffer = realloc(buffer, bytesread + n); //expand the buffer //check it is properly allocated //copy the newly read bytes to the buffer bytesread += n; } while (there_is_still_a_chance_of_reading_more_bytes); //do something with the complete buffer free(buffer); //does not really need if(buffer); 

当然。 还有其他方面的考虑:如果你知道要读取的字节数或者这个数字会很大,那么反复读取less量字节并使用memset效率不高。

无可否认,我从来没有见过这个,这是我第一次看到这种语法,可以说,function矫枉过正的经典案例。 结合里德的答案,我想指出,有一个类似的东西,看起来像一个重载的函数realloc

  • foo是非NULL,大小为零, realloc(foo, size); 。 当你传递一个非NULL的指针和大小为零的realloc时,realloc的行为就像你调用free(…)
  • foo为NULL,大小为非零且大于1, realloc(foo, size); 。 当你传入一个NULL指针并且size是非零值的时候,realloc就像你调用了malloc(…)

希望这有助于,最好的问候,汤姆。

要真正回答提出的问题: 没有理由这样做

为什么你不应该这样做…

由于malloc的返回值是依赖于实现的,所以可能会得到一个NULL指针或其他一些地址。 如果error handling代码不检查大小和返回值,这可能最终导致堆缓冲区溢出,导致稳定性问题(崩溃)甚至更糟糕的安全问题。

考虑这个例子,通过返回地址进一步访问内存会损坏堆,如果大小为零,并且实现返回非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编码标准中的这个安全编码页面 ,我将上面的例子用于进一步阅读。

不确定的是,根据我发现的一些随机的malloc源代码,input0会导致返回值为NULL。 所以这是一个疯狂的方式设置艺术家指针为NULL。

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

malloc(0)将返回NULL或一个有效的指针,可以正确地传递给空闲。 尽pipe它指向的内存似乎是无用的,或者它不能被写入或读取,但这并非总是如此。 🙂

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

我们期望在这里出现分段错误,但是令人惊讶的是,这打印100! 这是因为当我们第一次调用malloc的时候,malloc实际上要求大量的内存。 每次调用malloc之后,都会使用来自该大块的内存。 只有在大块结束之后,才会要求新的内存。

使用malloc(0):如果你想要后续的malloc调用更快的情况,调用malloc(0)应该为你做(除了边缘情况)。

根据Reed Copsey的回答和malloc的man page,我写了一些例子来testing。 我发现malloc(0)总会给它一个独特的值。 看我的例子:

 char *ptr; if( (ptr = (char *) malloc(0)) == NULL ) puts("Got a null pointer"); else puts("Got a valid pointer"); 

输出将是“有一个有效的指针”,这意味着ptr不为空。

在Windows中:

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

这是使用valgrind内存检查工具运行后的分析。

 ==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,依此类推。

malloc(0)将返回一个有效的内存地址,其范围将取决于正在分配内存的指针的types。 您也可以将值分配给内存区域,但是这应该在正在使用的指针types的范围内。 您也可以释放分配的内存。 我将用一个例子来解释一下:

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

上面的代码在Linux机器上的gcc编译器中可以正常工作。 如果你有一个32位编译器,那么你可以提供整数范围内的值,即-2147483648到2147483647。同样适用于字符。 请注意,如果声明的指针types被改变,那么值的范围将改变,而不pipemalloctypes转换,即

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

因为它被声明为一个无符号的整数,所以p将从char到0到25​​5的值。

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

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