This article is meant for programmers who have some familiarity with writing and compiling simple code in C/C++. It assumes the reader knows basic data types like int and double and how to define and use variables and functions. This article will then expose the reader to a basic memory model, explain how the use of variables interacts with this memory, and introduce addresses and pointers.

On a modern platform, memory is presented to a program as byte-addressable blocks. Each byte in this block has an associated integer address; this address is used to identify to the computer which piece of memory to operate on. For this demonstration, let us assume our program has a block of memory with the first byte at address 0x10. Each variable we declare in our program must occupy some of this memory. The compiler we're using will use this memory to store variables we define. Different data types can be different sizes: an int type is commonly 4 bytes, while a double is usually 8.

int cakes = 10; // 4 bytes starting at 0x10.
double level = 11.5; // 8 bytes starting at 0x14.

To manipulate these variables, we simply assign a value to their symbols, since their addresses have been managed for us by the compiler:

cakes = 15; // the compiler knows where "cakes" is stored in memory

Addresses and Pointers

Now, we would like to modify the values of these variables from an external function. This function does not know about the variables we have declared here because it exists at a different scope. We need two things to accomplish this. First, we need a way to obtain the address of our cakes variable in memory. For this, we can use the address of operator, &. Second, we need a variable into which this address can be stored; this is the pointer type, specified by a data type and a *. The size of the pointer type on this platform is 8 bytes, allowing for a 64-bit address space.

int *ptr_to_cakes; // 8 bytes starting at 0x18.
ptr_to_cakes = &cakes; // the value of ptr_to_cakes is 0x10

To modify the value through the pointer, we dereference, using the * operator.

*ptr_to_cakes = 25; // there are now 25 cakes

Lets go ahead and modify this value in our function.

/* Function takes a pointer to an int, allowing it to modify the value */
void get_num_cakes(int* how_many_cakes) {
    *how_many_cakes = 17;
}

get_num_cakes(ptr_to_cakes); // sets cakes to 17.
get_num_cakes(&cakes); // can pass address directly.

The next extension to this happens when we would like someone to modify the value of ptr_to_cakes, so that its value contains a different address. The principle of course is the same: to modify a variable, one must know its address.

void set_cake_ptr(int** cake_ptr_ptr, int* new_cake_ptr) {
    *cake_ptr_ptr = new_cake_ptr;
}

int another_cake = 1; // 4 bytes at 0x1C
set_cake_ptr(&ptr_to_cakes, &another_cake); // ptr_to_cakes is now 0x1C
Visit Part 2 to understand pointers and arrays!