C++: Pointer Arithmetic

If you've done much experimentation with arrays, you may have noticed that arrays are actually just constant pointers with associated sizes! They point to the first element in the array, and then just store the next elements sequentially in memory until some sort of terminator in the memory indicates the end of the array. The easiest way to see this is if you simply cout the name of the array without using the square bracket notation, which will output the memory address of the first element in the array:

1
2
3
int array_name[] = {1, 2, 3, 4, 5}; //We don't have to specify a value in the square brackets here, the compiler can count the initialization parameters for us!

cout << array_name;

We can actually perform a level of arithmetic on pointers in which some level of complexity is done for us. Let's say we wanted to access the second element of the array by performing some mathematics on the pointer instead of using the bracket notation. As the elements are stored next to each other in memory, we simply need to go forward 4 bytes (the size of a standard integer) in memory to access the second element in the array (the one with index '1'). As the array pointer is of the type of data that the array holds (in this case, int), this calculation which takes into account the size of the data-type is done for us. This means that instead of having to do something like array_name = array_name + sizeof(int) to get the correct memory address, we can simply type array_name = array_name + 1 and the compiler will do the sizeof calculation for us!

So to access the second element in our integer array, we can simply add one to the pointer and then dereference this:

1
2
int array_name[] = {1, 2, 3, 4, 5}; //The compiler fills the square brackets in for us
cout << *(array_name + 1);

Note that this calculation would be different if we were working directly with the memory addresses, in which we would have to actually add all four bytes. An example of this would be converting the pointer into a regular number using the (long) or (int) typecasts, and then adding sizeof(int) to this and dereferencing the result (which we have to typecast also so the compiler knows what the hell we're trying to dereference):

1
2
int array_name[] = {1, 2, 3, 4, 5};
cout << *(int*)((long)array_name + sizeof(int)); //The not-so-neat way

Remember that typecasts are generally considered pretty bad practice to use in situations where they can be avoided (which is most), and this code is for example only!

A nice example of pointer arithmetic might be a simple function which loops through an array passed to it, outputting each element. In this example there would, of course, be easier alternatives - like using 'for' loops to fill the square bracket notation - but at the moment it's tough to give a simple example for practical uses for pointer arithmetic, as most of them are pretty complicated, and so this will suffice.

My original idea for this was to create a simple function that takes an array of variable size, then calculates the size and loops around, doing some pointer arithmetic until it gets to the end of the array. The issue with this, however, is that when pointers are passed into functions with a variable size, they just degrade to pointers (without the size bit) - this means that doing a sizeof in the function won't actually return the desired results. As I didn't feel like creating some crazy workarounds, it seemed like the easiest solution would be to simply have to also pass in the size of the array. The following was what I came up with the accomplish the task using some basic pointer arithmetic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>

using namespace std;

void loop_through_the_array(int array[], int size)
{
	int *element, *terminator; //Declare two int pointers
	element = array; //Set 'element' to point to the first element in the array
	terminator = array + size; //Set 'terminator' to point to the byte after the last element in our array

	while(element != terminator) //As long as the current byte isn't at the terminator memory address
	{
		cout << *element << endl; //Output the element
		element++; //Go to the next element (move four bytes forward)
	}
}

int main()
{
	int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	loop_through_the_array(array, 10);

	return 0;
}

On running the above, you should see that our exercise in pointer arithmetic works! The good thing about this method of looping through the array is that we're always completely sure that we've reached the end of the array if we know the terminator is set correctly, as there can only be one byte at the address which the terminator is at, so there is no chance of conflict. Then again, we can be pretty damn confident that a 'for' loop is going to work every time if it loops the correct number of times too.

As a challenge to tie off this tutorial, try creating a basic program which operates on the basis of some simple pointer arithmetic with arrays - use your imagination.