Menu
Coddy logo textTech

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 icon

Challenge

Easy

Let'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 opaque Settings type using a forward declaration (the struct body stays hidden). Declare a get_settings function that returns a pointer to the singleton instance, plus getter and setter functions for two configuration values: volume (an integer) and brightness (an integer). Include guards are essential here.
  • settings.c: This is where the magic happens. Define the actual Settings struct with volume and brightness fields. Create a static pointer variable to hold the single instance (initialized to NULL). Implement get_settings so 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. Call get_settings twice, 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:

  1. The new volume value
  2. 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
100

Example output when the inputs are 25 and 60:

25
60

Example output when the inputs are 0 and 50:

0
50

The 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 static keyword 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 NULL on 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;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming