Singleton Pattern
Part of the Object Oriented Programming section of Coddy's C journey — lesson 54 of 61.
Sometimes you need exactly one instance of an object throughout your entire program — a configuration manager, a logging system, or a database connection. The Singleton pattern ensures that only one instance exists and provides a global access point to it.
In C, we implement this using a static variable inside a source file. Remember that static at file scope means the variable is private to that file and persists for the program's lifetime. Combined with a getter function, this creates our Singleton:
// config.c
#include "config.h"
#include <stdlib.h>
struct Config {
int max_connections;
int timeout;
};
static Config* instance = NULL;
Config* get_config(void) {
if (instance == NULL) {
instance = malloc(sizeof(Config));
instance->max_connections = 100;
instance->timeout = 30;
}
return instance;
}The magic happens in get_config(). The first call creates and initializes the instance. Every subsequent call returns the same pointer.
The static keyword ensures instance retains its value between function calls and remains hidden from other files.
From the header, users only see the getter function — they cannot access or modify the static variable directly. No matter how many times or from where you call get_config(), you always get the same object.
Challenge
EasyLet's build a Settings module that manages application-wide configuration using the Singleton pattern. No matter how many times your code requests the settings, it should always receive the exact same instance.
You'll organize your code across three files:
settings.h: Declare an opaqueSettingstype using a forward declaration (the struct body stays hidden). Declare aget_settingsfunction that returns a pointer to the singleton instance, plus getter and setter functions for two configuration values:volume(an integer) andbrightness(an integer). Include guards are essential here.settings.c: This is where the magic happens. Define the actualSettingsstruct withvolumeandbrightnessfields. Create astaticpointer variable to hold the single instance (initialized toNULL). Implementget_settingsso that the first call allocates and initializes the instance with default values (volume: 50, brightness: 75), while subsequent calls simply return the existing instance. Implement the getters and setters to access and modify the hidden fields.main.c: Demonstrate that the Singleton works correctly. Read two integers representing new volume and brightness values. Callget_settingstwice, storing the results in two different pointer variables. Use the first pointer to update the volume and brightness with the input values. Then use the second pointer to retrieve and print both values. If the Singleton is working, changes made through one pointer will be visible through the other.
Your program will receive two inputs:
- The new volume value
- The new brightness value
Print the volume and brightness on separate lines after modifying them through one pointer and reading through another.
Example output when the inputs are 80 and 100:
80
100Example output when the inputs are 25 and 60:
25
60Example output when the inputs are 0 and 50:
0
50The key insight is that both pointers point to the same object in memory — that's the essence of the Singleton pattern. The static variable inside your source file ensures only one instance ever exists, and it persists for the entire program's lifetime.
Cheat sheet
The Singleton pattern ensures that only one instance of an object exists throughout the entire program and provides a global access point to it.
In C, implement a Singleton using a static variable inside a source file combined with a getter function:
// config.c
#include "config.h"
#include <stdlib.h>
struct Config {
int max_connections;
int timeout;
};
static Config* instance = NULL;
Config* get_config(void) {
if (instance == NULL) {
instance = malloc(sizeof(Config));
instance->max_connections = 100;
instance->timeout = 30;
}
return instance;
}Key points:
- The
statickeyword at file scope makes the variable private to that file and persistent for the program's lifetime - The getter function checks if the instance is
NULLon first call, creates and initializes it, then returns it - Subsequent calls return the same pointer
- Users only see the getter function through the header — they cannot access or modify the static variable directly
- No matter how many times or from where you call the getter, you always get the same object
Try it yourself
#include <stdio.h>
#include "settings.h"
int main() {
int new_volume, new_brightness;
scanf("%d", &new_volume);
scanf("%d", &new_brightness);
// TODO: Call get_settings twice and store in two different pointer variables
// TODO: Use the first pointer to update volume and brightness with input values
// TODO: Use the second pointer to retrieve and print volume and brightness
// (This demonstrates that both pointers point to the same singleton instance)
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