tags:

views:

211

answers:

3

Hello, 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;

}
+4  A: 

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.

Ned Batchelder
+6  A: 

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.

Adam Rosenfield
+3  A: 

I'm going to add to Adam's answer here, because this probably won't fit in a comment. Adam is completely right. I suspect your generate_fields function, however, perhaps actually gets input from the user, I'm not sure. In any case, there are two ways to approach this:

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

and a corresponding free function, which I'll leave out for brevity. You can see what's going on - we're passing in the number of fields and the field size. Change this around as you need. The other option is to have generate fields pass back to the routine it's called from the size of the array. I'd do something like this:

int generate_fields(char** options) 
{
   int num_fields = 0;
   // somewhere here we get num_fields
   options = malloc(num_fields*sizeof(char *));
   for(int i = 0; i < num_fields; i++)
       options[i] = malloc(size_of_field);
   return num_fields;
}

And you call from main like this:

int main()
{
    int sizeofarray = 0;
    char** fields;
    sizeofarray = generate_fields(fields);

Or if you dislike that notation, you can always stick to what you had:

char** generate_fields(int* size) 

As the function prototype (return options this time and do size= somewhere in the code and call from main like this:

int sizeofarray = 0;
char** options;
options = generate_fields(&sizeofarray);

Hope that gives you some more ideas, Adam, feel free to edit any / all of this into your answer as appropriate, it comes from your answer anyway.

Ninefingers