我该检查malloc()是否成功?

18

在每次使用 malloc() 之后,是否应该检查它是否成功?malloc() 是否会失败?如果失败会发生什么?

在学校里,我们被告知应该进行检查:

arr = (int) malloc(sizeof(int)*x*y);
if(arr==NULL){
    printf("Error. Allocation was unsuccessful. \n");
    return 1;
}

这方面有什么惯例吗?我可以这样做吗:

if(!(arr = (int) malloc(sizeof(int)*x*y))
    <error>

5
理论上是可以的。但实际上,如果malloc失败了,操作系统很可能即将崩溃。PS:你的第二个例子比第一个难以阅读,应该被代码审查拒绝。 - Steve Wellens
2
arr = (int) malloc(...) 是错误的,malloc 返回一个指针。除此之外:是的,你应该检查它是否失败,因为它可能会失败。另外,强制转换其返回值是有害的。 - The Paramagnetic Croissant
  1. 你不需要进行强制类型转换。
  2. 是的,检查一下 - 为什么不呢?
- Ed Heal
1
@AlexD - 确实如此。但是,如果您分配的缓冲区太大,以至于malloc可能会失败,那么我会说需要重新设计。 - Steve Wellens
这回答了你的问题吗?为什么会在条件语句中使用赋值操作符? - ggorlen
显示剩余4条评论
2个回答

27

这主要是对现有答案的补充,但我理解你的想法,如果你进行了大量的内存分配,你的代码最终看起来会非常丑陋,并且需要添加所有用于 malloc 的错误检查。

个人而言,我经常使用一个小型的 malloc 包装器来避免这个问题,它永远不会失败。除非您的软件是一个具有弹性和安全性的关键系统,否则您不能有意义地解决 malloc 失败的情况,因此我建议使用类似以下的东西:

static inline void *MallocOrDie(size_t MemSize)
{
    void *AllocMem = malloc(MemSize);
    /* Some implementations return null on a 0 length alloc,
     * we may as well allow this as it increases compatibility
     * with very few side effects */
    if(!AllocMem && MemSize)
    {
        printf("Could not allocate memory!");
        exit(-1);
    }
    return AllocMem;
}

这样至少可以确保您获得一个错误消息和干净的崩溃,避免了所有错误检查代码的冗长。

对于可能会失败的函数,我还倾向于实现一个简单的宏,如下所示:

#define PrintDie(...) \
    do \
    { \
    fprintf(stderr, __VA_ARGS__); \
    abort(); \
    } while(0)

这将允许您运行一个函数,如下所示:

if(-1 == foo()) PrintDie("Oh no");

这将给您一个单行内容,再次避免大块内容同时实现适当的检查。


3
你的 PrintDie 应该调用 abort,而不是 exit。这样更容易进行调试(在 Linux 上,甚至会生成一个 core 转储文件,你可以使用 gdb 进行事后分析)。 - Basile Starynkevitch
@BasileStarynkevitch 谢谢,我忘记了abort,现在已经将示例更改为使用它。 - Vality
4
if(NULL == AllocMem) 这个判断是错误的。当 MemSize == 0 时,接收到 malloc() 返回值为 NULL 是符合规范的行为而不是分配失败。将其更改为 if(NULL == AllocMem && MemSize != 0) 可以解决该问题。 - chux - Reinstate Monica
@chux,你说得对,大多数实现都希望这种行为,但在标准中有些棘手,因为它说(在C99和C11中):“如果请求的空间大小为零,则行为是实现定义的”(7.22.3 P1,ISO C11)。然而,你建议的方法在许多编译器中都是常见的实现方式,所以我将在代码中添加一个检查,并附上注释。谢谢。 - Vality
1
@Ayxan 看起来是这样。虽然我以前从未在BSD上开发过,也没有见过xmalloc。不过看起来是个有用的函数。感谢提供信息。 - Vality
显示剩余2条评论

13

不需要对malloc()进行类型转换。但是,需要检查malloc()是否成功。

假设malloc()失败并且您正在尝试访问指针,认为内存已经被分配,这将导致崩溃。因此,在访问指针之前最好捕获内存分配失败。

int *arr = malloc(sizeof(*arr));
if(arr == NULL)
{
printf("Memory allocation failed");
return;
}

11
重点强调一下,这个回答提倡“检查malloc()是否成功分配内存”,这是个好主意。但是后面展示的是如何检查malloc(sizeof(int))的结果,而不是OP的malloc(sizeof(int)*x*y)。对于这个sizeof(int),测试是否等于NULL是足够的,但对于OP的sizeof(int)*x*y来说是错误的。如果x*y为0,则返回NULL是符合规范的代码,并不能表明内存已经被成功分配。更好的方法是使用if(arr == NULL && x != 0 && y != 0)来检查。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接