C++ Pointers
A pointer in C++ is a variable that stores the memory address of another variable. Instead of holding a value like 42 directly, a pointer holds the location where a value can be found.
Pointers are useful when code needs to work with existing data indirectly. They are also closely related to arrays, strings, dynamic memory, and many lower-level C++ features.
Pointer Syntax
Use * in a declaration to create a pointer type. Use & before a variable name to get that variable’s address.
#include <iostream>
int main(void) {
int score = 90;
int* scorePtr = &score;
std::cout << "score: " << score << std::endl;
std::cout << "value through pointer: " << *scorePtr << std::endl;
return 0;
}
Output:
score: 90
value through pointer: 90
The variable scorePtr stores the address of score. The expression *scorePtr means “go to the address stored in scorePtr and use the value there.” This is called dereferencing the pointer.
The Address Operator and Dereference Operator
The same symbols can mean different things depending on where they appear. In a declaration, int* p means p is a pointer to an int. In an expression, *p means the int value that the pointer points to.
&namegets the address ofname.int* ptrdeclares a pointer that can point to anint.*ptraccesses the value stored at the pointed-to address.
Changing a Value Through a Pointer
Dereferencing a pointer can read a value, and it can also change that value. When you assign to *pointer, you assign to the original variable being pointed at.
#include <iostream>
int main(void) {
int health = 100;
int* healthPtr = &health;
*healthPtr = 75;
std::cout << "health: " << health << std::endl;
health = health + 10;
std::cout << "through pointer: " << *healthPtr << std::endl;
return 0;
}
Output:
health: 75
through pointer: 85
The assignment *healthPtr = 75; changes health because healthPtr points to health. Later, changing health is visible through *healthPtr because both expressions refer to the same stored value.
Null Pointers
A pointer should either point to a valid object or hold the special value nullptr. A null pointer points to nothing. This is useful when a pointer does not have a target yet.
#include <iostream>
int main(void) {
int* numberPtr = nullptr;
if (numberPtr == nullptr) {
std::cout << "No value yet" << std::endl;
}
int number = 12;
numberPtr = &number;
if (numberPtr != nullptr) {
std::cout << *numberPtr << std::endl;
}
return 0;
}
Output:
No value yet
12
Do not dereference a null pointer. Writing *numberPtr is only safe after the pointer stores the address of a valid int.
Pointers and Arrays
In many expressions, the name of an array can be used like a pointer to its first element. This makes pointer arithmetic possible: adding 1 to an int* moves to the next int, not just the next byte.
#include <iostream>
int main(void) {
int values[] = {10, 20, 30};
int* current = values;
std::cout << *current << std::endl;
current = current + 1;
std::cout << *current << std::endl;
current = current + 1;
std::cout << *current << std::endl;
return 0;
}
Output:
10
20
30
At first, current points to values[0]. After current = current + 1;, it points to values[1]. Moving outside the array would make the pointer unsafe to dereference.
Common Mistakes
- Dereferencing an uninitialized pointer.
- Dereferencing
nullptr. - Forgetting that
&variablegives an address, while*pointeruses the value at an address. - Moving a pointer past the end of an array and then using
*on it. - Assuming pointers and references are identical. References act like aliases, while pointers store addresses and can be changed to point somewhere else.
Takeaway: a C++ pointer stores an address, and dereferencing that pointer lets you read or change the value at that address.
