Reputation: 2065
Given the following code:
typedef struct Tokens {
char **data;
size_t count;
} Tokens;
void freeTokens(Tokens *tokens) {
int d;
for(d = 0;d < tokens->count;d++)
free(tokens->data[d]);
free(tokens->data);
free(tokens);
tokens = NULL;
}
Why do I need that extra:
free(tokens->data);
Shouldn't that be handled in the for loop?
I've tested both against valgrind/drmemory and indeed the top loop correctly deallocates all dynamic memory, however if I remove the identified line I leak memory.
Howcome?
Upvotes: 2
Views: 109
Reputation: 17061
Let's look at a diagram of the memory you're using in the program:
+---------+ +---------+---------+---------+-----+
| data | --> | char * | char * | char * | ... |
+---------+ +---------+---------+---------+-----+
| count | | | |
+---------+ v v v
+---+ +---+ +---+
| a | | b | | c |
+---+ +---+ +---+
|...| |...| |...|
+---+ +---+ +---+
In C, we can dynamically allocate space for a group (more simply, an array) of elements. However, we can't use an array type to reference that dynamic allocation, and instead use a pointer type. In this case, the pointer just points to the first element of the dynamically allocated array. If you add 1 to the pointer, you'll get a pointer to the second element of the dynamically allocated array, add two to get a pointer to the second element, and so on.
In C, the bracket syntax (data[1]
) is shorthand for addition and dereferencing to a pointer. So pointers in C can be used like arrays in this way.
In the diagram, data
pointing to the first char *
in the dynamically allocated array, which is elsewhere in memory.
Each member of the array pointed to by data
is a string, itself dynamically allocated (since the elements are char *
s).
So, the loop deallocates the strings ('a...'
, 'b...'
, 'c...'
, etc), free(tokens->data)
deallocates the array data
points to, and finally, free(tokens)
frees the entire struct.
Upvotes: 6
Reputation: 83527
As a general rule of thumb, every malloc()
should have a corresponding call to free()
. If you look at the code which allocates the memory in this program, you will very likely see a very strict correspondence with the code you posted here that frees the memory.
Upvotes: 3
Reputation: 2708
data
is a pointer to a pointer. This means data
points to a dynamically allocated array of pointers, which then each point to the actual data. The first for loops frees each of the pointers IN the array, but you still need to free the original pointer TO that array of the other points which you freed already. That's the reason for the line you pointed out.
Upvotes: 4