Reputation:
some weeks ago I learn about proper way how pointers should be allocated and dealocated inside function so given in example linkedList:
typedef struct _node {
void *data;
struct _node *next;
} Node;
typedef struct _linkedList {
Node *head;
Node *tail;
Node *current;
} LinkedList;
In My opinion right way to destroy queue is by using function that get pointer to pointer to node which I want to delete:
void destroy (Node ** node)
Or in more real world example pointer to pointer and pointer to list to delete.
void destroy (LinkedList * list, Node ** node)
but now I am reading book "Understanding C pointers" and I encounter to problem because In chapter 6 pointers to structures there is followed example of function destroyList:
void delete(LinkedList *list, Node *node) {
if (node == list->head) {
if (list->head->next == NULL) {
list->head = list->tail = NULL;
} else {
list->head = list->head->next;
}
} else {
Node *tmp = list->head;
while (tmp != NULL && tmp->next != node) {
tmp = tmp->next;
}
if (tmp != NULL) {
tmp->next = node->next;
}
}
free(node); //free on pointer copy value not pointer
}
So in this example author run free on pointer that is passed by value, so in my opinion this shouldn't work. But I looked into errata and there is no notes about this example.
In this case I understand that List is function argument to use correct instance of list, but is should be rather that:
free(list->head) ; //It should work?
And then also free memory for allocated List.
Am I right? Because reading this example I have a feeling that I have a problem with good understanding of this topic.
Also I went to Linux Man Page and I saw free prototype:
void free(void *ptr); // http://linux.die.net/man/3/free
So why everybody told to pass pointer to pointer when You want to free memory but in standard library same free function take as parameter not pointer to pointer but pointer, how it work correctly?
Upvotes: 2
Views: 1699
Reputation: 495
I'll do my best to try and clarify here. When you are freeing memory, you are supposed to free the actual memory that was allocated. When you call a function like malloc, you are expected to give the size of data you want to malloc. In your case, 'node' would have been malloced like 'malloc(sizeof(node))'.
Again, when you call free, you are intending to free the entire block of memory that was allocated. If you were to free a pointer to the memory, you haven't actually freed the memory, but instead freed the thing pointing to it. Now you have leaked memory because nothing can access the malloced node anymore.
So in the code you cited, he isn't freeing the value of node, he is freeing the memory allocated to node. When he calls free(node)
he is passing to free a pointer to the node (because a node pointer was passed to the function), and free then releases that memory for node.
Upvotes: 0
Reputation: 9904
as you state correctly, free( void *p )
frees the memory p
points to but as the address is passed by value it will remain unchanged for the caller. Thus you could run into problems like this:
int *p = malloc( sizeof *p );
*p = 1;
free( p );
...
if( p )
*p = 2; // Undefined Behaviour!!! although p is free()'d it's still != NULL
So you will often find
free( p );
p = NULL;
Nevertheless in my opinion it's ok to write a free()
like function where you pass a pointer by value as long as the function's description states clearly that the pointer must not be used afterwards (no matter wht type of pointer that may be). But of course you're free to define the function with double pointers and set everything you have free()'d to NULL
inside, like in this very simple example:
void myfree( void **pp )
{
free( *p );
*p = NULL;
}
...
int *p = malloc( sizeof *p );
...
myfree( &p );
// now p == NULL
Upvotes: 2
Reputation: 206717
You don't need to use:
void destroy (LinkedList * list, Node ** node)
Using
void destroy (LinkedList * list, Node * node)
is sufficient.
You can use:
void destroy(int* pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(ip);
to free
memory allocated by malloc
and related functions.
Using
void destroy(int** pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
is wrong.
You can use:
void destroy(int** pointer)
{
free(*pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
but that uses additional &
and *
that are not necessary.
Upvotes: 0