Chapter 8 - Notes

Pointers

A pointer is a variable that stores a memory address, i.e. it points to a location in memory.

Declaring a Pointer

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).

<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

Variables are simply names that are fixed to a specific location in memory. The memory address of a variable cannot change.

The memory address of a variable named variable can be obtained with &variable.

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

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

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

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

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

What happens when we try to store the memory address of a float into an int* pointer?

Accessing Data Through an Address

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.

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.

The dereference operator can also be used to change the value stored at the memory address.

Size of a Pointer

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

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.

Dynamic Memory Allocation

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

Allocating Memory Dynamically

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.

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

int* dynamically_allocated_int = new int;

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

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

Releasing Memory Dynamically

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

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.

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

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

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

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

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

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

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

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

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

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.

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.

Pointers versus Arrays

Both arrays and pointers exhibit pointer behaviour.

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

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

  • Memory leaks

  • Using invalid memory locations

  • Dangling pointers leading to use-after-free

Pointers Best Practices

Do:

  • Always initialise pointer variables; use NULL if unsure.

  • Ensure that pointers always point to valid memory addresses.

  • Always release dynamically allocated memory with delete or delete[]

Don't:

  • Access the memory of a pointer after it has been released

  • Invoke delete on a pointer more than once

References

References are simply aliases for an existing variable.

int foo = 2;
int& bar = foo; 

bar is a reference to foo.

Reference Parameters

Constant Reference Parameters

Last updated

Was this helpful?