SSpoke
SSpoke

Reputation: 5836

How to free up a char*** memory properly In C so I don't get memory leak

I got the following code

int rows = 123;
int cols = 12;
char ***data = (char ***)malloc(rows * sizeof(char **));
if(data) {
    for(int i = 0; i < num_rows; i++)
    {
        data[i] = (char **)malloc(cols * sizeof(char *));
        if(!data[i])
        {
            for(int j = 0; j < i; j++)
                free(data[j]);
            free(data);
            printf("no memory\n");
            return -1;
        }
    }
}
char randomData[] = "<Inserts random string here everytime>";
for(int row = 0; row < rows; row++) {
     for(int col = 0; col < cols; col++) {
         data[row][col] = (char *) malloc(sizeof(char) * (1 + strlen(randomData)));
         strcpy(data[row][col], randomData);
     }
}

This example I wrote for this stackoverflow because real code is similar but <Inserts random string here everytime> is output from each SQL row and each column.

I just want to make a multi-dimensional array like data[row][column]

How do I free it up properly when I am done?

I was thinking to clear it up I have to first clear the first star. char *

for(int row = 0; row < rows; row++) {
     for(int col = 0; col < cols; col++) {
         free(data[row][col]);
     }
}

Then clear up the second star char **

for(int row = 0; row < rows; row++) {
     free(data[row]);
}

Then I can finally clear the last triple star char ***

    free(data);

Is this how you do it? seems like a overkill too much free's.. is the

for(int row = 0; row < rows; row++) {
     for(int col = 0; col < cols; col++) {
         free(data[row][col]);
     }
}

enough?

Upvotes: 2

Views: 282

Answers (3)

Serge Ballesta
Serge Ballesta

Reputation: 148890

You must de-allocate everything you malloc'ed.

At most you can save a loop by writing :

for(int row = 0; row < rows; row++) {
     for(int col = 0; col < cols; col++) {
         free(data[row][col]);
     }
     free(data[row]);
}
free(data);

If you want to de-allocate in a single pass, you must allocate in a single pass, but it is tricky for an array of pointers and must be commented in a red flashing font :

data = malloc(rows * (1 + cols) * sizeof(void *));
for (i=0; i<rows; i++) {
    data[i] = &(data[cols * i]);
}

De-allocate would then be :

for(int row = 0; row < rows; row++) {
     for(int col = 0; col < cols; col++) {
         free(data[row][col]);
     }
}
free(data);

If you prefer, you can allocate directly a 2D array :

data = malloc(rows * cols * sizeof(void *));

But then, you must access to the individual elements by data[j + i * rows] ... to be commented in red flashing font ...

Upvotes: 2

Jongware
Jongware

Reputation: 22457

Every single call to malloc needs a single call to free. You already outlined the correct (!) way to free up all allocations. The number of frees should not be a problem (after all, you have no problem with the exact same number of calls to malloc).

If you want to test to be sure, add some low-level debugging code:

  1. Add an integer int number_of_allocations = 0; at the top of your routine.
  2. Increment it after every single malloc.
  3. Decrement it after each free.
  4. Test if the net result is 0 at the end.

As far as I can tell, there should be no leak in there.

Upvotes: 2

bachN
bachN

Reputation: 612

You need to free as much as you malloc

To free the whole array it depends on your array dimension,

lets see first how you allocate this array :

1 - char ***array = char pointer to 2d arrays (A)

2 - **array= char pointer to 2d array         (B)

3 - *array= char pointer to (vector) of char  (C)

if you have ***array you need to start by :

1 - freeing each vector of your inner array (C)
2 - freeing inner array pointer             (B)                  
3 - freeing the main pointer                (A)

for your example you can do :

for(int row = 0; row < rows; row++) {
    for(int col = 0; col < cols; col++) {
        free(data[row][column]);
    }
    free(data[row]);
}
free(data);

Upvotes: 2

Related Questions