Tchiggy
Tchiggy

Reputation: 131

How to free a structure of linked structures

I have this structure

struct room {
    char* name;               
    char* description;         
    struct room *north;       
    struct room *south;       
    struct room *east;       
    struct room *west;          
    struct container* items;   
};

So I should write a function struct room* destroy_room(struct room* room); that frees all the memory used for room creation and return NULL as new room reference. So i thought that simply doing

free(room);
return NULL;

would resolve the problem, but it didn't.

Upvotes: 1

Views: 66

Answers (2)

Ackdari
Ackdari

Reputation: 3498

I would go with a solution using two seperate functions. The first is destroy_room it will free one single room and remove the references to itself from its neighbors:

struct room* destroy_room(struct room* room) {
    if (!room) return;
    if (room->name) free(room->name);
    if (room->description) free(room->description);
    if (room->items) free_items(room->items);

    // remove the references to this room from its neighbors
    if (room->north) room->north->south = NULL;
    if (room->south) room->south->north = NULL;
    if (room->east) room->east->west = NULL;
    if (room->west) room->west->east = NULL;

    free(room);

    return NULL;
}

This function can then be used to write a recursive function ro free all rooms that are reachable from the given room. The function saves the references to the neighbors, then frees the given room and then recursivly frees the neighbors:

struct room* destroy_rooms_rec(struct room* room)
{
    if (!room) return;

    // save references to neighbors
    struct room* north = room->north;
    struct room* south = room->south;
    struct room* east = room->east;
    struct room* west = room->west;

    // free this room
    destroy_room(room);

    // free all neighbors
    destroy_rooms_rec(north);
    destroy_rooms_rec(south);
    destroy_rooms_rec(east);
    destroy_rooms_rec(west);

    return NULL;
}

Note: I assumed that a function like free_items(struct container* items) exists that can free whatever items is.

EDIT: I noticed that this code has a implicit assumtions. It assumes that the graph build by the rooms has a tree structure. If the graph is a fully conected grid or has any cycles this code won't work and leeds to memory problems like double free and invalid access.

But I'm working on a solution for any graph

Upvotes: 4

Paul Ogilvie
Paul Ogilvie

Reputation: 25276

As Jabberwocky says, "nothing is freed automatically", so your function could look like:

void destroy_room(struct room* room)
{
    if (!room) return;
    if (room->name) free(room->name);
    if (room->description) free(room->description);
    if (room!=room->north) destroy_room(room->north);
    if (room!=room->south) destroy_room(room->south);
    if (room!=room->east) destroy_room(room->east);
    if (room!=room->west) destroy_room(room->west);
    free_items(room->items);
    free(room);
}

Upvotes: 2

Related Questions