# Chapter 8 - Notes

## Pointers

A **pointer** is a variable that stores a memory address, i.e. it **points to** a location in memory.&#x20;

### Declaring a Pointer&#x20;

A pointer is normally declared to be pointing to a **specific value type**, i.e. a pointer that points to an integer (integer pointer), or a pointer that points to a double (double pointer).&#x20;

```cpp
<pointed_type>* variable_name;
```

As with variables, uninitialised pointer variables contain junk values which will be interpreted as a memory address (very bad). These should be pointed to `NULL`.

### Getting the Address of a Variable&#x20;

Variables are simply **names** that are **fixed to a specific location** in memory. The memory address of a variable cannot change.&#x20;

The memory address of a variable named `variable` can be obtained with `&variable`.&#x20;

The `&` symbol, when used before a variable name, is called the **address-of** **operator**.

This may be slightly confusing as it shares the same symbol as a reference parameter or reference variable, which uses the symbol **after** the variable name.

### Storing an Address

```cpp
int number = 10;
int* pointer_to_number = &number;
```

Pointers can always be re-assigned to another memory address:

```cpp
int a = 10;
int* pointer_to_number = &a;

int b = 20;
pointer_to_number = &b;  // This is OK!
```

{% hint style="info" %}
What happens when we try to store the memory address of a `float` into an `int*` pointer?
{% endhint %}

### Accessing Data Through an Address&#x20;

The data stored in a memory address `address` can be obtained with `*address`.

The `*` symbol, when used before a pointer or memory address, is called the **dereference operator**.

```cpp
int number = 10;
int* pointer_to_number = &number;

std::cout << "The address of number is 0x:" << pointer_to_number << std::endl;
std::cout << "The value at that address is: " << *pointer_to_number << std::end;  // This will print 10 
```

When the dereference operator is used, the program uses the address stored in the pointer, fetches 4 bytes (the size of an `int`) from the memory location, and interprets it as an integer.&#x20;

{% hint style="info" %}
The dereference operator can also be used to change the value stored at the memory address.&#x20;
{% endhint %}

### Size of a Pointer&#x20;

Since all pointers only store memory addresses, the size of a pointer does not depend on the type of value it points to.&#x20;

The size of a pointer is the length of an address and is therefore constant for a given system. But may be different for different compilers, operating systems, and hardware.&#x20;

## Dynamic Memory Allocation&#x20;

Dynamic memory allocation allows a program to allocate additional or release excess memory when required.

### Allocating Memory Dynamically&#x20;

The `new` operator is used to allocate new memory blocks. This returns a pointer to the requested memory if successful or else throws an exception.&#x20;

When using `new`, the type of the data being allocated must be specified.

```cpp
int* dynamically_allocated_int = new int;
```

The `new` operator can also be used to dynamically allocate arrays.

```cpp
int* dynamically_allocated_array = new int[20];  // Array of 20 integers
```

### Releasing Memory Dynamically&#x20;

All memory that is dynamically allocated needs to be explicitly released using the `delete` operator.

```cpp
int dynamically_allocated_int = new int;
*dynamically_allocated_int = 5;
// Do some things with `dynamically_allocated_int`
delete dynamically_allocated_int; 
```

This also applies to dynamically allocated arrays, using `delete[]` instead.&#x20;

```cpp
int* dynamically_allocated_array = new int[20];  // Array of 20 integers
// Do some things with `dynamically_allocated_array`
delete[] dynamically_allocated_array; 
```

{% hint style="warning" %}
Memory that is dynamically allocated but not released will remain reserved for the application. This reduces the memory later available for the application and other applications, and may make the application or system slower.

This is known as a **memory leak** and should always be avoided.
{% endhint %}

## Pointer Manipulation

### Incrementing and Decrementing Pointers

An increment (`++`) or decrement (`--`) operation on a pointer is interpreted by the compiler as the need to point to the **next value of the same type** in memory.

### Using \`const\` with Pointers&#x20;

The `const` keyword, when applied to variables, ensures that the value of the variable is fixed for the life of the variable.

When used with pointers, **where** the `const` keyword appears determines the behaviour of the pointer:

#### Constant pointer

This is with the syntax `<pointed_type>* const <variable_name>`

* The memory address stored by the pointer **cannot change**
* The data stored at that address **can be changed**&#x20;

```cpp
int number_1 = 30;

int* const number_ptr = &number_1; 
*number_ptr = 20;  // OK! 

int number_2 = 20;
number_ptr = &number_2;  // NOT OK!
```

#### Pointer to a constant value&#x20;

This is with the syntax `const <pointed_type>* <variable_name>`

* The memory address stored by the pointer **can be changed**
* The data stored at that address **cannot be changed**&#x20;

```cpp
int number_1 = 30;

int* const number_ptr = &number_1; 
*number_ptr = 20;  // NOT OK!

int number_2 = 20;
number_ptr = &number_2;  // OK!
```

#### Constant pointer to constant value&#x20;

This is with the combined syntax `const <pointed_type>* const <variable_name>`

* The memory address stored by the pointer **cannot be changed**
* The data stored at that address **cannot be changed**

```cpp
int number_1 = 30;

int* const number_ptr = &number_1; 
*number_ptr = 20;  // NOT OK!

int number_2 = 20;
number_ptr = &number_2;  // NOT OK!
```

### Pointers as Function Parameters&#x20;

Pointers are useful to pass memory space that contains relevant data for functions to work on.&#x20;

The efficiency is comparable of that to reference variables when involving large data types, as only the memory address is copied and not the data that is stored at that address.&#x20;

It is important to ensure that the function is only allowed to modify parameters that you **want to let it modify**. The `const` keyword should be used to control what a function is allowed to modify for a pointer, as shown above.&#x20;

### Pointers versus Arrays&#x20;

Both arrays and pointers exhibit pointer behaviour.&#x20;

An array declaration is similar to a pointer in that it will be created to operate within a fixed range of memory.&#x20;

Arrays can be implicitly assigned to a pointer, but a pointer cannot be assigned to an array. This is because arrays are variables, and as discussed initially, are references to **fixed locations in memory**.

### Pointers Common Mistakes&#x20;

* Memory leaks&#x20;
* Using invalid memory locations
* Dangling pointers leading to use-after-free&#x20;

### Pointers Best Practices&#x20;

### Do:

* Always initialise pointer variables; use `NULL` if unsure.&#x20;
* Ensure that pointers always point to valid memory addresses.&#x20;
* Always release dynamically allocated memory with `delete` or `delete[]`&#x20;

### Don't:

* Access the memory of a pointer after it has been released&#x20;
* Invoke `delete` on a pointer more than once

## References&#x20;

References are simply **aliases** for an existing variable.

```cpp
int foo = 2;
int& bar = foo; 
```

`bar` is a reference to `foo`.&#x20;

### Reference Parameters&#x20;

### Constant Reference Parameters&#x20;
