What is the difference between const int*, const int * const, and int * const?
Categories:
Demystifying C/C++ Pointer Constants: const int*
, const int* const
, and int* const

Understand the subtle yet critical differences between various const
pointer declarations in C and C++ to write safer and more robust code.
In C and C++, the const
keyword is a powerful tool for enforcing immutability, which helps prevent accidental modifications and improves code safety. When const
is combined with pointers, its placement becomes crucial, leading to different interpretations of what exactly is constant. This article will break down the distinctions between const int*
, const int* const
, and int* const
, illustrating how each declaration affects the pointer itself and the data it points to.
Understanding const
and Pointers
Before diving into the specific declarations, let's establish the fundamental rule for const
with pointers: const
applies to whatever is immediately to its left. If there's nothing to its left, it applies to whatever is immediately to its right. This rule is key to deciphering complex pointer declarations.
flowchart TD A[Declaration] --> B{Is 'const' to the left of '*' ?} B -- Yes --> C[Pointer to a constant value] B -- No --> D{Is 'const' to the right of '*' ?} D -- Yes --> E[Constant pointer to a mutable value] D -- No --> F[Mutable pointer to a mutable value] C --> G[Value cannot be changed via this pointer] E --> H[Pointer cannot be re-assigned] F --> I[Both value and pointer can be changed]
Decision flow for interpreting const
in pointer declarations.
const int*
: Pointer to a Constant Integer
In the declaration const int* ptr;
, const
is to the left of int
. This means the int
value that ptr
points to cannot be modified through ptr
. However, ptr
itself is not constant, meaning it can be reassigned to point to a different int
(which must also be treated as constant through ptr
). This is often referred to as a "pointer to const
".
int value1 = 10;
int value2 = 20;
const int* ptr = &value1; // ptr points to a constant int
// *ptr = 15; // ERROR: cannot modify the value through ptr
std::cout << "Value pointed to by ptr: " << *ptr << std::endl; // Output: 10
ptr = &value2; // OK: ptr itself can be reassigned
std::cout << "New value pointed to by ptr: " << *ptr << std::endl; // Output: 20
Example of const int*
behavior.
const int*
when you want to pass a pointer to a function and ensure that the function does not modify the original data. This is a common practice for function parameters.int* const
: Constant Pointer to a Mutable Integer
With int* const ptr;
, const
is to the right of the *
. This signifies that ptr
itself is constant, meaning it cannot be reassigned to point to a different memory location after its initialization. However, the int
value that ptr
points to can be modified through ptr
. This is often called a "const
pointer".
int value = 10;
int another_value = 20;
int* const ptr = &value; // ptr is a constant pointer to an int
std::cout << "Initial value pointed to by ptr: " << *ptr << std::endl; // Output: 10
*ptr = 15; // OK: the value pointed to can be modified
std::cout << "Modified value pointed to by ptr: " << *ptr << std::endl; // Output: 15
// ptr = &another_value; // ERROR: ptr itself cannot be reassigned
Example of int* const
behavior.
const int* const
: Constant Pointer to a Constant Integer
The declaration const int* const ptr;
combines both const
placements. The first const
(to the left of int
) makes the int
value pointed to constant. The second const
(to the right of *
) makes the pointer ptr
itself constant. This means neither the value pointed to by ptr
nor ptr
itself can be modified after initialization. This is the most restrictive form.
int value = 10;
int another_value = 20;
const int* const ptr = &value; // ptr is a constant pointer to a constant int
std::cout << "Value pointed to by ptr: " << *ptr << std::endl; // Output: 10
// *ptr = 15; // ERROR: cannot modify the value through ptr
// ptr = &another_value; // ERROR: ptr itself cannot be reassigned
Example of const int* const
behavior.
const int*
and int const*
are semantically identical (both mean 'pointer to a constant int'), const int*
is the more common and generally preferred style for readability. The rule 'const
applies to what's on its left' still holds, as int const
is equivalent to const int
.graph TD subgraph "Pointer Declarations" A["int* ptr"] -- "Mutable pointer, mutable value" --> B(No const) C["const int* ptr"] -- "Mutable pointer, constant value" --> D("const int") E["int* const ptr"] -- "Constant pointer, mutable value" --> F("const *ptr") G["const int* const ptr"] -- "Constant pointer, constant value" --> H("const int" AND "const *ptr") end subgraph "What can be changed?" B --> B1["ptr can change, *ptr can change"] D --> D1["ptr can change, *ptr CANNOT change"] F --> F1["ptr CANNOT change, *ptr can change"] H --> H1["ptr CANNOT change, *ptr CANNOT change"] end
Summary of pointer const
declarations and their implications.
Mastering the nuances of const
with pointers is fundamental for writing robust and maintainable C/C++ code. By explicitly declaring what parts of a pointer expression are constant, you leverage the compiler to catch potential errors at compile time, leading to more reliable software. Always consider the level of immutability required for your pointers and apply const
accordingly.