Search code examples
cstructlinked-listfreels

Free linked list containing structures containing structures


This is for school.

I'm working on an implementation of the Unix 'ls' command. For this I'm using linked lists each time I'm reading a directory (so only one time if the -R option is not set). For this I have to use the linked lists functions and nodes (or elements, I'm not sure what's the correct name.) that we had to code on a previous project. Those nodes looks like this:

typedef struct s_list
{
    void          *content;
    size_t         content_size;
    struct s_list *next;
}t_list;

In my ls program, I use these to store, for each file in the directory I'm listing, it's name and it's stats, obtained with the stat() function. So the 'content' pointer of my t_list is this structure:

typedef struct s_entry
{
    char       *filename;
    struct stat filestat;
}t_entry;

Everything works fine, the only problem I got is that Valgrind tell me there's a leak comming from the malloc() used to allocate those t_entry structures. So I guess I'm freeing them up wrong.. here's how I do it:

void    free_list(t_list *entries)
{
    t_list *n_node;

    if (!entries)
        return ;
    while (entries)
    {
        n_node = entries->next;
        free(entries->content);
        free(entries);
        entries = n_node;
    }
}

I'm guessing it is not enough to just free the *content pointer, but I tried other ways and it wont works. If I try to free like

free(entries->content->filename);

for example, it doesn't works and the fact that the content is a void pointer seems to be a problem in some ways that I tried to resolve the problem, but that's the way we had to code those linked list functions.

If someone could give me an hint on how to free these lists correctly, It would be awesome as I'm really stuck on this. Thanks in advance. Sorry if my english or explanation isn't clear enough.

ps: Just in case, the whole project (far from finished) can be found here: https://github.com/Zestx/ft_ls


Solution

  • If you have your list of ls entries for each file within a directory where content is a pointer to an allocated t_entry containing the filename and stat information, e.g.

    typedef struct s_list {
        void          *content;
        size_t         content_size;
        struct s_list *next;
    } t_list;
    

    and

    typedef struct s_entry {
        char       *filename;
        struct stat filestat;
    } t_entry;
    

    A freelist (t_list *head) function would need to iterate over each node, and:

    1. free the filename allocated within each t_entry;
    2. free the allocated t_entry; and finally
    3. free the t_list node itself.

    You could do something similar to the following:

    void freelist (t_list *head)
    {
        t_list *node = head;        /* temporary node to iterate list  */
                                    /* (you could use head, but don't) */
        while (*node) {
            t_list *victim = node;  /* pointer to current node to free */
            t_entry *entry = node->content;     /* pointer to content */
    
            free (entry->filename)  /* free content->filename */
            free (entry);           /* free t_entry struct itself */
    
            node = node->next;      /* advance before freeing victim */
    
            free (victim);          /* free current t_list node (victim) */
        }
    }
    

    Note above, instead of using node, you could simply use head to iterate since freelist receives a copy that would not alter the list address anyway -- and since there will be no list left when you are done, but it is a far better habit to use a temporary node to iterate the list (in any function) so you do not confuse the circumstances when you are handling the actual list address (e.g. the parameter was t_list **) or a copy of the pointer (the parameter was t_list *).

    Look things over and let me know if you have further questions.