【问题标题】:Dynamic array cleanup when malloc returns nullmalloc 返回 null 时的动态数组清理
【发布时间】:2016-09-20 21:35:00
【问题描述】:

我想知道在 2D 数组创建失败期间清理已分配的内存的最佳方法是什么。

int** a = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i != rows; ++i)
    a[i] = (int*)malloc(columns * sizeof(int));

for (int i = 0; i != rows; ++i)
    free(a[i]);

free(a);

上面的示例代码应该像魅力一样工作。但是malloc 可以返回null,而当它返回时,上面的代码将无法处理该问题。我们如何保护这种情况?

假设(int*)malloc(columns * sizeof(int))i = 3 返回了null。我们已经为int** aa[0]a[1]a[2] 分配了空间。

这是我目前的方法。丑陋,不确定是否正确。这就是我向您寻求帮助的原因。

int rows;
int columns;
scanf("%d", &rows);
scanf("%d", &columns);

int** a = (int**)malloc(rows * sizeof(int*));
if (!a)
{
    printf("Cannot allocate enough space."); // nothing to clean up here
    return 1; // to make example easier
}

int i;
bool arrayCreated = true;

for (i = 0; i != rows; ++i)
{
    int* tmp = (int*)malloc(columns * sizeof(int));
    if (!tmp) // malloc returned null
    {
        arrayCreated = false; // let's mark that we need to do some cleanup
        break;
    }
    a[i] = tmp;
}

if (!arrayCreated) // creation failed, clean up is needed
{
    for (int j = 0; j <= i; ++j)
        free(a[j]);
}
else
{
    for (int i = 0; i != rows; ++i)
        free(a[i]);
}

free(a);

【问题讨论】:

  • @πάνταῥεῖ 很高兴看到一个完整的例子。你介意分享吗?
  • 很多问题,最好一次发布一种语言。
  • @ArchbishopOfBanterbury 我喜欢容器和智能指针,我一直在使用它们。我只是想知道过去是怎么做到的。
  • @dptd 不要混用 newmallocfree。这是一个强有力的规则。
  • @dptd 还请详细说明您的问题,为什么您认为这些 cmets 和答案实际上是无用?这些是处理内存分配的惯用方法。如果您想要不同的东西,请选择另一种编程语言,

标签: c memory-management memory-leaks null malloc


【解决方案1】:
int** b = (int**)calloc(sizeof(int*) * rows, sizeof(int*));

这是不正确的,calloc的第一个参数是“要分配的元素数”。

应该是

int** b = (int**)calloc(rows, sizeof(int*)); /* No need to cast in C */

在 C 和 C++ 中创建多维数组的安全方法是什么 对于这种情况?

在 C 中(为了避免分段)一个真正的 2D 动态数组应该被声明为

int (*arr)[columns]; /* A pointer to an array of n ints */

和(m)分配使用

arr = malloc(sizeof(int [rows][columns]));

arr = calloc(rows, sizeof(int[columns]));

这样,一次调用free(arr); 就足够了。

【讨论】:

  • 在 C 中,一个真正的二维数组应该被声明为...你没有解释为什么。
  • @Michi,OP提供的代码是一个分段的指针对指针的东西,这个线程中有解释:stackoverflow.com/questions/12462615/…
  • 我认为这对 OP 和 C 的新成员有好处 :)
  • @AlterMann In int (*arr)[columns]; 可以在运行时提供columns 值,还是必须在编译时知道这个值?
  • 是的,在运行时提供时称为 VLA Variable length array
【解决方案2】:

简而言之:

由于您有不同的函数用于分配内存,因此您需要相应地调用它们对应的释放函数:

  • malloc()calloc()realloc() 需要通过调用 free() 来释放
  • X* x = new X(); 需要与 delete x; 一起释放
  • X** x = new X[10]; 需要使用 delete[] x; 释放

c++ 中的惯用方式是使用容器

  • std::vector&lt;X&gt; x;

smart pointer 喜欢

  • std::unique_ptr&lt;X&gt; x = std::make_unique&lt;X&gt;();

让您不再关心必要的簿记以正确平衡分配/取消分配操作。


请注意,这是一个关于此类特定情况下的错误处理的理论问题。我想强调前两种情况是针对 C 而不是 C++。

如果您使用了错误的动态内存解除/分配函数对,则没有定义标准错误处理。

如上所述,它们需要像描述的那样配对。其他任何事情都称为未定义的行为。

【讨论】:

  • @t0mm13b 我不是说了吗?
  • 在循环中使用malloc()calloc() 分配内存时,您确定调用free() 就足够了吗?如果null pointer 将在第二次迭代期间返回,你应该如何清理到目前为止分配的内存?
  • @dptd 当然,每次调用malloc()calloc() 都需要对应调用free()
【解决方案3】:

我不确定 C,但是 C++; delete[] 就足够了。

【讨论】:

  • 仅供参考,C 中没有 delete
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 2015-06-14
  • 2016-05-24
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多