rgamber
rgamber

Reputation: 5849

Using free on a C struct

I have a simple Linked List node as follows

typedef struct node {
    void *data;
    struct ListElement *next;           
} node;

Also I have a node create and delete function as follows:

void createNode(void *data){
    node *n = malloc(sizeof(node));
    //assign data to data and initialize pointer to NULL
}

void deleteNode(List *list, Node *node){
    //Take care of the next pointer
    free(node);
}

When I free the node, do I have to delete the members of the struct (data and next pointer) as well? Since I am not using malloc specifically for the members, but only for the entire struct? If so then how do I do it? Will all the members of the node be placed on the heap, and the stack will not be used at all?

Upvotes: 0

Views: 225

Answers (3)

user4815162342
user4815162342

Reputation: 154876

data is not a variable, it's a member of struct node. If you dynamically allocate struct node with a call to malloc(), you get a chunk of memory large enough to hold all the members of the struct. This obviously includes the storage for the data pointer, but not for the contents the pointer points to. Consequently, the storage for struct members must not be freed separately, it is enough to free the struct.

However, since data is itself a pointer, there is no telling where the memory it points to and whether this memory needs to be freed until we see how it is initialized.

Upvotes: 1

user529758
user529758

Reputation:

The ultimate rule: you free() exactly the same number of times you malloc() (or calloc(), or...)

So:

I. If the data points to something allocated by these functions, then yes, you need to do so.

II. node->next is to be freed of course (assuming you are freeing the entire list), so you need to free it anyway, but only after you have taken care of the next element.

An iterative solution:

void free_list(Node *list)
{
    while (list != NULL) {
        Node *p = list->next;
        // maybe:
        // free(list->data);
        free(list);
        list = p;
    }
}

A recursive solution:

void free_list(Node *list)
{
    if (list->next != NULL) {
        free_list(list->next);
    }

    // free(list->data);
    free(list);
}

Upvotes: 2

Daniel Fischer
Daniel Fischer

Reputation: 183858

Usually, you will need to also free the data member, and you have to do that before freeing node,

free(node->data);
free(node);

but you don't need to free node->next, since either you want to keep the remainder of the list, or you free the entire list, and then freeing the next is done in the next iteration of the loop.

You must not free node->data if that doesn't point to allocated (with malloc or the like) memory, but that is a rare situation.

Upvotes: 1

Related Questions