【问题标题】:Dynamic multidimensional array reallocation动态多维数组重新分配
【发布时间】:2011-05-31 05:02:48
【问题描述】:

我在使用 realloc 函数时遇到了一些问题。

我正在用这个函数分配一个动态二维数组:

Bubble ***allocBubblesMatrix(int height, int width) {
  Bubble ***bubblesMatrix = (Bubble***) malloc(height * sizeof(Bubble**));
  assert(bubblesMatrix != NULL);
  int i;
  for (i = 0; i < height; ++i) {
    bubblesMatrix[i] = (Bubble**) malloc(width * sizeof(Bubble*));
    assert(bubblesMatrix[i] != NULL);
  }
  int x, y;  
  for (y = 0; y < height; ++y)
    for (x = 0; x < width;  ++x)
      bubblesMatrix[y][x] = newBubble(rand() % N_BUBBLES);

  return bubblesMatrix;
}

使用下一个代码调用wich:

int matrixHeight = 1, 
    matrixWidth  = MATRIX_X_SIZE;
Bubble ***bubblesMatrix = allocBubblesMatrix(matrixHeight, matrixWidth);

这样就成功创建了一个二维数组 1* MATRIX_X_SIZE。

然后,我想在矩阵中添加一行或多行,所以我使用realloc 和以下函数。它应该添加heightIncrement 行。问题是有时它可以工作,有时它会使程序崩溃。

void resizeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width, 
                         int heightIncrement) {
  if (heightIncrement <= 0) /* temporary */
    return;

  *bubblesMatrix = (Bubble***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));
  assert(bubblesMatrix != NULL);
  int x, y;
  int newHeight = height + heightIncrement;

  for (y = height; y < newHeight; ++y) {
    (*bubblesMatrix)[y] = (Bubble**) malloc(width * sizeof(Bubble*));
    assert((*bubblesMatrix)[y] != NULL);
    for (x = 0; x < width; ++x)
      (*bubblesMatrix)[y][x] = newBubble(rand() % N_BUBBLES);
  }
}

这个函数被调用:

while(true) {
  drawBubblesMatrix(x1, y1, matrixHeight, matrixWidth, &bubblesMatrix, bubbles);
  resizeBubblesMatrix(&bubblesMatrix, matrixHeight, matrixWidth, 1);
  ++matrixHeight;
  getch();
  clear_screen(1);
}

我做错了什么?

释放之前分配的内存块的函数:

void freeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width) {
  int y, x;
  for (y = 0; y < height; ++y) {
    for (x = 0; x < width; ++x) {
      free((*bubblesMatrix)[y][x]);
      (*bubblesMatrix)[y][x] = NULL;
    }
    free((*bubblesMatrix)[y]);
    (*bubblesMatrix)[y] = NULL;
  }
  free(*bubblesMatrix);
  *bubblesMatrix = NULL;
}

提前致谢。

编辑

  1. 真傻。正如 Karl Knechtel 所指出的,我没有对 realloc 的返回值做任何事情。但是现在程序在我每次运行时都会崩溃。
  2. 通过 Bart van Ingen Schenau 的回答,我证实了我所担心的:我忽略了之前分配的几个独立内存块。我什至最终得到了与 Bart 编写的代码相似的代码,但它继续使程序崩溃。
  3. 我添加了assert 来检查malloc/realloc 调用的结果,但我没有任何运气。我在 Win98 中使用 djgpp,发生的事情真的很奇怪:
    • Windows:有时,它永远不会崩溃;其他的,添加 2 行后会崩溃。
    • MS-DOS:添加 2 行后崩溃。 我将尝试将 -O3 与 gcc 一起使用以获取更多线索。什么是适用于 Windows 的有用(且快速学习/使用)的内存损坏/泄漏检测工具? Purify 是最佳解决方案吗?
  4. 甚至我释放数组的函数也返回页面错误。

【问题讨论】:

  • Bubble ****bubblesMatrix 也许是时候考虑一​​些typedef了
  • 我完全同意。我会这样做的。

标签: c dynamic multidimensional-array memory-management realloc


【解决方案1】:

我整理了一个快速测试用例,得出的结论是,您现在遇到的问题不在此代码块中。我创建了一个非常简单的测试用例,用整数替换了 Bubble 对象。当我这样做时,重新分配成功完成而不会崩溃。这是我的代码:

#include <malloc.h>
#include <assert.h>

int myVal = 0xDEAD;

int ***allocBubblesMatrix(int height, int width);
void resizeBubblesMatrix(int ****bubblesMatrix, int height, int width, 
                         int heightIncrement);

int main(int argc, char **argv)
{
  int matrixHeight = 1, matrixWidth = 10;
  int i = 0;
  int ***matrix = allocBubblesMatrix(matrixHeight, matrixWidth);
  for(i = 1; i < matrixWidth; i++)
    resizeBubblesMatrix(&matrix, matrixHeight, matrixWidth, 1);
  printf("Complete!\n");
}

int ***allocBubblesMatrix(int height, int width) {
  int ***bubblesMatrix = (int***) malloc(height * sizeof(int**));
  assert(bubblesMatrix != NULL);
  int i;
  for (i = 0; i < height; ++i) {
    bubblesMatrix[i] = (int**) malloc(width * sizeof(int*));
    assert(bubblesMatrix[i] != NULL);
  }
  int x, y;  
  for (y = 0; y < height; ++y)
    for (x = 0; x < width;  ++x)
      bubblesMatrix[y][x] = &myVal;

  return bubblesMatrix;
}

void resizeBubblesMatrix(int ****bubblesMatrix, int height, int width, 
                         int heightIncrement) {
  if (heightIncrement <= 0) /* temporary */
    return;

  *bubblesMatrix = (int***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(int**));
  assert(bubblesMatrix != NULL);
  int x, y;
  int newHeight = height + heightIncrement;

  for (y = height; y < newHeight; ++y) {
    (*bubblesMatrix)[y] = (int**) malloc(width * sizeof(int*));
    assert((*bubblesMatrix)[y] != NULL);
    for (x = 0; x < width; ++x)
      (*bubblesMatrix)[y][x] = &myVal;
  }
}

我所做的唯一更改是将 Bubble 替换为 int,并将矩阵中的所有条目指向单个 int 变量,而不是进行更多分配。

这意味着错误出现在 drawBubblesMatrix() 或 newBubble() 中。

【讨论】:

    【解决方案2】:

    您需要分别重新分配每个维度。您不能同时重新分配两个维度,因为每个“行”都是单独分配的。

    *bubblesMatrix = (Bubble ***) realloc(bubblesMatrix, (height + heightIncrement) * width * sizeof(Bubble*));
    

    需要改成

    *bubblesMatrix = (Bubble ***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));
    

    【讨论】:

    • 确实如此。我已经解决了。但是,我仍然遇到一些问题。
    • 你有没有核心文件。还要确保您的编译器已打开所有警告,即 gcc 使用 -Wall。有时,当编译器对您的代码进行更深入的检查时,打开所有优化也会触发额外的警告。在 gcc 中给 -O3 一个机会,看看你是否得到了额外的线索。
    • 我还建议您研究内存损坏/泄漏检测工具。您或许可以下载 Purify 的试用版
    • www-01.ibm.com/software/awdtools/purify linux 也有一个名为 Valgrind 的空闲内存检查器。 valgrind.org
    • -O3 没有帮助。我得到了完全相同的警告。
    【解决方案3】:

    您对realloc 的使用存在许多问题。

    1. 您将错误的指针传递给realloc。您应该传递您从malloc 选择的指针,即*bubblesMatrix。
    2. allocBubblesMatrix 和 resizeBubblesMatrix 函数中的矩阵“布局”不同。在 alloc 函数中,你分配了几个独立的内存块,但在 resize 函数中,你将其视为一大块内存。那根本行不通。

    正确的用法是:

    void resizeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width, 
                             int heightIncrement) {
      *bubblesMatrix = (Bubble ***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));
      int i;
      int newHeight = height + heightIncrement;
      for (i = height; i < newHeight; ++i)
        (*bubblesMatrix)[i] = (Bubble**) malloc(width * sizeof(Bubble*));
      int x, y;
      for (y = height; y < newHeight; ++y)
        for (x = 0; x < width; ++x)
          (*bubblesMatrix)[y][x] = newBubble(rand() % N_BUBBLES);
    }
    

    但是这个函数还是有一些问题:

    • malloc 和 realloc 都可能失败,此处不予考虑
    • 如果heightIncrement 为负数,则resize 函数中存在内存泄漏。

    【讨论】:

    • 谢谢。您消除了我对代码的一些疑问。但不幸的是,它仍然崩溃。 (我用新代码编辑了我的问题。)关于函数中的问题,我知道它们的存在,只是我还没有修复它们,但再次感谢你记住我。
    • @Renato:我建议您首先解决分配失败的可能问题,只要在每个malloc/realloc 调用之后添加一个assert。这样,您就可以确定分配是否成功,或者您可以确定程序终止的原因。
    • 添加了 asserts 但没有运气。
    【解决方案4】:

    阅读documentation:

    该函数可以将内存块移动到一个新位置,在这种情况下返回新位置.... 指向重新分配的内存块的指针,它可以与 ptr 参数相同或新位置。 此指针的类型是 void*,可以将其强制转换为所需的数据指针类型,以便可取消引用。 如果函数未能分配请求的内存块,则返回 NULL 指针,参数 ptr 指向的内存块保持不变。

    你不能正确使用realloc而不对返回值做一些事情。现在,您的代码期望 realloc 始终能够以新块位于同一位置的方式重新分配内存。这显然是不可能的;数组之后的内存可能正在用于其他用途。

    【讨论】:

    • 谢谢。然而,程序仍然崩溃。
    • 你还没有在重新分配函数中分配新的Bubble**s。
    猜你喜欢
    • 2017-03-18
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多