Optimal way to free() a malloc'ed 2D array in C - c

Supposing I have a 2 dimensional array which was created with something like this,
char **foo = (char **) malloc(height * sizeof(char *));
for(i = 0; i <= height; i++)
foo[i] = (char *) malloc (width * sizeof(char *));
First of all, Is this even the right way to create an array like this?. The catch here is, 'height' and 'width' is something that is set during runtime.
This seems to work, but which is the best strategy to free this 2d array.
free(funge) sounds wrong. Going by some other posts in here, I guess I will have free each row one by one?
I did try something like this,
for (height = 0; height < ip_ptr->funge_height; height++) {
free(funge[height]);
}
free(funge)
This, however gives me a double free pointer exception. Does this mean, I don't have to manage this piece of memory?. I was of the impression that, for every malloc'ed memory we should call free().

Since all the 'rows' are the same size, you can just allocate it in one swoop, with malloc(height * width * sizeof (char *)) (it's not entirely clear whether you're creating a 2d array of char or a 2d array of char *). You can use multiplication to calculate the appropriate index (i.e. foo[i][j] becomes foo + i * height + j),
free()ing it will similarly, take a single call.

In the for loop for allocation you are using i <= height; instead of i < height;. So you are writing to an invalid memory location and the behavior of your code becomes unpredictable.

The second allocation should be:
foo[i] = (char *) malloc (width * sizeof(char));
you're also looping height+1 times while allocating.
Besides that, those two snippets seem right to me, so the error should be elsewhere.
If the array was allocated as just one big chunk of memory, then you'd have to free it just once.
char **foo = (char **) malloc(height * sizeof(char *));
*foo = malloc(height * width * sizeof(char))
for (int i = 1; i < height; i++) {
foo[i] = *foo + i*width;
}
//and you just do 2 frees
free(*foo);
free(foo);

The mechanism to allocate is OK (though you should use sizeof(char) instead of sizeof(char *) in the allocate loop; you are overallocating the character strings) given that width and height are runtime values.
Your impression that you should call free() once for each malloc() is basically correct (things like calloc() and realloc() complicate the simple story).
The loop followed by free should be correct (or, at least, the general mechanism of 'free the sub-arrays first, then the array of pointers to sub-arrays) - so you need to review where the double free error is coming from. We can't see where the ip_ptr->funge_height was controlled; it is not immediately obvious that funge is described by ip_ptr->funge_height.
See the answer from 'unknown # google' - there's an array bounds problem.

When you allocate the memory, it should be i < height as the loop condition.
When you deallocate the memory, you should iterate up to the same index as you did when allocating. ip_ptr->funge_height should be the same as the original height, but it's not obviously so.
Other than that, it should work.
Here's another way, that involves fewer mallocs and frees.
To allocate:
char **foo = malloc (height * sizeof (char **));
foo[0] = malloc (height * width * sizeof (char *));
for (i = 1; i < height; ++i) {
foo[i] = foo[i-1] + width;
}
To deallocate:
free (foo[0]);
free (foo);

Allocation (assuming height > 0 and width > 0)
char **foo, *row;
assert(height > 0 && width > 0);
foo = malloc(height * sizeof *foo);
row = malloc(height * width * sizeof *row);
assert(foo != NULL && row != NULL);
for (i = 0; i < height; ++i, row += width)
foo[i] = row;
assert(row == *foo + height * width);
Deallocation
assert(foo != NULL);
free(*foo);
free(foo);

In such cases you can always use valgrind. Just compile your executable and run it:
valgrind --leak-check=full ./a.out
Valgrind will find all your memory validations and point to the code lines involved.
In your case it may have find the indexing problem (< vs. <=) easily.

If your compiler supports it, you could use a pointer to a variable-length array, ie
size_t width = 10, height = 5;
char *(*foo)[height][width] = malloc(sizeof *foo);
Keep in mind that you'll have to derefence the pointer before accessing the array elements, eg
(*foo)[1][2] = "foo";
This has the benefit that you'll only allocate a single, continuous block of memory which can be deallocated with a single call fo free().

This 100% works without exe crash.
char **map2d;
map2d=(char **)malloc(MAXY*sizeof(char *));
for(int a=0; a<MAXY; a++)
map2d[a]=(char *)malloc(MAXX*sizeof(char));
for(int a=0; a<MAXX; a++)
free(map2d[a]);
free(map2d);

Related

Why do I get the error: "double free or corruption(out) core dumped Aborted core dumped", when trying to free memory on heap?

I have used a malloc 2-D array and this it:
charArray = (char **)malloc(rows * sizeof(char *));
for (i = 0; i < columns; i++)
charArray[i] = (char *)malloc(columns * sizeof(char *));
And when I try to free the memory, it says: "double free or corruption(out). Aborted (core dumped). This is how i free it:
for (i = 0; i < rows; i++) {
free(charArray[i]);
charArray[i] = NULL;
}
free(charArray);
charArray = NULL;
Why do I get this error and how can I fix it? This is the valgrind report:
From the code you posted it is hard too see.
Make your life easier and use array pointers.
char (*charArray)[columns] = malloc(rows * sizeof(*charArray));
Only one allocation and free is needed. Fewer levels of indirection - faster code.
Your code fragment is terse to say the least, but there is a problem in the allocation loop: for (i = 0; i < columns; i++) should iterate on rows, not columns and allocate columns characters, not pointers.
If rows and columns differ, you have undefined behavior:
either columns > rows and the allocation code writes pointers beyond the end of the allocated block for charArray
or rows > columns and you attempt to free pointers that were not allocated and are probably invalid.
To avoid such mistakes, it is recommended to use sizeof with type of the destination element:
char **charArray = calloc(rows, sizeof(*charArray));
for (i = 0; i < rows; i++)
charArray[i] = calloc(columns, sizeof(*charArray[i]));
It would also be simpler to allocate a flat 2D array of char instead of an indirect array:
char (*charArray)[columns] = calloc(rows, sizeof(*charArray));
This array is also simpler to free:
free(charArray);

Copying a 2D array to a dynamically allocated 2D array outside of the function

I have fullNames, which is a 2D array that has sorted full names in it and I want to copy its content into sortedNames, which is a 2D array that exists out side of this function. (I get ***sortedNames as a parameter).
I dynamically allocated this array, but the copying does not succeed. The program crashes after the 4th attempt to copy a name from fullNames to sortedNames. Why?
stringcpy and stringlen are functions that I created. They do the same thing as strcpy and strlen does.
/*allocating memory for sortedNames*/
*sortedNames = (char**) malloc(n);/*n is the number of names*/
/*allocating memory for each sortedNames array*/
for (i = 0; i < n; i++)
{
(*sortedNames)[i] = (char*) malloc(stringlen(fullNames[i])+1);
}
/*Copying fullNames into sortedNames*/
for (i = 0; i < n; i++)
{
stringcpy((*sortedNames)[i],fullNames[i]);
}
You do not allocate enough memory for the array of pointers, you should allocate this way:
*sortedNames = (char**)malloc(n * sizeof(char *));
Furthermore, why not use strlen and strcpy in place of stringlen and stringcpy? It this just a typo or do these function perform some extra function?
Regarding the cast on malloc return value, you could remove it if you do not intend to compile your code as C++ and write this:
*sortedNames = malloc(n * sizeof(**sortedNames));
Regarding the extra parentheses around **sortedNames, be aware that they are not necessary so you can remove them or not depending on your local style conventions.
There should be 2 edits as the memory allocated may not be sufficient. This code :
(*sortedNames)[i] = (char*) malloc(n);
allocates memory for n bytes whiles you need memory for (n*the size of string) bytes.The second malloc may work as char occupies 1 byte. But try to use sizeof() to make it system independent.
The correct code would be :
(*sortedNames)[i] = malloc(n*sizeof(char *));

free a double pointer

I created a 2-D matrix using double pointer like that:
int** pt; pt = (int*) malloc(sizeof(int)*10);
I know that a pointer is freed like that
free(ptr);
How can we free the double pointer?
What if we print something and later freed that memory and exit the program? Does the final memory consist of that which we used or it will be same as initial?
Say you have a matrix mat
int** mat = malloc(10 * sizeof(int*));
for (int i=0; i<10; ++i) {
mat[i] = malloc(10 * sizeof(int));
}
then you can free each row of the matrix (assuming you have initialized each correctly beforehand):
for (int i=0; i<10; ++i) {
free(mat[i]);
}
then free the top-level pointer:
free(mat);
For your second question: if you allocate memory and use it, you will change that memory, which will not be "reverted" even if you free it (although you will not be able to access it reliably/portably any more).
Note: the top-level malloc is using sizeof(int*) as you are allocating pointer-to-ints, not ints -- the size of int* and int are not guaranteed to be the same.
If your matrix isn't "ragged", i.e. all rows have the same length, you might want to consider:
Accessing it manually, i.e. just treat it as a 1D array of values, and keep a separate width value. To access an element at (x,y) use mat[y * width + x].
If you really want the convenience of mat[y][x], you can improve it by doing a single call to malloc() that allocates both the pointer array and all the rows, then initializing the pointers to point at each row. This has the advantage that it can all be free:ed with a single free(mat); call.
The second approach would look something like this:
double ** matrix_new(size_t width, size_t height)
{
double **p = malloc(height * sizeof *p + width * height * sizeof **p);
double *e1 = (double *) (p + height);
size_t i;
for(i = 0; i < height; ++i)
p[i] = e1 + i * width;
return p;
}
Note: the above is un-tested, and production code should obviously check for failure before using p.
For the first question, I'll tell you the rule of thumb.
The number of times you call free() should be equal to the number of times you call malloc() + the number of times you call calloc().
So if you allocated in such a way that you made a pointer to pointers to ints, and then used malloc() on each pointer to ints, then you'll free "row" number of times, where each free() is for each pointer to ints.
And a final free() is called on the pointer to pointers to ints. That will balance out the malloc() + calloc() with free() calls.

Reallocation of contiguous 2D array

I am generating contiguous 2d arrays using the method posted on here by Shawn Chin.[1][2] It works very well.
Briefly from his post:
char** allocate2Dchar(int count_x, int count_y) {
int i;
# allocate space for actual data
char *data = malloc(sizeof(char) * count_x * count_y);
# create array or pointers to first elem in each 2D row
char **ptr_array = malloc(sizeof(char*) * count_x);
for (i = 0; i < count_x; i++) {
ptr_array[i] = data + (i*count_y);
}
return ptr_array;
}
And the following free function:
void free2Dchar(char** ptr_array) {
if (!ptr_array) return;
if (ptr_array[0]) free(ptr_array[0]);
free(ptr_array);
}
It is not obvious to me how to create an equivalent reallocate function in either dimension, though I am only interested in realloc'ing the number of rows while maintaining continuity. Growing the number of columns would be interesting to understand but probably quite difficult. I haven't found any direct discussion of this issue anywhere other than to say, "it's hard!".[2]
Of course this is doable by a horrible brute force method, copying the data to a new 1D array (data, above) for storage, realloc'ing the 1D array, then freeing and regenerating the pointers (ptr_array) to the row elements for the new size. This, however, is pretty slow for row modifications, since it is necessary to at least double the memory requirement to copy out the data, and this is truly horribly bad for changing the number of columns.
This is an example of said method for changing the number of rows (it wouldn't work properly for changing the number of columns because the offsets for the pointers would be wrong for the data). I haven't fully tested this, but you get the idea ...
double **
reallocate_double_array (double **ptr_array, int count_row_old, int count_row_new, int count_col)
{
int i;
int old_size = count_row_old * count_col;
int new_size = count_row_new * count_col;
double *data = malloc (old_size * sizeof (double));
memcpy (&data[0], &ptr_array[0][0], old_size * sizeof (double));
data = realloc (data, new_size * sizeof (double));
free (ptr_array[0]);
free (ptr_array);
ptr_array = malloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}
Plus, this method requires you know the previous size, which is obnoxious!
Any thoughts greatly appreciated.
[1] How can I allocate a 2D array using double pointers?
[2] http://www.eng.cam.ac.uk/help/tpl/languages/C/teaching_C/node52.html
The first malloc and the memcpy are unnecessary, because you have easy access to the original data array at ptr_array[0]. You don't need to know the old size, because realloc should recall how much it allocated at the address and move the correct ammount of data.
Something like this should work.
double **
reallocate_double_array (double **ptr_array, int count_row_new, int count_col)
{
int i;
int new_size = count_row_new * count_col;
double *data = ptr_array[0];
data = realloc (data, new_size * sizeof (double));
free (ptr_array);
ptr_array = calloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}

Dynamic allocation (malloc) of contiguous block of memory

For an assignment, I have to allocate a contiguous block of memory for a struct, but I'm first trying to do it with a 2D array of ints first and see if I understand it correctly. We had an example in the book that creates a block of memory for the pointer array (rows), and then initializes the cols and points the pointer to them. This example was:
int **CreateInt2D(size_t rows, size_t cols)
{
int **p, **p1, **end;
p = (int **)SafeMalloc(rows * sizeof(int *));
cols *= sizeof(int);
for (end = p + rows, p1 = p; p1 < end; ++p1)
*p1 = (int *)SafeMalloc(cols);
return(p);
}
void *SafeMalloc(size_t size)
{
void *vp;
if ((vp = malloc(size)) == NULL) {
fputs("Out of mem", stderr);
exit(EXIT_FAILURE);
}
return(vp);
}
I basically need to do what the above code does except make it one contiguous block of memory. The constraint is I'm only allowed to call malloc once, and then I have to use pointer math to know what to initialize the pointers to. So I thought I would initialize enough memory with something like:
int *createInt2D(size_t rows, size_t cols)
{
malloc(rows * sizeof(int *) + (row + cols) * sizeof(int));
}
But that doesn't seem quite right since I would think I would have to typecast the void * returned from malloc, but it's a combination of int and int*. So I'm not quite sure if I'm on the right track. Thoughts?
If you want a contiguous array, you should malloc(rows * cols * sizeof(int)).
Then you'd access arr[x, y] like:
arr[x * cols + y]
You are on the right track. The block returned by malloc is guaranteed to be aligned properly for either int * or int; you can use it for either. Typecasting isn't a one time operation.
If you are going to use array[row, col] addressing exclusively, you can get by without allocating extra space for the row pointers. If you would like to be able to use array[row] to get an int * column list, you'll have to include space for the column pointers in your allocation.
Hope that's enough to help with your exercise.
malloc((row * cols) * sizeof(int));
It's row*cols which is number of elements in the 2D array and not row+cols.
No need to multiply by the size of int *. That's only used to allocate the pointers for the rows. Same too with the sum of rows and cols. It's sufficient to allocate (rows * cols) * sizeof whatever structure is being allocated.

Resources