Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to properly free a char **table in C

Tags:

c

malloc

I need your advice on this piece of code: the table fields options[0], options[1] etc... doesn't seem to be freed correctly. Thanks for your answers

int main()
{
  ....
  char **options;
  options = generate_fields(user_input);
  for(i = 0; i < sizeof(options) / sizeof(options[0]); i++)  {
    free(options[i]);
    options[i] = NULL;
  }

  free(options);
}

char ** generate_fields(char *) 
{
   char ** options = malloc(256*sizeof(char *));
   ...
   return options;

}
like image 766
Zenet Avatar asked Mar 20 '10 16:03

Zenet


2 Answers

The problem is this:

for(i = 0; i < sizeof(options) / sizeof(options[0]); i++)

options is a pointer type, not an array type, so sizeof(options) will always be the same (typically 4 bytes on a 32-bit machine or 8 bytes on a 64-bit machine), so sizeof(options)/sizeof(options[0]) will almost always be 1.

The key is to always free memory in the same manner as you malloc'ed it. So, if you malloc a 2-dimensional array and then malloc a series of 1-dimensional arrays, you need to do the reverse when freeing it:

char ** generate_fields(char *) 
{
   char ** options = malloc(256*sizeof(char *));
   for(int i = 0; i < 256; i++)
       options[i] = malloc(some_size);
   return options;
}

void free_fields(char ** options)
{
    for(int i = 0; i < 256; i++)
        free(options[i]);
    free(options);
}

Note that if the size (256 in this case) is not a constant, you need to keep track of it yourself, since otherwise you have no way of knowing how many times to loop when freeing.

like image 103
Adam Rosenfield Avatar answered Oct 07 '22 13:10

Adam Rosenfield


You should have the same number of frees as you have mallocs.

In your code you allocate the array of pointers, but you don't allocate any memory for the individual elements of the array to point to. But your freeing code is written as if you did.

like image 29
Ned Batchelder Avatar answered Oct 07 '22 13:10

Ned Batchelder