Pointers
Whenever we declare new variables so that we can store values in them, we actually send a memory allocation request to the operating system. The OS will try to reserve a block of continuous memory for our application if there is enough free memory left.
When we want to access the value stored in that memory space, we call the variable name.
We don't have to worry about the memory location where we have stored the value. However, what if we want to get the address of the location where the variable is stored?
The address that locates the variable within the memory is called a reference to the variable. To access this, we use an address-of & operator. To get the address location, we place the operator before the variable.
Pointers are variables, and like any other variables they are used to store a value; however, this specific variable type allows the storage of the address—the reference—of another variable.
In C/C++, every variable can also be declared as a pointer that holds a reference to a value of a certain data type by preceding its variable name with an asterisk (*). This means, for example, that an int pointer holds a reference to a memory address where a value of an int may be stored.
A pointer can be used with any built-in or custom data type. If we access the value of a pointer variable, we will simply get the memory address it references. So, in order to access the actual value a pointer variable references, we have to use the so-called de-referencing operator (*).
If we have a variable called age and assign a value to it, to get the reference address location, we use &age to store this address in a variable. To store the reference address, we can't just use a regular variable, we have to use a pointer variable and use the deference operator before it to access the address, as follows:
int age = 10; int *location = &age;
Here, the pointer location will store the address of where the age variable's value is stored.
If we print the value of location, we will get the reference address where age is stored:
#include <iostream> #include <conio.h> // Program prints out values to screen int main() { int age = 10; int *location = &age; std::cout << location << std::endl; _getch(); return 0; }
This is the output:
This value might be different for you, as the location will be different from machine to machine.
To get the location of where the location variable itself is stored, we can print out &location to get this value as well.
This is the memory location of the variable on my system memory:
Let's look at another example, as follows:
#include <iostream> #include <conio.h> // Program prints out values to screen int main() { int age = 18; int *pointer; pointer = &age; *pointer = 12; std::cout << age << std::endl; _getch(); return 0; }
Here, we create two int variables; one is a regular int and the other is a pointer type.
We first set the age variable equal to 18, then we set the address of age and assign it to the pointer variable called pointer.
The int pointer is now pointing to the same address where the age variable stores its int value.
Next, use the de-reference operator on the pointer variable to give us access to the int values stored at the referenced address and change the current value to 12.
Now, when we print out the value of the age variable, we will see that the previous statement has indeed changed the value of the age variable. A null pointer is a pointer that is not pointing to anything, set as follows:
int *p = nullptr;
Pointers are very much associated with arrays. As arrays are nothing but a continuous sequence of memory, we can use pointers with them.
Consider our arrays example from the arrays section as follows:
int age[5] = { 12, 6, 18 , 7, 9 };
Instead of using the index, we can use pointers to point to the values in the array.
Consider the following code:
#include <iostream> #include <conio.h> // Program prints out values to screen int main() { int *p = nullptr; int age[5] = { 12, 6, 18 , 7, 9 }; p = age; std::cout << *p << std::endl; p++; std::cout << *p << std::endl; std::cout << *(p + 3) << std::endl; std::cout << *p << std::endl; _getch(); return 0; }
In the main function, we create a pointer called pointer, as well as an array with five elements. We assign the array to the pointer. This causes the pointer to get the location of the address of the first element of the array. So, when we print the value pointed to by the pointer, we get the value of the first element of the array.
With pointer, we can also increment and decrement as a regular int. However, unlike a regular int increment, which increments the value of the variable when you increment a pointer, it will point to the next memory location. So, when we increment p it is now pointing to the next memory location of the array. Incrementing and decrementing a pointer precisely means moving the referenced address by a certain number of bytes. The number of bytes depends on the data type that is used for the pointer variable .
Here, the pointer is type int, so when we move the pointer by one, it moves 4 bytes and points to the next integer. When we print the value that p is pointing to now, it prints the second element's value.
We can also get the value of other elements in the array by getting the pointer's current location and by adding to it the nth number you want to get from the current location using *(p + n), where n is the nth element from p. So, when we do *(p + 3), we will get the third element from where p is pointing to currently. Since p was incremented to the second element, the third element from the second element is the fifth element, and so the value of the fifth element is printed out.
However, this doesn't change the location to which p is pointing, which is still the second position.
Here is the output: