const & Pointers
const and pointers combine in more than one way, and where you place the keyword changes what is actually being protected: the data being pointed to, the pointer variable itself, or both. Mixing these up is one of the most common sources of confusion in C, even for experienced programmers — but there is a reliable trick for reading any declaration correctly.
The four combinations
Declaration | Meaning |
|---|---|
| Plain pointer. Both the pointed-to |
| Pointer to const data. The |
| Const pointer to non-const data. |
| Const pointer to const data. Neither the pointed-to |
Reading declarations right-to-left
For const int *p, start at p: "p is a pointer to an int that is const." The const binds to int, so it is the data that cannot be changed through p.
const int *p; int value = 10; p = &value; // OK: reassigning p is allowed // *p = 20; // ERROR: cannot modify the int through p
For int *const p, start at p again: "p is a const pointer to an int." This time const binds to p itself, so the pointer cannot be reassigned, but the int it points to is fully mutable through it.
int a = 10, b = 20; int *const p = &a; *p = 99; // OK: modifying the int through p is allowed // p = &b; // ERROR: cannot reassign a const pointer
const on function parameters documents intent
Marking a pointer parameter as const is a common, valuable habit: it tells both the compiler and every future reader that the function promises not to modify the data through that pointer. The compiler will then flag any accidental write inside the function as an error, catching bugs before they ship.
#include <stdio.h>
// print_array only reads through arr — it should never write to it.
// const documents (and enforces) that promise.
void print_array(const int *arr, int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
// arr[i] = 0; // ERROR: would violate the const promise
}
printf("\n");
}
int main(void) {
int nums[3] = {1, 2, 3};
print_array(nums, 3);
return 0;
}constbefore the*protects the pointed-to data;constafter the*protects the pointer variable itself.Read the declaration starting at the variable name and moving outward to figure out which one you have.
A
constpointer parameter is a promise, checked by the compiler, that a function will not modify the data it points to.You can always pass a non-const pointer where a
constpointer parameter is expected — the reverse is not allowed.