Alexis Draussin


C: the const modifier

2024-08-23


The C const modifier with nested pointers

The const is a way to tell the C compiler to consider the target variable read-only. On function declaration, the data arguments are de facto const, but we could specify the pointers' behavior as seen below.

The key is to apply the const modifier from right to left

/* August 2024, C99.
 * Const modifier to data pointers.
 * Note: the patterns are just layers of Pascal's binomial triangle,
 *       easy to repete for a growing number of stars.
 */

/*
 * Zero star.
 */
/* Zero const modifier -> 1 choose 0. */
static int data;
/* One const modifier -> 1 choose 1. */
static int const constData;

/*
 * One star
 */
/* Zero const modifier -> 2 choose 0. */
static int *ptr_data;
/* One const modifier -> 2 choose 1. */
static int const *ptr_constData;
static int *const constPtr_data;
/* Two const modifiers -> 2 choose 2. */
static int const *const constPtr_constData;

/*
 * Two stars
 */
/* Zero const modifier -> 3 choose 0. */
static int **ptr_ptr_data;
/* One const modifier -> 3 choose 1. */
static int const **ptr_ptr_constData;
static int *const *ptr_constPtr_Data;
static int **const constPtr_ptr_Data;
/* Two const modifiers -> 3 choose 2. */
static int const *const *ptr_constPtr_constData;
static int const **const constPtr_ptr_constData;
static int *const *const constPtr_constPtr_data;
/* Three const modifiers -> 3 choose 3. */
static int const *const *const constPtr_constPtr_constData;

/*
 * Three stars
 */
/* Zero const modifier -> 4 choose 0. */
static int ***ptr_ptr_ptr_data;
/* One const modifier -> 4 choose 1. */
static int const ***ptr_ptr_ptr_constData;
static int *const **ptr_ptr_constPtr_data;
static int **const *ptr_constPtr_ptr_data;
static int ***const constPtr_ptr_ptr_data;
/* Two const modifiers -> 4 choose 2. */
static int const *const **ptr_ptr_constPtr_constData;
static int const **const *ptr_constPtr_ptr_constData;
static int const ***const constPtr_ptr_ptr_constData;
static int *const *const *ptr_constPtr_constPtr_data;
static int *const **const constPtr_ptr_constPtr_data;
static int **const *const constPtr_constPtr_ptr_data;
/* Three const modifiers -> 4 choose 3. */
static int const *const *const *ptr_constPtr_constPtr_constData;
static int const *const **const constPtr_ptr_constPtr_constData;
static int const **const *const constPtr_constPtr_ptr_constData;
static int *const *const *const constPtr_constPtr_constPtr_data;
/* Four const modifiers -> 4 choose 4. */
static int const *const *const *const constPtr_constPtr_constPtr_constData;

We can then do the same for following stars depth, but as we can see the number of possibilities is combinatorial: for \(n\) stars-pointers we will have \(2^{n + 1}\) const flavours possible.

You can verify the above assumptions by:

#include <stddef.h>

void foo(int *ptr_data, int const *ptr_constData, int *const constPtr_data, int const *const constPtr_constData)
{
        *ptr_data = 0; // OK: modifies the pointed data
        ptr_data = NULL; // OK: modifies the pointer

        *ptr_constData = 0; // Error!
        ptr_constData = NULL; // OK: modifies the pointer

        *constPtr_data = 0; // OK: modifies the pointed data
        constPtr_data = NULL; // Error!

        *constPtr_constData = 0; // Error!
        constPtr_constData = NULL; // Error!
}