Home > Blockchain >  Should you free pointers that reference already allocated data?
Should you free pointers that reference already allocated data?

Time:09-17

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 to free, nothing in between.

  • Each malloc must be followed by a corresponding free.

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.

  • Related