Van Teo Le
Van Teo Le

Reputation: 156

free() function only frees the first element of a struct?

I'm working with two structs:

typedef struct ListNode{
    void* value;
    struct ListNode *next;
    struct ListNode *prev;
} Node;

typedef struct List{
    Node *first;
    Node *last;
    int count;
} List;

Then i declare these variable and allocate memory

List *x = calloc(1,sizeof(List));
Node *x1 = malloc(sizeof(Node));
Node *x2 = malloc(sizeof(Node));
x->first = x1;
x->last =x2;
x->count = 2;
free(x);

So i'm pretty sure that if i free x, the x->count, x->first, x->last will also disappear as well. However, in this case ,i use gdb to check, and surprisingly only the first element of x is removed (e.g: if in the struct List i put count on the top, then it will remove only count and leave the rest intact). Why is this happening, and how do i free() the whole struct?

Upvotes: 1

Views: 563

Answers (3)

Marco Bonelli
Marco Bonelli

Reputation: 69276

Your assumption is wrong. If you do free(x) you're only freeing the block of memory holding the contents of x, but since this block contains some pointers to other blocks, you will need to free() those first. This is because free() does not care about the content of the memory you're freeing, it doesn't do anything fancy. If you see some value modified after using free(), it's just because free() uses that memory to store some useful internal values to keep track of memory usage, and it's only a coincidence if that happens to "clear" a pointer in your struct.

The correct way to free() your struct is the following:

free(x->first);
free(x->last);
// DO NOT free(x->count), it's an integer, not a previously allocated pointer!
free(x);

Here's a visual representation (pardon my awful handwriting):

enter image description here

Upvotes: 8

Gerhardh
Gerhardh

Reputation: 12404

You seem to have invalid expectation what happens when you call free. You cannot verify the result of free in GDB.

Freeing a memory location does not mean that the memory in that place is modified in any way. It may still look the same as before. The OS or C runtime library may set it to all zero, but that's not mandatory. Also the pointer x will not change.

Freeing an address only means that you tell the OS it can take it back and give it to someone else. After calling free you are no longer allowed to access the memory. That's all what happens after free.

Therefore last and count will not "disappear".

That said, you also have a memory leak as others have already pointed. Freeing x does not free any other memory accessible via x->first or x->last.

Upvotes: 1

Sheena Artrip
Sheena Artrip

Reputation: 2010

It's important to understand the memory layout of the struct... i'm no expert so this will be really really simplified:

List x = [pointer-to-x1][pointer-to-x2][int] (plus padding)

So when you run calloc(1, sizeof(List)), you aren't creating the x1 and x2 structs in the same region of memory as the List, because they are just pointers to some other place in memory. you are just creating small reference to them which hasn't even been setup yet. That's why you have to malloc x1 and x2 separately.

so when you free(x), you also aren't freeing x1 or x2 either. free doesn't know how and doesn't know that you ran malloc for x1 and x2. if it tried to free it, it could end up freeing memory too early or freeing memory on the stack. it's only going to look at the region of memory i mapped out above.

Was writing this and saw another answer just come in. Marco has a good answer!

Upvotes: 1

Related Questions