Question
Understanding `const int*`, `const int * const`, and `int * const` in C and C++
Question
I often get confused about how to use const int *, const int * const, and int * const correctly in C or C++. What are the rules that define what is allowed and what is not?
I want to understand the practical do's and don'ts for:
- assigning these pointer types
- modifying the pointed-to value
- changing the pointer itself
- passing them to functions
- returning them from functions
For example, what operations are valid or invalid for these forms?
const int *p1;
const int * const p2 = nullptr;
int * const p3 = nullptr; // or another valid initialization
Short Answer
By the end of this page, you will understand how const applies to pointers in C and C++, how to read declarations from right to left, and what each form allows you to change: the value, the pointer, both, or neither. You will also see how these types behave in assignments and function parameters.
Concept
const with pointers can apply to two different things:
- the value being pointed to
- the pointer variable itself
That is why pointer declarations with const can look similar but behave differently.
Consider these three common forms:
const int *p;
int * const p;
const int * const p;
They mean:
const int *p→ pointer to a constant integerint * const p→ constant pointer to an integerconst int * const p→ constant pointer to a constant integer
The key idea
A pointer has two separate properties:
- What it points to
- Whether the pointer itself can be changed
const can lock either one.
Why this matters
This is important in real programs because developers use const to:
Mental Model
Think of a pointer as a sticky note with an address written on it.
There are two things you might want to protect:
- the paper the sticky note points to
- the address written on the sticky note
const int *p
The address on the sticky note can change, but the paper is read-only through this pointer.
- you can move the sticky note to another address
- you cannot edit the value through this pointer
int * const p
The sticky note's address is permanent, but the paper is editable.
- you cannot move the sticky note to a new address
- you can edit the value at that address
const int * const p
Both are locked.
- you cannot move the sticky note
- you cannot edit the value through this pointer
This mental model helps because most confusion comes from mixing up:
- changing where the pointer points
- changing the data at that location
Syntax and Examples
Core syntax
const int *p; // pointer to const int
int const *p; // same meaning as above
int * const p = &x; // const pointer to int
const int * const p = &x; // const pointer to const int
const int *p and int const *p mean the same thing. The position of const around the base type does not change the meaning here.
Example 1: pointer to const int
int a = 10;
int b = 20;
const int *p = &a;
p = &b; // valid: pointer can change
//*p = 30; // invalid: cannot modify value through p
Explanation
pcan point toa, then later tob- but
*pis treated as read-only through
Step by Step Execution
Consider this example:
#include <iostream>
int main() {
int a = 10;
int b = 20;
const int *p1 = &a;
int * const p2 = &a;
const int * const p3 = &a;
p1 = &b;
*p2 = 15;
std::cout << a << " " << b << '\n';
std::cout << *p1 << " " << *p2 << " " << *p3 << '\n';
}
Step by step
1. int a = 10; int b = 20;
Two integers are created.
aholds10bholds20
2. const int *p1 = &a;
p1 points to .
Real World Use Cases
1. Read-only function parameters
void displayScore(const int *score) {
std::cout << *score << '\n';
}
Use const int * when a function should inspect data without modifying it.
2. Protecting API inputs
In larger systems, functions often receive pointers to shared data. Marking data as const prevents accidental writes.
bool isPositive(const int *value) {
return *value > 0;
}
3. Fixed internal references
A const pointer can be useful when a pointer member or local alias should never be redirected after setup.
int value = 42;
int * const fixedPtr = &value;
This is less common in everyday application code than const int *, but it can still be useful when pointer reassignment would be a bug.
4. Read-only handles to configuration data
Real Codebase Usage
In real projects, const with pointers is mostly about communicating intent and preventing bugs.
Common patterns
Guarding inputs
void logUserId(const int *userId) {
if (userId == nullptr) return;
std::cout << *userId << '\n';
}
This combines:
- a pointer validity check
- read-only access
Validation before mutation
bool setIfPositive(int *value, int newValue) {
if (value == nullptr) return false;
if (newValue < 0) return false;
*value = newValue;
return true;
}
When mutation is intended, use int *, not const int *.
Common Mistakes
1. Confusing “const data” with “const pointer”
Broken code:
int a = 10;
int b = 20;
int * const p = &a;
p = &b; // error
Why it fails:
pitself is const- the pointer cannot be reassigned
2. Trying to modify data through const int *
Broken code:
int a = 10;
const int *p = &a;
*p = 99; // error
Why it fails:
- the pointed-to value is treated as read-only through
p
3. Removing const protection in assignment
Broken code:
const int x = 5;
int *p = &x; // error
Why it fails:
Comparisons
Pointer constness comparison
| Declaration | Can change *p? | Can change p? | Meaning |
|---|---|---|---|
int *p | Yes | Yes | pointer to mutable int |
const int *p | No | Yes | pointer to const int |
int * const p | Yes | No | const pointer to mutable int |
const int * const p | No | No | const pointer to const int |
const int * vs
Cheat Sheet
Quick reading rule
Start at the variable name and read outward.
const int *p→pis a pointer to const intint * const p→pis a const pointer to intconst int * const p→pis a const pointer to const int
What each form allows
int *p;
- change
p✅ - change
*p✅
const int *p;
- change
p✅ - change
*p❌
int * const p = &x;
- change
p❌ - change
*p✅
FAQ
What is the easiest way to read pointer const declarations?
Start at the variable name and move outward. This usually makes the meaning clear.
Is const int *p the same as int const *p?
Yes. Both mean “pointer to const int.”
Can I assign an int * to a const int *?
Yes. That is safe because it adds const protection.
Can I assign a const int * to an int *?
No. That would remove const protection and could allow illegal modification.
Does const int *p mean the integer can never change?
No. It only means you cannot change it through p. The original variable may still change through another non-const name or pointer.
Why must int * const p be initialized immediately?
Because the pointer itself cannot be changed later, so it needs its final address at declaration time.
Should I use pointers or references in C++ for read-only parameters?
If null is not a valid state, const int & is often clearer in C++. If null is meaningful, use .
Mini Project
Description
Build a small C++ program that demonstrates all three pointer const forms using a few integers. The project helps you practice which operations are allowed, which are rejected by the compiler, and how these types are commonly used in functions.
Goal
Create a program that reads values through const-safe pointers and modifies values only through pointers that allow mutation.
Requirements
[
"Declare one normal integer and one const integer.",
"Create examples of const int *, int * const, and const int * const.",
"Show at least one valid reassignment and one valid value modification.",
"Add two functions: one that reads an integer through a pointer and one that updates an integer through a pointer.",
"Include commented-out invalid lines to show what the compiler would reject."
]
Keep learning
Related questions
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
Definition vs Declaration in C and C++: What’s the Difference?
Learn the difference between declarations and definitions in C and C++ with simple examples, common mistakes, and practical usage.
Difference Between #include <...> and #include "..." in C and C++
Learn the difference between #include with angle brackets and quotes in C and C++, including search paths, examples, and common mistakes.