You are on page 1of 2

# A variable is just a way to access a location in memory.

## The type of a variable

tells us
how much data is associated with that variable.

Integers are pretty small variables, and are usually around 4 bytes long.
When we create a new integer: int x = 2;
The program finds an unused location in memory, say address 0x400, then it
says "okay this is where I will put the value of x". So it attaches a name to that
memory location. After this, it takes those 4 bytes at address 0x400 and sets their
value to 2 (probably 00 00 00 02).

## A pointer is just a variable in the same way an integer is just a variable.

If we want to create a pointer, we use the type int* to declare a variable.
The * is a decorator, and does not actively do anything to the value of the
variable. All the * does in "int*" is tell the compiler "this is a pointer to int".
Do not worry right now about the other use of the * operator.

## When we create a new pointer: int* p = 0;

The program finds an unused location in memory, say address 0x500, then it says
"okay this is where I will put the value of p". It attaches the name p to that
memory location. Then it takes the value at address 0x500 and sets it to 0,
since we wrote x = 0.

Pointers were created so that we could easily take the address of a variable and
store that address somewhere for use later. C++ allows us to do this by using the
address-of operator, &. In the context of a unary operator, & works as follows:
p = &x;
This statement is executed as follows. First the program realizes that we want the
address of x. Then it finds the memory location in which x is stored. Remember this

was 0x400. Once we get the address of x, the program searches for where p is
stored.
Then the value of p (as a variable!!) is changed to 0x400. If you really want, you
could
interpret the value of p to be 1024 (since 0x400 is 1024 in decimal). Now our
memory looks
as follows:
memory location - value
x: 0x400 - 2
p: 0x500 - 0x400

We generally want to "follow" the pointer and take the value that it "points" to.
Currently,
p "points to" x since the value of p is the address of x. If for example, we don't
the variable x and only have the pointer p, we want to find what is the value of x.
We have to
do this using p. The next important use of the * symbol is instead as an operator.
Recall that
before * was used as a "decorator" to denote a certain type, namely a pointer. Now,
* can be used
as an operator to find the value of the variable that p points to. In this case,
the * is used as follows:
*p (notice no type is there!)
We will see what this actually does. The program sees "*p" and takes the value of p
(this is the address of x).
In this case, the value of p is 0x400. Then the program goes to memory location
0x400 (&x) and reads the value stored
there. The value is 2, which is the value of x. The unary operator * is known as
"dereferencing".

Lastly, we will talk about references. References are very similar to pointers
except that references are not allowed
to be "empty" (they can't be nullptr). Moreover, references MUST be initialized. We
will see what this means in a moment.
A reference, internally, is stored as a pointer, and we declare a reference by
replacing the * decorator with the & decorator.
That is, a reference r is created as follows: int& r = x;
Again, int& is the type of variable r. However, in this case, the compiler lets us
write r = x as a sort of shortcut.
r = x does not literally mean take the value of x and put it into r, especially
since r is a "pointer". In this case,
r = x essentially means take &x and put it into the value of r (recall r is a type
of pointer).

References are sort of tricky since we treat them as not pointers, and just as
regular variables. However, we have to
remember that inside the program and in memory, they are just pointers. If we look
at the example above,
we can "translate" references into pointers.
int& r = x works the same as int* p = &x.
But remember the important part about what a reference actually is, a pointer.
Another aspect of references is that they
allow us to treat the reference as the variable that it points to. So in the
example above, int& r = x,
we can use r as if it were x and assign it integer values:
r = 3 does the same thing as x = 3 since r "refers" to x.

References are preferred over pointers since if we have a reference, then we know
it actually exists. It can't be empty.
Further, they allow us to write more generic code since we can treat the reference
as the variable itself.

If we have two referenes, then assignment works slightly differently than usual.
Let's set up an example:
int x = 2;
int y = 3;
int& r1 = x;
int& r2 = y;
So then we can use r1 as x itself and check to see what is the value of r1 (x):
r1 == 2 (is true)
A subtle point about references is that assignment works differently between two
references:
r1 = r2 does not mean take the value of x and set it to the value of y.
This statement means make r1 refer to what r2 refers to. So after executing r1 = r2
we can expect:
r1 == 3 (is true)
r2 == 3 (is true)