Destructor Pattern
Part of the Object Oriented Programming section of Coddy's C journey — lesson 13 of 61.
Every object created with malloc must eventually be freed. Just as we wrote a create_ function to handle allocation, we write a free_ function to handle cleanup. This is the destructor pattern.
The key insight is that freeing must happen in reverse order of allocation. If your constructor allocated internal members first and then the struct itself, your destructor must free the struct's members first, then the struct:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Safety check
free(p->name); // Free internal member first
free(p); // Then free the struct itself
}
The NULL check at the start prevents crashes if someone accidentally passes an invalid pointer. After freeing the internal name string, we free the struct itself. If we freed p first, we'd lose access to p->name and cause a memory leak.
Using the destructor is straightforward:
Person *alice = create_person("Alice", 30);
// ... use alice ...
free_person(alice); // Clean up when done
This pattern ensures all memory is properly released. Without it, every object you create would leak memory until your program runs out.
Challenge
EasyLet's build a Movie module that demonstrates the complete object lifecycle—both creation and destruction. You'll practice writing a destructor function that properly cleans up all allocated memory in the correct order.
You'll create three files:
movie.h: Declare aMoviestruct with two members:char *title(a dynamically allocated string) andint year. Declare both a constructorcreate_moviethat takes a title and year, and a destructorfree_moviethat takes a Movie pointer. Use include guards with the symbolMOVIE_H.movie.c: Implement both functions. Your constructor should allocate memory for the struct and its title string (don't forget the null terminator). Your destructor must free memory in the reverse order of allocation—first the internaltitlestring, then the struct itself. Include a NULL check at the start of your destructor for safety.main.c: Create a movie, display its information, then properly clean up the memory.
You will receive two inputs: the movie title (a string) and the release year (an integer).
In your main file, use create_movie to create a new movie, print its information, then call free_movie to release all memory. After freeing, print a confirmation message.
Print the output in this format:
Movie: {title} ({year})
Memory freedFor example, with inputs Inception and 2010, the output would be:
Movie: Inception (2010)
Memory freedRemember: the key to a proper destructor is freeing in reverse order. Whatever your constructor allocates first gets freed last, and whatever it allocates last gets freed first.
Cheat sheet
Every object created with malloc must be freed using a destructor function. Destructors follow the pattern of freeing memory in reverse order of allocation.
Basic destructor structure:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Safety check
free(p->name); // Free internal members first
free(p); // Then free the struct itself
}
Key principles:
- Always include a
NULLcheck at the start to prevent crashes - Free internal members before freeing the struct itself
- If you free the struct first, you lose access to its members and cause memory leaks
Usage example:
Person *alice = create_person("Alice", 30);
// ... use alice ...
free_person(alice); // Clean up when done
Try it yourself
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
int main() {
char title[100];
int year;
// Read input
scanf("%[^\n]", title);
scanf("%d", &year);
// TODO: Create a movie using create_movie
// TODO: Print the movie information in format:
// Movie: {title} ({year})
// TODO: Free the movie using free_movie
// TODO: Print "Memory freed"
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy