Can someone explain what's wrong with it
When you have called free on a node, you cannot access head->next. You have to free head->next before head.
and what's the correct way to free linked list from memory?
A pretty elegant solution is recursion. Recursion is good for making code understandable, but unless you are aware of the dangers, avoid it in production code. I often use it for prototyping. Here is an example.
void free_list(struct node *head)
{
if(head) {
// Before freeing the first element, free the rest
free_list(head->next)
// Now it's only one element left to free
free(head);
}
}
It works like this. Let's say that we have a list: [e0, e1, e2, ..., en]. We want to free all elements. We do that by first freeing the list [e1, e2, ..., en] and then free the element e0. Next step works the same way. We want to free [e1, e2, ... en], so we start with calling the same algorithm on the list [e2, e3, ..., en] and when that is finished, we free e1. The base case is when we get an empty list [] in which case we do nothing.
You can also do this non-recursively. It's not as pretty, but often more efficient and it eliminates the risk of stack overflow. This is how I would have written this in production code.
void free_list(struct node *head)
{
struct node *tmp;
while(head) {
tmp = head;
head = head->next;
free(tmp);
}
}