【问题标题】:How to properly free when there's an error allocating memory for two dimensional array为二维数组分配内存出错时如何正确释放
【发布时间】:2026-01-14 20:40:01
【问题描述】:

在出现问题后释放二维数组中的内存时,我遇到了一些奇怪的事情。

案例一:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

int main(void)
{
    int **a = NULL;
    int i;
    int j;

    if(!(a = calloc(5, sizeof(int *))))
    {
        printf("Error, could not allocate memory for a!\n");
        exit(EXIT_FAILURE);
    }

    for(i = 0; i < 5; i++)
    {
        if(i != 2)
        {
            if(!(a[i] = calloc(3, sizeof(int))))
            {
                printf("Error, could not allocate memory for a[%d]!\n",i);
                for(j = 0; j < i; j++)
                {
                    free(a[j]);
                }
                free(a);
            }
        }

        else
        {
            if(!(a[i] = calloc(MAX_INT * 1000, sizeof(int))))
            {
                printf("Error, could not allocate memory for a[%d]\n", i);
                for(j = 0; j < i; j++)
                {
                    free(a[j]);
                }
                free(a);
            }
        }
    }

    return 0;
}

案例 2:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

int main(void)
{
    int **a = NULL;
    int i;
    int j;

    if(!(a = calloc(5, sizeof(int *))))
    {
        printf("Error, could not allocate memory for a!\n");
        exit(EXIT_FAILURE);
    }

    for(i = 0; i < 5; i++)
    {
        if(i != 2)
        {
            if(!(a[i] = calloc(3, sizeof(int))))
            {
                printf("Error, could not allocate memory for a[%d]!\n",i);
                for(j = 0; j <= i; j++)
                {
                    free(a[j]);
                }
                free(a);
            }
        }

        else
        {
            if(!(a[i] = calloc(MAX_INT * 1000, sizeof(int))))
            {
                printf("Error, could not allocate memory for a[%d]\n", i);
                for(j = 0; j <= i; j++)
                {
                    free(a[j]);
                }
                free(a);
            }
        }
    }

    return 0;
}

这两种情况的唯一区别是,在情况 1 中,当分配内存出错时(我故意分配较大的内存导致它在 i == 2 时失败)我从 j = 0 循环到 j

【问题讨论】:

  • 嗯,也许MAX_INT * 1000 溢出了?添加assert(SIZE_MAX/1000 &gt;= MAX_INT);。你确定代码需要这么大的数组吗?我想你可能想要:calloc(1000, sizeof(int))
  • 为什么需要分配MAX_INT的物品?这看起来就像你在试图破坏某些东西。
  • 请注意,在许多系统上MAX_INT*1000 causes an overflow,因此您会得到未定义的行为而不是分配错误。
  • @e0k,我试图打破它。我希望触发 free 语句,以便我可以使用 valgrind 测试泄漏,看看是否有任何一种方法产生了泄漏。

标签: c arrays memory-leaks


【解决方案1】:

为了进入分配失败的if 的分支,a[i] 必须设置为NULL 指针。 Since passing NULL pointer to free is well-defined in the C standard,在循环中包含或排除 a[i] 没有区别。

不过,两个版本都有相同的问题:当故障发生在外部 for 循环内时,您不会在清理后退出程序,而是让分配继续。这应该通过在free(a) 之后添加对exit(EXIT_FAILURE) 的调用来解决。

【讨论】: