Skip to content
FollowtheDamnCode

Const Correctness

Promising not to change what you only read.

6 minute read

Big idea

const is a promise: "I won't change this." Put it on pointer parameters a function only reads, and the compiler holds the function to that promise.

Recap: const on a plain variable

You met const in Constants and Keywords:

const int LIMIT = 10;
LIMIT = 11;           // ✗ error: read-only

That's simple. Pointers make it more interesting, because there are two things that could be read-only: the data the pointer leads to, and the pointer itself.

Reading the declarations

Read pointer declarations right to left:

DeclarationRead it as*p = 5;p = &other;
int *pp is a pointer to int✓✓
const int *pp is a pointer to an int that's const✗✓
int *const pp is a const pointer to int✓✗
const int *const pa const pointer to a const int✗✗

The second line is the one you'll write all the time. (int const *p means exactly the same as const int *p.)

const parameters: "I only look"

When a function takes an array or string just to read it, mark it const:

sum promises not to touch the array
#include <stdio.h>

int sum(const int *a, int n) {
    int total = 0;
    for (int i = 0; i < n; i++) {
        total += a[i];
    }
    return total;
}

int count_char(const char *s, char c) {
    int n = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == c) n++;
    }
    return n;
}

int main(void) {
    int marks[] = {70, 85, 90};
    printf("%d\n", sum(marks, 3));
    printf("%d\n", count_char("banana", 'a'));
    return 0;
}
output
245
3

Run and edit it in the app.

Two wins:

  1. Readers know at a glance that sum won't change marks — no need to read its body.
  2. The compiler checks. If sum tries a[0] = 0;, it's a compile error, not a bug found next week.

The standard library does this everywhere: size_t strlen(const char *s); — strlen promises not to change your string. char *strcpy(char *dest, const char *src); — it writes dest, only reads src.

The compiler catches it

Fix the bug: this doesn't compile
#include <stdio.h>

void shout(const char *s) {
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] >= 'a' && s[i] <= 'z') {
            s[i] = s[i] - 'a' + 'A';
        }
    }
}

int main(void) {
    char word[] = "hello";
    shout(word);
    printf("%s\n", word);
    return 0;
}
output
HELLO

Run and edit it in the app.

shout does change the string, so it must not promise otherwise — remove const from its parameter. const should tell the truth.

Watch it

String literals are read-only

A string literal like "hello" lives in read-only memory. Point at it with const char *:

const char *name = "Asha";   // ✓ honest
char *name2 = "Asha";        // compiles, but name2[0] = 'a' may crash
char name3[] = "Asha";       // ✓ an array COPY you're allowed to change

Given const char *p = buffer; which line is a compile error?

Common mistake

Casting const away to silence the compiler: ((char *) s)[0] = 'X';. It compiles — and if s points to a literal, the program may crash. If you need to change it, don't take it as const.

Think of it like

Lending someone a book with "reference only — no notes" stamped inside. They can read every page, flip back and forth (move the pointer), but not write in it. And if they try, the librarian (compiler) stops them at the desk.

Key terms

  • const — Marks something read-only.
  • Pointer to const (const int *p) — Can't change the data through p; p itself can move.
  • Const pointer (int *const p) — p can't move; the data can change.
  • Const correctness — Marking everything that shouldn't change as const, so the compiler enforces it.

Check yourself

Given const int *p; what can't you do?

Why does strlen take a const char *?

How should you point at the string literal "hello"?