Learn addresses, pointers and references through examples; swap, const references and nullptr.
Pointers are the "scary" topic of C++, but they actually rest on a simple idea: every variable has an address in memory, and we can create variables that hold that address. This lesson lays the groundwork for both pointers and their safer siblings, references.
Address and pointer
&x: gives the address of the variable x.int* p: declares a "pointer to int".*p: reaches the value at the place p points to (dereference).nullptr: a safe empty value meaning "I point nowhere".
Reference
A reference is an alias for an existing variable. After you write int& r = x;, r and x are the same box. A reference must be bound to a variable when it is declared and cannot be rebound to another variable later; it cannot be nullptr. That is why it is safer than a pointer.
#include <iostream>
#include <vector>
void swapValues(int& a, int& b) { // by reference: the originals change
int temp = a;
a = b;
b = temp;
}
double average(const std::vector<double>& v) { // read without copying or changing
double t = 0.0;
for (double x : v) t += x;
return t / v.size();
}
void reset(double* p) { // by pointer: a nullptr check is a must
if (p != nullptr) *p = 0.0;
}
int main() {
int x = 10;
int* p = &x;
*p = 20; // write to where p points -> x = 20
int& r = x;
r++; // r is an alias for x -> x = 21
std::cout << "x = " << x << '\n';
int a = 3, b = 7;
swapValues(a, b);
std::cout << "a=" << a << " b=" << b << '\n';
std::vector<double> v = {2.0, 4.0, 6.0};
std::cout << "average = " << average(v) << '\n';
double load = 5.5;
reset(&load);
std::cout << "load = " << load << '\n';
int arr[3] = {10, 20, 30};
int* q = arr; // points to the first element of the array
std::cout << *(q + 1) << ' ' << q[2] << '\n';
return 0;
}
x = 21
a=7 b=3
average = 4
load = 0
20 30
What happened in the code?
Passing by reference
In the previous lesson we said that parameters are copied. In the swapValues(int& a, int& b) function, however, the & means the original variables are changed; that is why a and b really did swap places. If you are passing a large object that you won't change, use a const reference: there is no copying cost, and the function cannot change it. average(const std::vector<double>& v) is an example of this.
Passing by pointer
In the call reset(&load) we pass the address. Since a pointer can be empty, the function first does a nullptr check. In new code, prefer a reference where possible, and a pointer for cases where "there may be no value".
The relationship between arrays and pointers
An array's name can decay into the address of its first element. q + 1 moves to the next int (4 bytes ahead); *(q + 1) gives its value and is the same as q[1]. This is called pointer arithmetic.
In embedded systems, hardware registers are accessed through pointers. For example, a port register sits at a fixed address in memory and is pointed to like this: volatile std::uint32_t* const port = reinterpret_cast<volatile std::uint32_t*>(0x40020014);. volatile tells the compiler "this value can be changed by the hardware, don't optimize it away". This is the foundation of writing to hardware with C++.
Dangerous situations: (1) using a pointer that was never given an initial value, (2) dereferencing nullptr, (3) keeping the address of a local variable that no longer exists (a dangling pointer), (4) going past the end of an array. All of these are undefined behavior: the program sometimes works, sometimes crashes, and sometimes silently produces a wrong result.
Pointer or reference?
| Property | Reference | Pointer |
|---|---|---|
| Can it be empty? | No | Yes (nullptr) |
| Can it be rebound to something else later? | No | Yes |
| Usage | r (directly) | with *p |
Try it yourself
- Write a
swapfunction that swaps twodoublevalues. - Write a function that multiplies every element of a vector by 2: its parameter should be
std::vector<double>&. - Print an
intarray using pointer arithmetic (*(q + i)). - Declare
int* p = nullptr;and write anifthat checks it before dereferencing.
// Mini quiz
Click an option; you will see right away, with the reason, whether it is correct or not.
Mark it when you finish: your progress is saved and you earn +20 XP.
Tip: ← → keys let you move between lessons.