0

I have a array that has 6 elements. And each of those 6 elements have 40 elements. I am wondering when i free the malloced memory, do I have to free both or can i just free the main layer ( the one containing the 6 elements) will this automatically free the other secondary array?

 char ** listofdetails;  //FIRST ARRAY
    listofdetails = malloc(sizeof(char*)*6);

    for(i=0;i<6;i++)
    {
    listofdetails[i] = malloc(sizeof(char)*40); // SECONDARY ARRAY
    fgets(listofdetails[i], 40, fp);
    }
dee-see
  • 23,668
  • 5
  • 58
  • 91
45aken
  • 23
  • 1
  • 2
  • 6

6 Answers6

4

You need a destroying function like

 void destroy_array_of_cstrings (char**lis, size_t siz)
 {
    if (!lis) return;
    for (size_t ix=0; ix<siz; ix++) free (lis[ix]);
    free (lis);
 }

You'll call destroy_array_cstring(listofdetails, 6) in your case. As Alfred Hang answered, you should clear listofdetails immediately after: listofdetails=NULL; to avoid accidentally free-ing a pointer twice, or dereferencing a freed pointer.

You'll better use calloc for allocation of an array of pointers (you really want each of them to be initialized to NULL, which calloc does in practice).

See also this answer to a question also mentionning listeofdetails with 6 (so I guess it is the same homework).

BTW, you might later use Boehm's conservative garbage collector: you would use GC_MALLOC, GC_STRDUP and you won't bother about free-ing anymore. Discuss that with your teacher.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
3

Rule of thumb: for every malloc there is a free.

You have to provide a similar loop where you free each individual string before freeing the array of strings.

BeyelerStudios
  • 4,243
  • 19
  • 38
2

In addition to Basile's answer, to avoid having dangling pointers after you free each array entry, it is a good idea to immediately set the pointer to null.

Reference: free()

Alfred Huang
  • 433
  • 6
  • 13
1

No, the secondary arrays will not be freed automatically; you will need to explicitly free them before freeing listofdetails:

for ( i = 0; i < 6; i++ )
  free( listofdetails[i] );
free( listofdetails );

For every malloc there must be a free, and the free calls must be executed in the reverse order of the malloc calls.

If the number of columns is known at compile time1, you can allocate the whole thing in one malloc call, like so:

char (*listofdetails)[40] = malloc( sizeof *listofdetails * 6 );  

This allocates a 6x40 array of char in a single call. You'd use it pretty much the same way as you do above:

fgets( listofdetails[i], sizeof listofdetails[i], fp );

The type of listdetails[i] is "40-element array of char", so sizeof listdetails[i] will give us the same result as sizeof (char) * 40 (note that this only works because I declared listofdetails as a pointer to a 40-element array of char, not as a pointer to a pointer to char).

This also has the advantage that all of the rows are adjacent to each other in memory, which may matter for some situations. That's not necessarily the case for the 2-step allocation method.

This only requires a single free call:

free( listofdetails );

but y'all probably aren't to the point of discussing pointers to arrays yet.


1. If you're using a C99 compiler or a C2011 compiler that still supports variable-length arrays, you can still use the single malloc call like so:

size_t rows, cols;
...
char (*listofdetails[cols]) = malloc( sizeof *listofdetails * rows );
...
free( listofdetails );
Otherwise, you'll have to do the piecemeal allocation as in your code.
John Bode
  • 119,563
  • 19
  • 122
  • 198
0

If you want to access listofdetails[i][j] like this, then yes, you will need to malloc the internal array. And you will have to free it separately too.

If you know the inner array size and it is fixed for all, then you can alloc everything up front (width * height) and access it like this: listofdetails[i * width + j]

Nick Banks
  • 4,298
  • 5
  • 39
  • 65
0

After dynamically allocating memory for this aaray when it comes time to free one of these dynamically allocated multidimensional ``arrays,'' we must remember to free each of the chunks of memory that we've allocated. (Just freeing the top-level pointer, array, wouldn't cut it; if we did, all the second-level pointers would be lost but not freed, and would waste memory.) Here's what the code might look like:

for(i = 0; i < nrows; i++)
    free(array[i]);
free(array);

For your case it should be :

for ( i = 0; i < 6; i++ )
  free( listofdetails[i] );
free( listofdetails ); 
PU.
  • 148
  • 9