Intro to pointers & references.

Quick Mapping:

  • * next to a type (e.g., int*): Makes it a pointer type
  • * in front of a pointer variable (e.g., *ptr): "Dereference" operator - gets the value at the address
  • & next to a type (e.g., int&): Makes it a reference type
  • & in front of a variable (e.g., &x): "Address of" operator - gets the memory address

Wtf is a pointer?

A pointer, for all intents and purposes, is just another variable. Let's start with a very simple code example:

Read out loud what is happening in each line of code here, it will help later:

  • Declare a variable with the type of an int named x with the value of 10
  • Declare a variable with the type of an int* named ptr_to_x with a value that is the address of x
  • Declare a variable with the type of an int** named ptr_to_ptr_to_x with a value that is the address of ptr_to_x
  • Declare a reference with the type of int& named reference_to_x and bind it to x

This wording is very deliberate. Let's first break down the symbols, because they're stupid. C++, being a statically typed language, has a very specific syntax for declaring variables: [type] [variable_name] = [value]

That means that, to break down each line, we understand that int, int*, int**, and int& are all types. x, ptr_to_x, ptr_to_ptr_to_x, and reference_to_x are all variable names. The stuff after the equals sign is the value assigned to each variable.

You will occasionally see some morons declare pointers and references using the wrong syntax, which usually consists of some variation of:

This is wrong. The * and & are part of the type, not the variable name. Don't do this. Please.

The reason it helps to understand pointers this way is for when we start actually doing things with pointers. For example, can we get the value of a pointer? Yes, we just need to do something called dereferencing. This literally just means we are getting the value of the thing the pointer is pointing to. Thats it.

I, personally, treat the * symbol similarly to the mathematical concept of cancelling out like terms. What happens when we remove * from a type like int*? We are left with just an int. What about * from an int**? int*. And so on and so forth.

Wtf is a reference?

A reference is basically just an alias for another variable. When you create a reference, you are not creating a new variable, you are just creating a new name for an existing variable. This means that any changes made to the reference will also affect the original variable, and vice versa.

When you declare a reference, you cannot change what it is referencing. It is permanently bound to the variable it was created with.

Cool. How do we do shit with pointers and references?

When you pass variables to functions, you have three options:

1. Pass by Value (Copy)

We can essentially provide a copy of num to change_value, where we cannot modify the argument that was passed into it, but we can modify that argument within the scope of the change_value function.

2. Pass by Reference (Alias)

We are literally passing an alias to the original variable. Remember, references are just another name for an existing variable.

3. Pass by Pointer (Address)

Why use references vs pointers in function parameters?

References (int& x):

  • Cleaner syntax - no need for & when calling or * when using
  • Cannot be null - always refers to something valid
  • Preferred when you know the parameter will always exist

Pointers (int* x):

  • Can be nullptr - useful for optional parameters
  • More explicit at call site (&num shows you're passing an address)
  • Required when you might want to reassign what you're pointing to

Rule of thumb: Use references when the parameter is required, use pointers when it's optional or you need to convey that you're working with addresses explicitly.