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
intnamedxwith the value of10 - Declare a variable with the type of an
int*namedptr_to_xwith a value that is theaddress of x - Declare a variable with the type of an
int**namedptr_to_ptr_to_xwith a value that is theaddress of ptr_to_x - Declare a reference with the type of
int&namedreference_to_xandbind 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 (
&numshows 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.