Pointer Dereferencing in C++
What is Dereferencing?
Dereferencing means accessing the value stored at the memory address a pointer holds. It is done using the dereference operator (*).
Key points:
- Translates a memory address into the actual value it points to
- Can be used for both reading and writing values (unless the pointee type is const)
- Dereferencing an invalid pointer (null, dangling, or out-of-bounds) leads to undefined behavior
Dereferencing Syntax
The `*` symbol appears in declarations to form pointer types and in expressions to dereference. In expressions, `*ptr` yields the referred-to object.
int value = 42;
int* ptr = &value;
// Reading through pointer
int readValue = *ptr; // 42
// Writing through pointer
*ptr = 100; // value becomes 100
// Parentheses help disambiguate complex expressions
(*ptr) += 5; // increments the pointee
int* q = ptr + 1; // pointer arithmetic on the pointer itself
Practical Dereferencing Examples
Dereferencing is often used to modify values indirectly, to pass values by pointer to functions, and to walk arrays.
#include <iostream>
using namespace std;
void square(int* numPtr) {
*numPtr = (*numPtr) * (*numPtr);
}
int main() {
// Basic dereferencing
int x = 5;
int* xPtr = &x;
cout << "Original value: " << *xPtr << '\n';
// Modifying through dereference
*xPtr += 3;
cout << "Modified value: " << x << '\n';
// Function parameter dereferencing
square(&x);
cout << "Squared value: " << x << '\n';
// Pointer arithmetic and dereferencing
int arr[3] = {10, 20, 30};
int* arrPtr = arr; // &arr[0]
cout << "First element: " << *arrPtr << '\n';
cout << "Second element: " << *(arrPtr + 1) << '\n';
}
Original value: 5 Modified value: 8 Squared value: 64 First element: 10 Second element: 20
Member Access via Pointers
Use `->` to access members through a pointer to an object. `p->m` is shorthand for `(*p).m`.
#include <iostream>
#include <string>
using namespace std;
struct User { string name; int score; };
int main() {
User u{"Ada", 90};
User* pu = &u;
cout << pu->name << '\n'; // (*pu).name
pu->score += 10; // (*pu).score += 10
cout << u.score << '\n';
}
Ada 100
Operator Precedence Gotchas
`*`, prefix/postfix `++`, and `+` have different precedences. Parentheses make intent explicit.
int a[3]{1,2,3};
int* p = a; // points to a[0]
int x1 = *p++; // dereference then increment pointer (yields 1, p -> a[1])
int x2 = (*p)++; // increment value at p (a[1] becomes 3), yields old value 2
int x3 = *++p; // increment pointer first (p -> a[2]), then dereference (yields 3)
int x4 = ++*p; // increment value at p (a[2] becomes 4), then yield 4
Const and void* Considerations
You cannot modify a value through a pointer-to-const.
`void*` is a generic, untyped pointer and cannot be dereferenced directly; cast it to the correct type first.
const int ci = 10;
const int* pc = &ci;
// *pc = 5; // ❌ error: pointee is const
int x = 7;
void* vp = &x; // generic pointer
// *vp; // ❌ invalid: cannot dereference void*
int* ip = static_cast<int*>(vp);
*ip = 9; // OK: x becomes 9
9
Common Dereferencing Pitfalls
- Dereferencing null pointers (`nullptr`).
- Dereferencing dangling pointers (pointing to destroyed or out-of-scope objects).
- Dereferencing uninitialized pointers (indeterminate value).
- Performing pointer arithmetic that leaves the array’s bounds and then dereferencing.
- Forgetting parentheses in expressions like `(*p)++` vs `*p++` (they do different things).