0

Currently, I'm learning about pointers and static/dynamic memory allocation. In the following code, I have a 3D array. The variable array is a pointer to a pointer to a pointer mat3***. I've learnt that malloc allocates memory from the heap and returns a pointer. The function free frees that memory.

int main()
{
   double*** mat3;
   int m,n,p;
   int i,j,k;
   
   m=2; n=3; p=4; /* unequal dimensions should work fine as well */
   
   mat3 = (double***) malloc(m*sizeof(double**));
   if (mat3 == NULL)
    exit(1);
   
   for (i=0; i<m; i++)
   {
      mat3[i] = (double**) malloc(n*sizeof(double*));;
      if (mat3[i] == NULL)
          exit(1);
      
      for (j=0; j<n; j++)
      {
          mat3[i][j] = (double*) malloc(p*sizeof(double));
          if (mat3[i][j] == NULL)
             exit(1);
      }
   }
   
   // Fill with some data that makes checking easy (value = sum of the indexes) :
   for(i=0;i<m;i++)
      for(j=0;j<n;j++)
         for(k=0;k<p;k++)
            mat3[i][j][k] = i + 10*j + 100*k;
   
   show(mat3,m,n,p);
   
   free(mat3);
}

So after showing I'm done with the 3D array and I want to free the memory. Therefore I use free, but I really doubt if I did it correctly. Since I gave to command for the *** to be freed, but the ** itself and the * were not in a command. So that would mean that in the heap there are still pointers to pointers and the pointers itself. If that is true I wouldn't know how to free the memory, maybe I could use the same loop, but then instead of allocating memory I could free it.

Another question is more theoretical. Since I freed the memory, but the memory is not overwritten immediately. If I use free() before printf() I get a segmentation error. Although the memory is freed? The physical memory location still exists right? So why couldn't I access it with the reference address?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Tim
  • 415
  • 2
  • 10
  • 1
    `free()` *frees*, it doesn't *reallocate*. You want to *free* the memory. – Marco Bonelli Oct 10 '20 at 13:42
  • Unless you want a ragged array, you don't need to malloc each dimension separately. It's enough to malloc `m * n * p` entries and index into it with something like `i * (m + n) + j * n + k`... – AKX Oct 10 '20 at 13:44
  • @AKX that format is part of an assignment. I cannot change that. – Tim Oct 10 '20 at 13:46
  • 1
    It's fine to `malloc` per dimension but you have to `free` per dimension too. `free` isn't recursive. Also, see [this](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – ggorlen Oct 10 '20 at 13:47

1 Answers1

3

So that would mean that in the heap there are still pointers to pointers and the pointers itself.

This is true. As a rule of thumb, remember that for each malloc(), there must be a corresponding free(). You are:

  1. Allocating space for the 3D matrix (m pointers of type double **).
  2. Allocating space for each 2D matrix (n pointers of type double *, m*n total).
  3. Allocating space for each line of each 2D matrix (p double values, m*n*p total).

Therefore, when you free, you must do the exact same thing, but backwards:

  1. Free the memory for each of the lines of each 2D matrix.
  2. Free the memory for each 2D matrix.
  3. Free the memory for the 3D matrix.

In terms of code:

for(i = 0; i < m; i++) {
    for(j = 0; j < n; j++) {
        free(mat3[i][j]);
    }

    free(mat3[i]);
}

free(mat3);

Since I freed the memory, but the memory is not overwritten immediately. If I use free() before printf() I get a segmentation error. Although the memory is freed? The physical memory location still exists right? So why couldn't I access it with the reference address?

You do not know anything about what happens to the memory you free. What really happens is implementation specific, OS specific, and depends on different complex factors. It could still exist, it could have been deallocated by the system, it could have been used by different parts of the program when calling other malloc()s (printf() uses malloc() too). Accessing memory after freeing it is undefined behavior.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • Thanks for the reply! I was thinking about it again and it is also possible to this without a loop? Instead of a loop you would do 3 free() statements. free(mat3[0][0]) free(mat3[0]]) free(mat3) Since the [0][0] and [0] point to the adress of the array? – Tim Oct 18 '20 at 17:13
  • 1
    @Terr070 no, not possible without loops. You have to free *all* of them, not just `[0]` or `[0][0]`. You do `1 + n*m` allocations, you need to do `1 + n*m` frees. – Marco Bonelli Oct 18 '20 at 17:14