Search code examples
cdynamicmultidimensional-arraymemory-managementrealloc

Dynamic multidimensional array reallocation


I'm having some trouble with the realloc function.

I'm allocating a dynamic bidimensional array with this function:

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 is called with the next code:

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

This successfuly creates a bidimensional array 1* MATRIX_X_SIZE.

Then, I want to add a row or multiple rows to the matrix, so I use realloc with the following function. It's supposed to add heightIncrement rows. The problem is that sometimes it works, other it crashes de program.

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);
  }
}

This function is called with:

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

What am I doing wrong?

Function to deallocate the memory blocks previously allocated:

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;
}

Thanks in advance.

EDIT

  1. Silly me. I wasn't doing anything with the return value of realloc as the Karl Knechtel pointed out. But now the program crashes whenever I run it.
  2. With Bart van Ingen Schenau's answer, I confirmed what I feared: I was ignoring the several independent memory blocks that I had allocated previously. I even ended up with a similar code to the one written by Bart but it continues to crash the program.
  3. I've added the assert's to check the results of the malloc/realloc calls and yet I didn't have any luck. I'm using djgpp with Win98 and what's happening it's really odd:
    • Windows: Sometimes, it never crashes; others, it crashes after adding 2 rows.
    • MS-DOS: Crashes after adding 2 rows. I'm gonna try to use -O3 with gcc to get additional clues. What would be a useful (and quick to learn/use) memory corruption/leak detection tool for windows? Is Purify the best solution?
  4. Even my function to free the array is returning page faults.

Solution

  • I threw together a quick test case, and I have come to the conclusion that the problem you are now experiencing is not in this block of code. I created a very simple test case that replaces the Bubble objects with ints. When I do this, the reallocation completes successfully without crashing. Here is my code:

    #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;
      }
    }
    

    The only changes I made were to replace Bubble with int, and to point all the entries in the matrix to a single int variable rather than doing even more allocation.

    That means the error is either in drawBubblesMatrix() or in newBubble().