And, welcome back to another fabulous episode of 'Puny Mortals Asking
(Potentially)
Dumb Questions'.
I wrote a solution to K&R's exercise 1-16 that uses dynamic memory allocation. As part of checking my work, I ran my code through Valgrind. Valgrind reported some memory leaks, though I had a 1:1 malloc:free ratio (which is perplexing). After much fiddling and reading of the GNU c lib manual and the Valgrind user manual , I eventually came to SO. None of the posts that I read really solved my problem, until I noticed some solutions to other unrelated problems that used a notation that may be expressed as the following equivalence:
*(dbl_ptr + i) == dbl_ptr[i]
Where dbl_ptr
is of type char**
and i
is of type int
.
In my own, original code, I had been attempting to free()
a double pointer in the following manner:
for( i = 0 ; i < count ; ++i ) {
free( (dbl_ptr + i) ); //Valgrind complains about a leak right here
}
free( dbl_ptr );
But when I recompile the program with these lines instead:
for( i = 0 ; i < count ; ++i ) {
free( dbl_ptr[i] ); //No more Valgrind complaints
}
free( dbl_ptr );
The program is then reported as being memory safe. Why?
Help me to understand, merciful and benevolent StackOverlords!
CODA:
I recommend reading templatetypedef's answer to this post if you want a solid understanding of what happened here. I don't believe I can write a better explanation of what was going wrong within my own code. It turns out that my error was a combination of misunderstandings about how free()
interprets arguments, as well as a fundamental ignorance of the semantics behind the array syntax in C.
Fast and dirty: dbl_ptr[i]
implicitly dereferences dbl_ptr + i
.
When you call free
, the argument should be a pointer to the front of the block of memory you want to deallocate.
So let's suppose you have an array of double*
s. That array looks like this:
dbl_ptr ---> [ 0 ][ 1 ][ 2 ] ... [ k ]
| | | |
v v v v
arr arr arr arr
Now, suppose you call
free(dbl_ptr + i);
Graphically, dbl_ptr + i
points here (let's pick i = 1
)
dbl_ptr + i --------+
|
v
dbl_ptr ---> [ 0 ][ 1 ][ 2 ] ... [ k ]
| | | |
v v v v
arr arr arr arr
Therefore, free
interprets this call as if you want to deallocate something from the middle of the block of memory allocated to dbl_ptr
, rather than the block of memory pointed at by dbl_ptr[i]
. That's a problem, because you can't call free
with a pointer to the middle of a block of memory.
On the other hand, calling
free(*(dbl_ptr + i));
or
free(dbl_ptr[i]);
then you're actually saying to deallocate the memory pointed at by the i
th element of the array pointed at by dbl_ptr
, which is what you want.
You forgot dereference operator in
free( (dbl_ptr + i) );
It should be
free( *(dbl_ptr + i) );
free
deallocates the memory pointed to by the pointer argument. In the correct case, free(dbl_ptr[i])
, you look up a pointer from within the array, and then free the memory that it points at. In the incorrect case, free( (dbl_ptr + i))
, the pointer passed to it is actually a pointer to a location within the array, a pointer to the pointer to the memory you want to free.
For an easy way to view the difference, consider the i=0 case. the correct verison is free(dbl_ptr[0])
. The incorrect version is free(dbl_ptr+0)
, which is the same as free(dbl_ptr)
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.