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!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.
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 integersReleasing 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; 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.
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
NULLif unsure.Ensure that pointers always point to valid memory addresses.
Always release dynamically allocated memory with
deleteordelete[]
Don't:
Access the memory of a pointer after it has been released
Invoke
deleteon 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?