Ch5.2: Pointer Basics

Overview

A pointer is a variable that stores an address. It does not store a value like 42; it stores the location of an object in memory.

In this chapter, we introduce only the syntax of pointers:

We use only simple types such as ::std::size_t, int, char, and double. Containers will be covered later in Ch5.12.

1. Include <memory> for ::std::addressof

To obtain the address of an object, we use ::std::addressof. It is defined in the <memory> header.


#include <memory>   // for ::std::addressof

We use ::std::addressof instead of & because:

2. What is a pointer?

Every object in memory has an address. A pointer is a variable that stores such an address.


Address:   2000   2001   2002   2003
Memory:   [  7  ][  7  ][  7  ][  7  ]
            ↑
           x lives here

#include <memory>

::std::size_t x{7};
::std::size_t *p = ::std::addressof(x);   // p stores the address of x

3. Declaring pointers

A pointer type is written as T*, meaning “pointer to T”. In this tutorial, we prefer writing the * next to the variable name:


int *ip;
char *cp;
::std::size_t *sp;
double *dp;

Always initialize pointers

You must always initialize a pointer. An uninitialized pointer contains an unpredictable address, and using it is undefined behavior.


int *p = nullptr;              // safe: p points to nothing
char *q = nullptr;             // safe
::std::size_t *r = nullptr;    // safe

Later, when you have a real object, you can assign its address:


int value{42};
int *p = ::std::addressof(value);

A common beginner trap

This declaration is misleading:


int* p, q;   // q is NOT a pointer

Only p is a pointer. q is a plain int.

Writing the * next to the variable name makes the meaning clearer:


int *p, q;   // p is a pointer, q is an int

Even better, declare one pointer per line and always initialize it:


int *p = nullptr;
int *q = nullptr;

4. Pointer to pointer

A pointer can also store the address of another pointer. This is called a pointer-to-pointer.


int value{42};
int *p = ::std::addressof(value);   // p points to value
int **pp = ::std::addressof(p);     // pp points to p

value:
Address:   3000
Memory:   [ 42 ]

p:
Address:   4000
Memory:   [ 3000 ]   ← p stores address of value

pp:
Address:   5000
Memory:   [ 4000 ]   ← pp stores address of p

You can keep adding more * levels, but pointer-to-pointer is the most common.

5. nullptr

A pointer can also store “no address”. This is written as nullptr.


int *p = nullptr;   // p does not point to anything
int **pp = nullptr; // pp also does not point to anything

We will explore nullptr more in Ch5.4.

6. Printing pointers

A pointer stores an address, and sometimes you want to print that address to see where something lives in memory. In fast_io, the recommended way to print a pointer is to use the pointervw manipulator.

To use it, include the namespace:


using namespace ::fast_io::iomnp;

Then you can print a pointer like this:


#include <memory>
#include <fast_io.h>
using namespace ::fast_io::iomnp;

int value{42};
int *p = ::std::addressof(value);

println(pointervw(p));

This prints the address stored inside p in a readable, consistent format. The exact number depends on your system, but conceptually it looks like:


0x0000000000007d30

You can print any pointer this way, including pointer-to-pointer:


int **pp = ::std::addressof(p);
println(pointervw(pp));

Printing pointers is useful for understanding how memory is laid out and how pointers relate to each other.

Key takeaways