简体   繁体   中英

How to free my double pointer allocated with malloc in another function

I want to free the double pointer, the problem is I was receiving as parameter another double pointer which actually makes a copy of the one I wanna free but that means it doesn't actually free the original, so how can I free the original in another function.

I've tried passing a double pointer as argument and a pointer pointing to this double pointer too but none of this worked.

int main(){

    int ** matrix;
    int rows = 5;
    int cols = 6;
    matrix = createMatrix(rows, cols);
    printf("%d\n", matrix[2][3]);
    freeMatrix(matrix, rows);
    printf("%d\n", matrix[2][3]);
}
int** createMatrix(int row, int col){
    int **m = (int **)malloc(row * sizeof(int*));
    for(int x = 0; x < row; x++){
        m[x] = (int *)malloc(col * sizeof(int));
    }
    return m;
}
void freeMatriz(int **m, int row){
    for(int x = 0; x < row; x++){
        free(m[x]);
    }
    free(m);
}

I was trying to print a position, lets say matrix[2][3] before and after the free; but both times its printing the number when after the print it shouldn't because that space in memory its supposed to be freed which apparently is not happening.

other than the typo in the

void freeMatriz(int **m, int row)
              ^

This is correctly freeing up the memory. The printf after freeing the matrix should actually result in an access violation. Which when testing with a MUCH larger 1024x2048 matrix this is what happens. My theories are as follows...

  1. The memory has not yet been reclaimed and was still within program reach...
  2. Some sort of delay in garbage collection or something.. lol

I'll leave it up to someone who might know why the second printf worked with such a small memory space being allocated to do so.. ;) would love to know the exact reason..

if you step through this with a debugger you will see the memory does get freed properly and if stepped through with a debugger the second printf results in an access violation... so it's gotta have something to do with the kernel.. :)

If you look at the Working Set and the Memory allocation in task manager, and put a system("pause") or getchar() (whatever type of break you want) before the free.. you can allocate a large matrix, check in in task manager... resume the program (with another break after the free). and you will see that the memory is being released. :)

Your two primary problems are:

  1. You fail to validate the return of each allocation so malloc could have failed and you would have no way of knowing; and
  2. After allocating storage for your integer values, you fail to initialize the memory, leaving the memory holding whatever garbage values happened to be present at that memory location (you can, and in the case of your integer allocations, use calloc to allocate and initialize at the same time, or use memset to do the same)

Your attempt to access matrix[2][3] before free() was simply accessing a uninitialized 4-bytes of memory containing whatever bits happened to be there. Your attempt to access matrix[2][3] after free() invokes Undefined Behavior . After free() , you can no longer validly access the memory that has been freed.

If you allocate, you must validate... It's not a matter of if malloc can fail returning NULL , it is a matter of when malloc fails returning NULL . To handle the failure case, you must always check the return of the allocation function (just as you do with every input function) you use. It is simple, if malloc returns NULL the allocation failed. So just check, eg

int **creatematrix (int row, int col)
{
    int **m = malloc (row * sizeof *m);

    if (!m) {                   /* if you allocate -- you must VALIDATE */
        perror ("malloc-m");
        return NULL;
    }

    for (int x = 0; x < row; x++) {
        if (!(m[x] = malloc (col * sizeof *m[x]))) {    /* ditto */
            perror ("malloc-m[x]");
            while (x--)         /* on error free any allocated memory */
                free (m[x]);
            free (m);           /* before returing NULL */
            return NULL;
        }
    }

    return m;
}

( note: before returning NULL you should free() any memory you have allocated up to that point to prevent a memory leak when you return NULL )

In your calling function ( main() here), you need to validate the return of your creatematrix function to determine success/failure of the allocate -- before you make use of the memory, eg

int main (void) {

    int **matrix,
        rows = 5,
        cols = 6;

    if (!(matrix = creatematrix (rows, cols)))  /* VALIDATE allocations */
        exit (EXIT_FAILURE);

    for (int i = 0; i < rows; i++) {        /* loop initializing all values */
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
            printf (" %3d", matrix[i][j]);  /* output all values */
        }
        putchar ('\n');
    }

    freematrix (matrix, rows);              /* free all allocated memory */
}

Now you can free() all memory (which except for the typo of 'z' instead of 'x' you were doing correctly). Putting it altogether you could do:

#include <stdio.h>
#include <stdlib.h>

int **creatematrix (int row, int col)
{
    int **m = malloc (row * sizeof *m);

    if (!m) {                   /* if you allocate -- you must VALIDATE */
        perror ("malloc-m");
        return NULL;
    }

    for (int x = 0; x < row; x++) {
        if (!(m[x] = malloc (col * sizeof *m[x]))) {    /* ditto */
            perror ("malloc-m[x]");
            while (x--)         /* on error free any allocated memory */
                free (m[x]);
            free (m);           /* before returing NULL */
            return NULL;
        }
    }

    return m;
}

void freematrix (int **m, int row)
{
    for (int x = 0; x < row; x++)
        free (m[x]);

    free (m);
}

int main (void) {

    int **matrix,
        rows = 5,
        cols = 6;

    if (!(matrix = creatematrix (rows, cols)))  /* VALIDATE allocations */
        exit (EXIT_FAILURE);

    for (int i = 0; i < rows; i++) {        /* loop initializing all values */
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
            printf (" %3d", matrix[i][j]);  /* output all values */
        }
        putchar ('\n');
    }

    freematrix (matrix, rows);              /* free all allocated memory */
}

Example Use/Output

$ ./bin/freematrix
   0   1   2   3   4   5
   6   7   8   9  10  11
  12  13  14  15  16  17
  18  19  20  21  22  23
  24  25  26  27  28  29

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/freematrix
==17080== Memcheck, a memory error detector
==17080== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17080== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17080== Command: ./bin/freematrix
==17080==
   0   1   2   3   4   5
   6   7   8   9  10  11
  12  13  14  15  16  17
  18  19  20  21  22  23
  24  25  26  27  28  29
==17080==
==17080== HEAP SUMMARY:
==17080==     in use at exit: 0 bytes in 0 blocks
==17080==   total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==17080==
==17080== All heap blocks were freed -- no leaks are possible
==17080==
==17080== For counts of detected and suppressed errors, rerun with: -v
==17080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM