Skip to content
Theory · References and Pointers · lesson 2 of 8

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:

C++
#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:

C++
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):

C++
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:

C++
int main() {
    int* p;
    *p = 5;  // ✗
}
TEXT
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.