4

I'm just starting to learn coding in c, and I have a few questions regarding 2d matrices in combination with the free() command.

I know that you first need to create an array with pointer, pointing to the different columns of the matrix:

double **array = (double **)malloc(5*sizeof(double *));
for(int n = 0; n<5; n++){

array[n] = (double *) malloc(6*sizeof(double));

I know that the correct way to then deallocate this matrix is to first deallocate the individual rows and then the array pointer itself. Something along the lines of:

for (i = 0; i < nX; i++){  
   free(array[i]); }     

free(array);

My question is: Why is this necessary? I know that this incorrect, but why can't you just use: free(array)? This would deallocate the pointer array, to my understanding. Won't the memory that is used by the columns just be overwritten when something else needs acces to it? Would free(array) lead to corrupted memory in any way?

Any help is much appreciated!

B.Ing
  • 57
  • 6
  • 1
    It is not a 2D array. It is an array containing pointers to other arrays. All of those other arrays exist elsewhere in memory and need to be freed. – Christian Gibbons Dec 06 '18 at 21:04
  • @ChristianGibbons: It's a pointer to pointer, not a pointer to array(s). – too honest for this site Dec 06 '18 at 21:24
  • 1
    @toohonestforthissite I wanted to keep the clarity that these were not singular objects. It can be difficult to describe in a way that is technically correct but still clear. – Christian Gibbons Dec 06 '18 at 21:34
  • Not freeing the rows doesn't lead to corrupted memory, it just means that memory can never be used again for the lifetime of the program (since it's been allocated and not freed, but you don't know where it is any more). If you do this too much you will run out of memory. – M.M Dec 06 '18 at 22:04

4 Answers4

6

It would not lead to corruption, no, but would create a memory leak.

If done once in your program, it probably doesn't matter much (a lot of professional/expensive applications have - small,unintentional - memory leaks), but repeat this in a loop, and you may run out of memory after a while. Same thing if your code is called from an external program (if your code is in a library).

Aside: Not freeing buffers can be a useful way (temporarily) to check if the crashes you're getting in your programs originate from corrupt memory allocation or deallocation (when you cannot use Valgrind). But in the end you want to free everything, once.

If you want to perform only one malloc, you could also allocate one big chunk, then compute the addresses of the rows. In the end, just deallocate the big chunk (example here: How do we allocate a 2-D array using One malloc statement)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
6

Your code, not only allocate memory for array of pointers (the blue array), but in the for loop, you also allocate memory for the red arrays as well. So, free(array) line, alone, will just free the memory allocated by the blue array, but not the red ones. You need to free the red ones, just before loosing the contact with them; that is, before freeing the blue array.

And btw;

Won't the memory that is used by the columns just be overwritten when something else needs acces to it?

No. The operating system will keep track of the memory allocated by your process (program) and will not allow any other process to access the allocated memory until your process terminates. Under normal circumstances —I mean, remembering the C language not having a garbage collector— the OS never knows that you've lost connection with the allocated memory space and will never attempt like, "well, this memory space is not useful for this process anymore; so, let's de-allocate it and serve it for another process."

enter image description here

ssd
  • 2,340
  • 5
  • 19
  • 37
2

This is needed because C does not have a garbage collector. Once you allocate memory with malloc or similar function, it is marked as "in use" for as long as your program is running.

It does not matter if you no longer hold a pointer to this memory in your program. There is no mechanism in the C language to check this and automatically free the memory.

Also, when you allocate memory with malloc the function does not know what you are using the memory for. For the allocator it is all just bytes.

So when you free a pointer (or array of pointers), there is no logic to "realize" these are pointers that contain memory addresses.

This is simply how the C language is designed: the dynamic memory management is almost1 completely manual - left to the programmer, so you must call free for every call to malloc.


1 C language does handle some of the more tedious tasks needed to dynamically allocate memory in a program such as finding where to get a free continuous chunk of memory of the size you asked for.

Lev M.
  • 6,088
  • 1
  • 10
  • 23
0

Let's take this simple example:

int **ptr = malloc(2*sizeof *ptr);
int *foo = malloc(sizeof *foo);
int *bar = malloc(sizeof *bar);
ptr[0] = foo;
ptr[1] = bar;
free(ptr);

If your suggestion were implemented, foo and bar would now be dangling pointers. How would you solve the scenario if you just want to free ptr?

klutt
  • 30,332
  • 17
  • 55
  • 95
  • it's a counterfactual example – Tim Randall Dec 06 '18 at 21:28
  • @toohonestforthissite *"If your suggestion were implemented"* – klutt Dec 06 '18 at 21:30
  • I can read (and even undertand). My objection stands, neither `foo` nor `bar` are dangling pointers and for the original code, there are no dangling pointers either, because after **the object `array` points to** has been freed, it does not exist anymore`. FWIW: A dangling pointer is a pointer which points to unallocated memory. – too honest for this site Dec 07 '18 at 08:00
  • @toohonestforthissite OP:s suggestion is that the call `free(ptr)` should also free the pointers `ptr[0]` and `ptr[1]`. That would leave `foo` and `bar` as dangling pointers. – klutt Dec 07 '18 at 08:44
  • @Broman: Ah, now I got what he means. However, if OP's suggestion was implemented, the only reasonable thing was to mark `foo` and `bar` null pointers (or otherwise "pointing to nowhere). Insofar OP's question is not well researched resp. thought. Said that, it does not makes sense to GC an object as long there is a pointer to it anyway. But OP explicitly shows an example where there are **no** further pointers to the `malloc`ed objects making this answer pointless. – too honest for this site Dec 07 '18 at 09:12