Pointers, addresses and nullptr
A reference cannot be re-bound to another variable, and it is never empty. A pointer can do both. In this program, one pointer p changes two variables in turn:
#include <iostream>
int main() {
int a = 1;
int b = 2;
int* p = &a;
*p = 10;
p = &b;
*p = 20;
std::cout << a << ' ' << b << '\n'; // 10 20
}Address and dereference
A pointer is a variable that holds the address of another variable, that is, the number of its location in memory. The type int* reads as "pointer to int". The expression &a gives the address of a, so int* p = &a; stores the address of a in p.
The expression *p denotes the variable whose address p holds. This access is called dereferencing: *p = 10; changes a. The line p = &b; changes the pointer itself, and the next *p = 20; changes b instead.
The symbols & and * mean different things in a declaration and in an expression. In a declaration, int& is a reference and int* is a pointer. In an expression, &a takes an address, and *p dereferences a pointer.
The null pointer
A pointer that has nothing to point to yet is given the value nullptr; it is called a null pointer. This is how, for example, a search function reports that it found nothing. Such a pointer is checked before it is dereferenced:
int* found = nullptr;
if (found != nullptr) {
std::cout << *found << '\n';
}There is no variable behind nullptr, so there is nothing to read through it. Dereferencing a null pointer is undefined behavior. The compiler builds such a program, but the standard does not say what it will do—not even a crash is guaranteed.
Numbers in a row
A function can receive several int numbers that lie in memory one after another. It takes two parameters: a pointer data to the first number and the count n. Then data + i points to the number with index i, counting from zero. The notation data[i] is short for *(data + i):
int sum(int* data, int n) {
int total = 0;
for (int i = 0; i < n; ++i) {
total = total + data[i];
}
return total;
}The indices run from 0 to n - 1. Reading data[n] goes past the last number and is undefined behavior too.
Common mistake
A pointer is declared without an initial value and dereferenced right away:
int main() {
int* p;
*p = 5; // ✗
}warning: variable 'p' is uninitialized when used here [-Wuninitialized]The compiler only warns. The value of p is not set, and writing to such an address is undefined behavior. If there is no address yet, initialize the pointer with nullptr: then the check p != nullptr shows that it is empty.