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, (hei开发者_StackOverflow中文版ght + 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
- 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. - 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.
- I've added the
assert
's to check the results of themalloc
/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?
- Even my function to free the array is returning page faults.
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.
There are a number of things wrong with your use of realloc
.
- You are passing the wrong pointer to
realloc
. You should pass the pointer you optained frommalloc
, which would be*bubblesMatrix
. - The 'layout' of the matrices in your
allocBubblesMatrix
andresizeBubblesMatrix
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
andrealloc
can fail, which is not taken into account here - If
heightIncrement
is negative, you have a memory leak in the resize function.
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().
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**));
精彩评论