2

If I have several linked structures in C like:

struct structA {
    int a;
    int b;
    struct structA *next;
}

struct structB {
    char a;
    int b;
    struct structB *next;
}

and I dynamically allocate memory like this:

struct structA *mystructA = (struct structA*) malloc(sizeof(struct structA));
mystructA->next = (struct structA*) malloc(sizeof(struct structA));

struct structB *mystructB = (struct structB*) malloc(sizeof(struct structB));
mystructB->next = (struct structB*) malloc(sizeof(struct structB));

do I always have to free it for each struct type like this:

struct structA *p, *pNext;
for (p = mystructA; p != NULL; p = pNext) {
    pNext = p->next;
    free(p);
}

struct structB *p, *pNext;
for (p = mystructB; p != NULL; p = pNext) {
    pNext = p->next;
    free(p);
}

or is there any generic solution? I assume there is no other solution because the free() procedure must know how many bytes have to be freed. But maybe I'm wrong and someone can teach me better.

1
  • you must deallocate the structures one by one. Commented Jul 19, 2013 at 12:58

3 Answers 3

5

The standard way is to make the "list part" the first element of the structure, and let each derived struct share this same prefix. Since the first element is guaranteed to be placed at offset zero this wil work. Example snippet:

#include <stdlib.h>
#include <string.h>

struct list {
    struct list *next;
    };
struct structA {
    struct list list;
    int a;
    int b;
    };

struct structB {
    struct list list;
    char a;
    int b;
    };

void *create_any(size_t size) 
{
    struct list *this;
    this = malloc (size);
    if (!this) return this;
    memset(this, 0, size);
    this->next = NULL;
    return this;
}


void free_all_any(struct list **lp) {
    struct list *tmp;
    while ((tmp = *lp)) { *lp = tmp->next; free(tmp); }
}
#define CREATE_A() create_any(sizeof(struct structA))
#define CREATE_B() create_any(sizeof(struct structB))
#define FREE_A(pp) free_any((struct list **) pp)
#define FREE_B(pp) free_any((struct list **) pp)

int main(void)
{
struct structA *ap;
struct structB *bp;

ap = CREATE_A ();
bp = CREATE_B ();

// some code here ...

FREE_A( &ap);
FREE_B( &bp);

return 0;
}

This is more or less the method used in the linux kernel, but a lot more preprocessor magic is used there. (and there is no malloc there, obviously)

Sign up to request clarification or add additional context in comments.

3 Comments

Why did you define macros and why are you calling memset()?
Mainly as an illustration. The macros hide the casts and the sizeof. The memset is just to set the complete object to zeros. (NULL is not necessarily represented as all-zeros, so that has to be done separately anyway)
Okay, everything clear now thank you! Very good generic solution but maybe little confusing on the first look (because of the macros and memset() :-)
2

Since free() accepts pointers to void * and structA and structB both have the same size, you can pass both pointer types.

This is, however, not optimal in terms of elegance. You should think about the following questions:

Why do you have two different structs with the same members?

Why do you not have a generic list item type, such as the following:

struct list_node {
    void *data;
    struct list_node *next;
}

1 Comment

They haven't same members and also not same size, have a closer look at my provided code. structA has 2 ints; structB has 1 char, 1 int
2

Actually, this is a very interesting question. The part is true that you have to free() each struct type individually, as they have been malloc()-ed individually, and each memory block has been allocated specifically for that type.Also, on some systems char and int have different storage sizes, but you can try a solution like Phillip provided. For more info, read about the doom memory engine. On a side note, please don't cast malloc() in C. The funny thing is that once the program is terminated, the operating system will reclaim the memory, so if you only deallocate the structures near the end of the program, when you don't need them anymore, it may not be necessary to free() them

2 Comments

"the OS will reclaim the memory" just be careful with this statement - it's not required that the OS does this, but it's just very unlikely that it won't.
Agreed, but the mainstream OS' windows and linux do, so I said :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.