Ch5.1: Memory & Addresses

Overview

Before we talk about pointers, we need a simple mental model of memory. In this chapter, “memory” just means a long sequence of bytes, and each byte has a number called its address.

You can think of memory as a street with houses:


Address:   1000   1001   1002   1003   1004   1005   1006   1007
Memory:   [ ?? ] [ ?? ] [ ?? ] [ ?? ] [ ?? ] [ ?? ] [ ?? ] [ ?? ]
           ↑
          a byte at address 1000

Every object in your program (integers, doubles, containers, etc.) lives somewhere along this “street” and occupies one or more bytes.

Objects and their memory

When you create a variable, the compiler reserves space for it in memory. The variable’s value is stored in this space, and its address is the number of the first byte it uses.

Example: a simple integer


int x{42};

Imagine x uses 4 bytes starting at address 2000:


Address:   1996   1997   1998   1999   2000   2001   2002   2003   2004   2005
Memory:    ....   ....   ....   ....  [ 42 ][ 42 ][ 42 ][ 42 ]   ....   ....
                                        ↑
                                      x starts here

You do not need the real numbers; this is just a model. The important part is: every object occupies some bytes, and those bytes have an address.

Containers also live in memory

In Chapter 4, you learned about ::fast_io::string, ::fast_io::vector, and ::fast_io::array. These are also objects, so they also occupy space in memory.

Example: ::fast_io::array


::fast_io::array a{10, 20, 30, 40};

You can imagine it like this:


Address:   3000   3004   3008   3012
Memory:   [ 10 ] [ 20 ] [ 30 ] [ 40 ]
           ↑
         a[0] starts here

The elements are stored one after another in memory. The actual addresses are decided by the compiler and system, but they form a continuous block.

string and vector: object plus elements

::fast_io::string and ::fast_io::vector are a bit more complex. They are objects that manage a separate block of memory where the elements live.

Example: ::fast_io::string


::fast_io::string s{"Hello"};

You can picture it like this:


           (object s)                     (characters managed by s)
Address:   4000   4008   4016            5000   5001   5002   5003   5004
Memory:   [ ... s header ... ]          [ 'H' ][ 'e' ][ 'l' ][ 'l' ][ 'o' ]
           ↑                              ↑
         s lives here              first character lives here

The details of the “header” do not matter yet. The key idea is: the string object has its own address, and the characters it manages have their own addresses as well.

Example: ::fast_io::vector


::fast_io::vector v{1, 2, 3};

           (object v)                     (elements managed by v)
Address:   6000   6008   6016            7000   7004   7008
Memory:   [ ... v header ... ]          [  1  ][  2  ][  3  ]
           ↑                              ↑
         v lives here             v[0] lives here

Again, the important point is that both the container object and the elements it manages occupy space somewhere in memory.

Why we care about addresses

In the rest of Chapter 5, we will work with pointers. A pointer is just a variable that stores an address, such as the address of an int, or the address of the first element in a ::fast_io::vector or ::fast_io::array.

This simple model of memory and addresses will help you understand:

In the next chapter (Ch5.2), we will formally introduce pointers and see how they store and work with these addresses.

Key takeaways