1

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.
2
  • Bubble ****bubblesMatrix perhaps it's time to consider some typedefs Commented Dec 27, 2010 at 16:24
  • I totally agree. I'll do that. Commented Dec 27, 2010 at 22:13

4 Answers 4

3

Read the documentation:

The function may move the memory block to a new location, in which case the new location is returned.... A pointer to the reallocated memory block, which may be either the same as the ptr argument or a new location. The type of this pointer is void*, which can be cast to the desired type of data pointer in order to be dereferenceable. If the function failed to allocate the requested block of memory, a NULL pointer is returned, and the memory block pointed to by argument ptr is left unchanged.

You cannot correctly use realloc without doing something with the return value. Your code, right now, expects that realloc will always be able to reallocate the memory in such a way that the new block is in the same place. This is clearly impossible; the memory immediately after your array might be in use for something else.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Yet, the program still crashes.
You haven't allocated new Bubble** s in the reallocation function.
3

There are a number of things wrong with your use of realloc.

  1. You are passing the wrong pointer to realloc. You should pass the pointer you optained from malloc, which would be *bubblesMatrix.
  2. The 'layout' of the matrices in your allocBubblesMatrix and resizeBubblesMatrix functions is different. In the alloc function, you allocate several independent memory blocks, but in the resize function, you treat it as one big block of memory. That will simply not work.

The correct usage would be:

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

But this function still has some issues:

  • Both malloc and realloc can fail, which is not taken into account here
  • If heightIncrement is negative, you have a memory leak in the resize function.

3 Comments

Thanks. You took me out some doubts I had about my code. But unfortunately, it still crashes. (I edited my question with the new code.) About the issues in the function, I know their existence, I just didn't yet fixed them, but again, thanks for remembering me.
@Renato: I would advice you to address the possible problem with the allocation failure first, if only by adding an assert after every malloc/realloc call. That way you can be sure that either the allocations succeeded or you get an identifiable reason for the program termination.
Added asserts but with no luck.
2
+50

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().

Comments

1

You need to reallocated each dimension separately. You cannot reallocate both dimensions at once, since each "row" was allocated individually.

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

needs to change to

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

5 Comments

Indeed. I already fixed that. Yet, I'm still having some problems.
Do you get a core file. Also ensure that your compiler has all warnings turned on, i.e. for gcc use -Wall. Sometimes also turning on all optimizations triggers additional warning as the compiler does a deeper inspection of your code. In gcc give -O3 a shot to see if you get additional clues.
I would also advise you to look into memory corruption/leak detection tools. You may be able to download a trial version of Purify
www-01.ibm.com/software/awdtools/purify Also linux has a free memory checker called Valgrind. valgrind.org
-O3 didn't help. I'm getting exactly the same warnings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.