Skip to content
C Basics: Separate Read-Only Access from Fixed Pointer Bindings

C Basics: Separate Read-Only Access from Fixed Pointer Bindings

November 1, 2026

A read-only parameter and a pointer that cannot be reassigned express different promises. Make that difference visible in a small counter API.

Prepare a scratch directory

Tested on Linux amd64 with GCC 14.2.0. You need GCC with C17 support, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. No external library is required.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as const-pointer-contracts-demo.c:

#include <stdio.h>

struct counter { int value; };

static void print_counter(const struct counter *counter) {
    printf("Count: %d\n", counter->value);
}

static void increment_counter(struct counter *counter) {
    ++counter->value;
}

int main(void) {
    struct counter current = { .value = 4 };
    struct counter *const fixed_pointer = &current;
    const struct counter *read_only_view = &current;
    print_counter(read_only_view);
    increment_counter(fixed_pointer);
    print_counter(read_only_view);
    return 0;
}

Compile and run it. The program runs only if compilation succeeds:

gcc -std=c17 -Wall -Wextra -Werror -pedantic const-pointer-contracts-demo.c -o const-pointer-contracts-demo &&
./const-pointer-contracts-demo

Observed output:

Count: 4
Count: 5

Read the result

The read-only view prevents modification through that pointer. The fixed pointer cannot be reassigned, but still permits changes to the counter. Both point to the same object.

Apply it carefully

Const is not an ownership or synchronization mechanism. Another permitted alias can change a non-const object. Do not cast away const to modify an object that was defined const; that has undefined behavior. These helpers require a non-null pointer to a live counter, and incrementing INT_MAX would overflow.

See the WG14 C draft, sections 6.7.3 and 6.7.6.1 for the underlying language rules.

Clean up

Remove only the source and executable created here, return to the starting directory, and remove the empty practice directory:

rm -- const-pointer-contracts-demo.c const-pointer-contracts-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on