非常简单的问题,我写了下面这个程序:
#include <stdlib.h>
int main(int argc, char ** argv)
{
void * ptr;
ptr = malloc(0);
free(ptr);
}
它在我的机器上没有段错误。这是stdlib中malloc和free的可移植行为,还是我在寻找麻烦?
编辑: 看起来不可移植的是malloc返回的值。问题是关于malloc(0) + free组合,而不是ptr的值。
行为是实现定义的,您将接收到一个NULL指针或地址。然而,调用接收到的指针的free应该不会导致问题,因为:
可以返回NULL指针,也可以返回不能被解引用的非NULL指针,这两种方式都是标准允许的(参见7.20.3):
如果请求空间的大小为零,则行为是实现定义的:要么返回一个空指针,要么行为好像大小是一些非零值,除了返回的指针不应用于访问对象。
抱歉给您带来麻烦,我应该先阅读man手册:
malloc() 分配大小为size的字节并返回指向分配内存的指针。内存不会被清除。如果size为0,则malloc()返回NULL或唯一指针值,稍后可以成功传递给free()。
free() 释放ptr指向的内存空间,该指针必须是之前调用malloc()、calloc()或realloc()返回的。否则,或者如果已经调用过free(ptr),就会发生未定义行为。如果ptr为NULL,则不执行任何操作。
至少对于gnu libc而言,这似乎是正确的。
虽然这可能是合法的C/C++,但它表明了更大的问题。我通常称之为“指针粗心大意”。
请参见“不要对malloc(0)或calloc(0)的结果做出假设”,https://www.securecoding.cert.org/confluence/display/seccode/VOID+MEMxx-A.+Do+not+make+assumptions+about+the+result+of+malloc%280%29+or+calloc%280%29。
ptr
设置为null,在另一个平台上则设置为非null,但只要不对其进行解引用操作,那么代码就是正确的,并且可以正常工作。 - M.MNULL
,或者一个唯一的指针,稍后可以传递给free
。如果没有最小可重现测试用例,并命名发生这种情况的确切环境:编译器版本、库、操作系统,则您的评论是无用的。 - Kazptr
来自malloc(size)
,那么((char *) ptr)]size]
不是有效字节,在这种情况下,size
为0。此外,您不能多次释放它。一旦您释放它,它就变得不确定;这些指针容易出现双重释放错误。假设malloc(0)
的结果可以在两个或更多位置被释放的程序将在返回NULL的平台上运行,但在其他地方可能会失败。 - Kaz
malloc(0)
是有用的,而这并没有被提到。在那些返回非NULL值的实现中,特别是在DEBUG版本中,它很可能会分配比您请求的更多的内存,并给您指向其内部标头之后的指针。如果您在一系列分配之前和之后获取此指针,则可以了解实际内存使用情况。 - Jesse Chisholm