I'm aware that pointers that point to malloc
-ed data need to be freed where appropriate.
For example:
Item* items = (Item*)malloc(sizeof(Item) * 1);
^ when I'm done with this, I'd have to free it. Makes sense.
However, consider the following struct:
typedef struct Items {
Vector* fruits;
} Items;
where Vector
is:
typedef struct Vector {
void** data;
int size;
} Vector;
Assume I've allocated memory for the Items
struct and the Vector
member contains, say, 3 items (of another struct Boxes
).
If I were to have a Boxes
pointer variable that references the second member of the Vector in the Items
struct, would that need to be freed after usage?
// Does `box1` need to be explicitly freed?
Boxes* box1 = items->fruits[1]; // `items` is of type `Items`
I understand that that variable box1
wasn't explicitly heap-allocated. Do only heap-allocated pointers need to be freed?
CodePudding user response:
man malloc/free
The malloc() function allocates size bytes and returns a pointer to the allocated memory. ...
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), ...
That being said, the address returned by
malloc
has to be passed later tofree
, nothing in between.Each
malloc
must be followed by a correspondingfree
.
CodePudding user response:
If you execute this:
Boxes* box1 = items->fruits[1];
Then box1
and items->fruits[1]
are the same pointer; they refer to the same object, which has one address in memory.
If you call free(items->fruits[1])
then items->fruits[1]
becomes an invalid pointer. Because box1
is exactly that same pointer, it also becomes invalid.
If you know that that the memory management for items->fruits[1]
is taken care of elsewhere, and you just want a shorter name for it some block of code, it can be often safe to create an alias for the object like box1
.
You have to be absolutely sure that you don't continue to use box1
at some point in the program where box1
is still in the lexical scope (so accessing the variable per se is hunky dory), but some code has been executed which has already destroyed items->fruits[1]
, to that box1
has invisibly, stealthily become invalid.
If you have some code that has a box1
alias, and it's possible that some function which it calls will destroy items->fruits[1]
and replace that pointer with a new one. In that case you can pick up the new value:
Boxes *box1 = items->fruits[1];
maybe_replaces_items(items); // items->fruits[1] potentially overwritten
box1 = items->fruits[1]; // pick up latest fruits[1]
This kind of thing is a source of bugs.
You know that computing proverb that "there are only two hard things in Computer Science: cache invalidation and naming things"? Well, this is cache invalidation: box1
is a cached copy of some pointer that has possibly gone invalid, and must be refreshed.