Pointers in C++

published

last modified

6kb

Pointers are an essential part of the c/c++ language. They are a powerful, mysterious and arcane tool. Kind of. They are actually quite simple.

A pointer is a variable the stores the address of another variable.

That's it.

Say we have a variable x of type int with value 25 stored at memory location 1004. Then a pointer to x would contain the value 1004.

Note__ that a pointer also has an address which again could have a pointer pointing to it.

Syntax

So how do we use pointers in c++. Well we declare them using the *.

int *my_ptr = nullptr;
char *my_char_ptr = nullptr;
double *my_double_ptr = nullptr;

It's easier to read this from right to left as: a pointer of type integer, called my_ptr.

It is important to note that it is best practise to always intiliaze pointers. If we don't they can be pointing anywhere and if we were to use this pointer we could change something in a memory location that we don't want to

Address

How do we even get the address of a variable, if say, we wanted to store that in a pointer? In c++ we can use the &. This operator is known as the address-of operator.

int foo = 25 // (address 1004)
int *ptr = nullptr;
 
ptr = &foo;
 
cout << ptr // --> 1004

Dereferencing

The next logical thing to think about is whether we can access the underlying value the pointer is pointing to. Of course we can! We do this using the dereference operator. This can simply be read as the value pointed to by.

Using the example from above:

int foo = 25; // (address 1004)
int *ptr = nullptr;
 
ptr = &foo;
 
cout << *ptr // --> 25

_Note: do not get confused with using the _ in different contexts. They do different things depending on where you use them. For example in declaring pointers vs dereferencing them.*

Changing Values Using Pointers

We can change the value the pointer is pointing too. This is quite simple.

double temp = 37.5;
double *temp_ptr = &temp;
 
cout << temp; // 37.5
 
*temp_ptr = 10.0;
 
cout << temp; // 10.0

Notice here that we first dereference the pointer, that is we say, grab the value pointed to by pointer and then assign 10.0 to that variable.

If we where to try do this without dereferencing, we would get an error as we would be attempting to assign a double to a pointer. This isn't allowed as pointers have to contain addresses.

Pointers Relationship to Arrays

Pointers and arrays have an interesting relationship. Arrays in c/c++ are implemented as pointers to the first element in the array.

So in other words if define an array and name it my_array this is actually just an alias for the memory location of the first element.

int my_nums[5] = {1, 2, 3, 4, 5};
cout << my_nums << endl; // 0x305384b20
 
cout << &my_nums[0] << endl;  // 0x305384b20

So if I print my_nums, I get back the memory location of the first element, which is at 0x305384b20 on my comupter. Indeed, if we print the reference to the first element to the array (the memory location) we get back the same value as when we just print the name of the array. So what happens when we declare a pointer to my array? That's a good question and the answer seems obvious now.

int *my_nums_ptr = {nullptr};
my_nums_ptr = my_nums;
cout << my_nums_ptr; // 0x305384b20

This pointer is just the memory location of the first element, exactly the same thing as what my_nums is.

So what happens when we access elements at each index?

Pointer Arithmetic

How do we access the next element in an array? We usually do this using subscript notation:

cout << my_nums[2] << endl; // 3

But what actually happens here? If we turn back to the fact that an array is just a contigous collection of homogenous elements in memory, then the next element should be the size of that data type plus the previous location in memory, right? You would be correct to think that.

For example, we know that an int takes up four bytes of memory. If we check the memory locations of the first two elements, we would expect to see something like this:

cout << "Memory location of the first element: " << &my_array[0] << endl;
cout << "Memory location of the second element: " << &my_array[1] << endl;
 
Memory location of the first element: 0x30df74b20
Memory location of the second element: 0x30df74b24

Indeed these two elements are four bytes away from each other! Awesome. Lets experiment with the pointer to my_nums.

What happens when we add, let's say the number one to the my_nums_ptr?

cout << "Increment pointer by 1: " << (my_array_ptr + 1) << endl; // 0x30df74b24

Oh okay! It looks like we get back the memory location of the next element back. It seems that adding one to the array actually adds four bytes to the memory location.

This is pointer arithmetic. When we add 1 to a pointer we move it by the size of the data type it is pointing to. Quite nifty right!

Subscript Notation and Pointer Arithmetic

Hmm. But I want the value at that next memory location. Wait. Isn't there that dereference operator, maybe I can use that?

cout << "Increment pointer by 1 and dereference it: " << *(my_array_ptr + 1) << endl; // 2

Okay cool! That makes sense. If we shift the pointer by the size of an int then dereference that we get back 2. If we do my_nums[1] we get the same thing. So I guess we can say something like:

my_nums[1] = *(my_nums_ptr + 1);

Contact

If you have any comments or thoughts you can reach me at any of the places below.