Recently, I am trying to understand how to efficiently free the memory space allocated by the malloc function in the C language. And I have got some ideas about this, but I am not sure whether they are right or wrong. So, I come here to ask for some suggestions.
For example:
Fisrt, I define a Structure, i.e. demo. And use demo to define a structure pointer, i.e. demo *demo_pointer = NULL. Then, using malloc function to allocate a piece of memory space to this pointer, i.e. demo_pointer = (demo *)malloc(sizeof(demo)). Normally, to free this memory space, I need fisrt to do "free(demo_pointer)", next to do "demo_pointer = NULL".
But, if I use "free((char *)demo_pointer)", can I free the allocated memory?
If this can work, I think I could define a function to do this:
void Free(void **p)
{
free(*p);
*p = NULL;
return;
}
Thus, to free the allocated memory space, I only need to do "Free(&demo_pointer)". Does it work?
Thanks for your kind suggestions!
CodePudding user response:
If the goal is to ensure that the pointer variable is set to NULL after the call to free()
, a simpler solution might be to simply define a macro.
#define myFree( p ) do { free(p); p = NULL; } while(0)
/* code */
char *foo = malloc( 80 );
/* omitting test for success */
/* code */
myFree( foo ); // 'foo' will now be set to NULL
CodePudding user response:
Yes, your Free()
function will work just fine. The return
statement doesn't do anything so you can leave it out.
As there is little to no cost try your experiment(s). It's a quick way to learn.
Consider a different name, though. If you ever need to talk to someone about your code you may quickly tire of having to say "initial uppercase free" as opposed to "lowercase free". It matters as the two functions are not interchangeable (different prototypes).
CodePudding user response:
Yes is the answer to the question in title, and to the question whether passing the address of demo_pointer
to your Free
function would free the memory or not.
But, if I use "free((char *)demo_pointer)"
Not fatal but free
's signature accepts void *
.
I would recommend you to read more about memory allocation and de-allocation functions. Especially the functions prototype as what they accept as arguments/parameters and what do they return.
Normally, to free this memory space, I need fisrt to do "free(demo_pointer)", next to do "demo_pointer = NULL".
demo_pointer = NULL
is not mandatory. The demo_pointer
is already freed by free
. This is just a cosmetic way of indicating that the memory pointed by demo_pointer
was freed.
This helps in cases where the demo_pointer
is getting accessed later in the program, there demo_pointer
can be checked:
if (!demo_pointer) {
/* do something */
} else {
/* do something else */
}
If your concern is efficiently freeing the memory, then free
just does that. Just make sure that the previously allocated memory/address is not mangled up.
And if you want all the freed up addresses to point to NULL
value by default then the Free
function in your question is just fine. You could get rid of the return
.
CodePudding user response:
The question asks:
But, if I use free((char *)demo_pointer)
, can I free the allocated memory?
The short answer is: No
Explanation:
When it comes to malloc
and free
the important thing is the value of the void pointer returned by malloc
. When you later call free
you need to pass a void pointer with the exact same value.
Now the C standard specifies that if a void pointer is converted to any other pointer type and back to void pointer, the resulting value will be equal to the value of the original void pointer.
So code like
T* var = malloc(...); // Implicit conversion: void pointer to T pointer
free(var); // Implicit conversion: T pointer to void pointer
is fine. First a void pointer is (implicit) converted to a T pointer and then the T pointer is (implicit) converted back to a void pointer which is used as argument for free
. That is exactly the conversion steps that the standard guarantee to give identical values.
However the code
demo* demo_pointer = (demo *)malloc(sizeof(demo));
free((char *)demo_pointer);
is doing these pointer conversions:
void pointer --> demo pointer // explict cast (btw: not needed in C)
demo pointer --> char pointer // explicit cast
char pointer --> void pointer // implicit conversion
The C standard does not guarantee that this sequence of pointer conversion will result in the final void pointer being equal to the initial void pointer. Consequently, the final void pointer can't be used when calling free
It will probably work on any real world system but the standard has no such guarantee.
Regarding your function:
The prototype is
void Free(void **p)
so the function expects a pointer to pointer to void
When calling it like
Free(&demo_pointer)
the argument is a pointer to pointer to demo
These are incompatible types so the function is incorrect.
Compiling this code
struct demo *demo_pointer = malloc(sizeof *demo_pointer);
Free(&demo_pointer);
with "gcc -Wall -Wextra" also gives warning like:
main.cpp: In function 'main':
main.cpp:40:10: warning: passing argument 1 of 'Free' from incompatible pointer type [-Wincompatible-pointer-types]
40 | Free(&d);
| ^~
| |
| struct demo **
main.cpp:16:18: note: expected 'void **' but argument is of type 'struct demo **'
16 | void Free(void **p)
| ~~~~~~~^
that tells you that it's the wrong thing to do.