Search code examples
cstructfreestrdup

Is there a way to free all members of a struct which have been strdup'd all at once?


For example I have the following struct:

 struct Student{
     char *studentName;
     int studentAge;
     struct Student *next;
  };

I have many instances of the Student struct (for many different students) in a linked list. Each variable within the struct is strdup'd (except for the int's).

Now after doing all the processing that my program is set out to do, I want to add a function that will free ALL struct instances and also free all the variables that have been strdup'd. Is there a way I can do this in a quick manner?


Solution

  • It's unclear what you mean by "in a quick manner" or "all at once". My best guess is that you are looking for a standard library function that in one call will automagically free all the memory you want freed. There is indeed such a function: exit(). Unfortunately, its other effects are unlikely to be compatible with your purposes.

    Otherwise, there is no standard library function that achieves what you're after. Standard library functions in general and the memory management functions in particular don't understand the contents of your structs. They do not, for instance, have the ability to recognize that some of your struct members are pointers that might need their referrents deallocated, too. Even if they could detect that, it would not be safe for them to perform that deallocation, because they cannot know whether there are any other pointers to the same dynamic memory.

    The usual approach to this sort of problem revolves around writing your own function to free instances of your struct, along with all members thereof that need deallocation. For example:

    void free_student(struct Student *s) {
        free(s->studentName);
        free(s);
    }
    

    That has the distinct advantage that if you ever modify the struct then you can change the deallocation function as appropriate, instead of changing ad-hoc deallocation code in multiple places.

    You might make such a function do double duty to also free the next student in the list, recursively, but it is cleaner to have a separate function for that purpose (that uses the first):

    void free_student_list(struct Student *head) {
        while (head) {
            struct Student *next = head->next;
    
            free_student(head);
            head = next;
        }
    }
    

    Such an approach is predicated on certainty about which members can and should be freed, so you must take care that the members you intend to free indeed do point to allocated memory, that they do not alias each other, and that there are no presumed-valid pointers to the same memory elsewhere in the program.