为什么malloc(0)在Windows中返回非空地址?

为什么malloc(0)在Windows中返回非空地址?,c,memory-management,malloc,C,Memory Management,Malloc,下面的代码在Windows中执行时返回一个地址,尽管我希望它返回NULL int main() { char *ptr = NULL; ptr = malloc(0); printf("malloc returned = %u\n", ptr); } 是什么促使了malloc的实现?这背后有什么原因吗 因为这是一个0字节的内存,所以我没有尝试写入任何数据。但是,这个内存可以用来做任何事情吗?这在comp.lang.c常见问题解答中得到了回答: ANSI/ISO标准说,它可以

下面的代码在Windows中执行时返回一个地址,尽管我希望它返回NULL

int main()
{
   char *ptr = NULL;
   ptr = malloc(0);
   printf("malloc returned = %u\n", ptr);

}
是什么促使了malloc的实现?这背后有什么原因吗


因为这是一个0字节的内存,所以我没有尝试写入任何数据。但是,这个内存可以用来做任何事情吗?

这在comp.lang.c常见问题解答中得到了回答:

ANSI/ISO标准说,它可以做到以下两个方面:;行为由实现定义(见问题11.33)。可移植代码必须注意不要调用malloc(0),或者为可能的空返回做好准备


标准说它可以做到这两个方面


这只是您要求的最小尺寸。由于Win32堆中没有零长度块,您可以:

void *p = malloc(0);
// ... do some stuff in between...
realloc(p, n);
这将主要导致重用堆的一个块(如果幸运的话,并且新的大小很小的话)。一个小的机会主义优化(或减速,取决于环境和血液咖啡水平)


这是一个简化的例子。实际情况可能是一个类,它在创建缓冲区时分配缓冲区,并允许对其进行扩展。如果输入难以控制,您可以让它执行零大小的缓冲区分配。

回答问题的第二部分否,内存不能用于任何事情,因为“可访问部分”是从返回的地址开始的0字节


IIRC可以保证,如果实现返回非null,那么它将是一个与当前分配的任何其他内存块不同的地址。因此,从理论上讲,您可以使用地址作为临时唯一ID(指针类型),尽管显然有很多其他方法可以获得唯一ID。即使您打算使用它,
malloc(1)
也可以与
malloc(0)
一样工作,并且更便于移植。

这并不是无用的。从malloc返回的块应该是唯一的。因此,malloc返回的每个块都携带块内的数据和它的唯一标识符,即它的地址。如果后一个属性很重要,并且它不包含任何数据这一事实不是问题,那么它是有用的


然而,正如前面提到的,这是编写不可移植代码的好方法。但是,这与非法代码不同,实现支持它是完全有效的(显然windows也是如此)。

但是,是什么让实现选择返回一些有效值呢?在所有情况下返回NULL是否都有意义?不一定。对于二次猜测的编译器编写者,我不寒而栗,但只有在内存无法真正分配时,实现者才可能希望malloc返回
null
。@Jay:由于实现可以自由执行这两种操作,它可能会决定执行较少的代码。决定不麻烦自己编写额外的代码行来测试输入0并返回空指针是合理的。再说一次,如果实现已经有了一个测试,证明所需的大小不是非常大(如果是的话,将返回一个空指针),那么检查非常大或为零可能同样容易。+1就像我实际看到有一个人为了“优势”而使用它一样当他不想在循环中对任何可能使malloc'd/realloc'd内存增长得非常大的东西进行特殊处理时,您可以将空指针传递到
realloc
,因此此技巧绝非必要。你也可以
void*p=0@Steve这不是什么把戏。它是编程和松散平台规范的产物。例如,在没有测试的情况下,不清楚heaperalloc(heap,heap\u REALLOC\u IN\u PLACE\u ONLY,0,4)的行为方式。@user1240436:我的意思是“小编程技术”意义上的“技巧”。我的观点是,JimR的朋友不需要这样做,以避免特殊的套管环。从空指针开始就可以了。更有趣的场景是分配非零大小的东西,然后使用
realloc
将其调整为零,然后使用另一个
realloc
将其调整为原始大小。通过让“收缩”realloc调用至少“弱”保留内存,可以提高效率,因此如果原始对象想要恢复到其早期大小,可以将其返回给原始对象。如果零大小的realloc(0)返回null,则系统无法知道应该将块返回给谁。如果零大小的realloc可以返回非null,那么零大小的malloc也没有理由不返回。