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

Pointers, addresses and nullptr

In the previous lesson, a reference was a second nameplate on a house's door. The nameplate is nailed on once, and it never exists without a house.

Every house on the memory street has a number: its address. An address can be written on a slip of paper. With the slip, you can walk to the house, look inside or change something in it. Later, the slip can be erased and the address of another house written on it. It can also stay blank when there is nowhere to go yet.

In C++, such a slip is called a pointer. 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
}

Let's go through the example line by line:

  1. int a = 1; and int b = 2; build two houses.
  2. int* p = &a; writes the address of the house a on the slip p.
  3. *p = 10; follows the address on the slip and puts 10 into the house a.
  4. p = &b; erases the slip and writes the address of the house b on it.
  5. *p = 20; now goes to the house b and puts 20 there.
  6. The program prints 10 20: both variables changed through one pointer.

Address and dereference

A pointer is a variable that holds the address of another variable, that is, the number of that other variable's 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, rewriting the slip, and the next *p = 20; changes b instead.

Compare this with a reference: ref = b; does not move the nameplate, it copies the value. Step through the program and watch which house ref and p lead to after each line:

LiveReference and pointer: what leads wherestep 1 of 9 · frames: 1

House a, holding 1

Step through the lines and watch ref and p

The symbols & and * mean different things in a declaration and in an expression:

  • in a declaration, int& is a reference;
  • in a declaration, int* is a pointer;
  • in an expression, &a is the address of a;
  • in an expression, *p is the variable p points to.

The null pointer

A pointer that has nothing to point to yet is given the value nullptr, and such a pointer is called a null pointer. It is a blank slip. 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';
}

The line if (found != nullptr) asks: is there an address on the slip? Only if there is does the program follow it and print the value.

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.

This is where the slip analogy ends: a person with a blank slip goes nowhere, while a program that evaluates *found on a null pointer may do anything at all.

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: the slip holds random scribbles, 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.

Key points

  • A pointer holds the address of a variable: &a takes the address, and *p is the variable at that address.
  • A pointer can be redirected: p = &b; rewrites the address, while *p = 20; changes the variable.
  • nullptr is an empty pointer; check it before dereferencing, otherwise the behavior is undefined.
  • Never dereference a pointer without an initial value; initialize it with nullptr at least.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way