Pointer Arithmetic

Last modified by Microchip on 2023/11/09 09:06

A Preview


Here, is an example of an array and a pointer being used to identify a particular element. One of the most powerful features of using pointers with arrays is that incrementing a pointer always moves it to the next element in the array, regardless of the number of bytes that each element occupies.

Pointer Arithmetic 1

First, we set the pointer to the address of the first element (which is the address of the array itself).

Pointer Arithmetic 2

Next, we increment the pointer so that it now points to the next element in the array.

Pointer Arithmetic 3

Back to top.

Incrementing Pointers


When you increment or decrement a pointer, it will always increment by the number of bytes occupied by the type it points to. For example, if we have a pointer to float, incrementing the pointer will increment the address it contains by 4, since float variables occupy 4 bytes of memory. The compiler does this automatically for you, eliminating the need to keep track of variable sizes yourself in these situations.

Example

1 float x;
2 float *p = &x;
3 p++;

Pointer Arithmetic 4

Back to top.

Larger Jumps


Similarly, if we use the compound assignment operator to add or subtract a larger number for a longer jump, the pointer will be modified by a multiple of the number of bytes occupied by the type it points to.

For example, if we have a pointer to int, adding 3 to the pointer will add 3*2 = 6 to the address it contains. This is because int variables occupy 2 bytes. Likewise, if we had a pointer to float, adding 3 to the pointer will add 3*4 = 12 to the address it contains. This is because float variables occupy 4 bytes.

Example

1 int x;
2 int *p = &x;
3 p += 3;

Pointer Arithmetic 5

Back to top.

Pointer Arithmetic


Here, we have a simple program to illustrate the concepts of both incrementing a pointer and using a compound assignment operator to jump more than one element in the array. First, we initialize the pointer p to point to the array x. In this case, we are initializing the pointer as it is declared. The syntax is exactly the same as doing this for an ordinary variable.

Example

Pointer Ex 1

This first line adds 4 to the element pointed to by p which in this case is x. So, we started off with x[0] = 1 :
 

*p += 4
x[0] += 4
x[0] = x[0] + 4
x[0] = 1 + 4
x[0] = 5

Arithmetic Ex 1

Now, we increment the pointer. Since we are pointing to a long, the pointer will be incremented by 4 bytes:

p = 0800
p++
p = p + (1 * 4)
p = 0800 + 4
p = 0804

Arithmetic Ex 2

Now, we assign the value 0xDEADBEEF to x[1] via the pointer which was just incremented.

Arithmetic Ex 3

Increment the pointer again (by 4 bytes).

Arithmetic Ex 4

Assign the value 0xF1D0F00Dto x[2] via the pointer.

Arithmetic Ex 5

Now, we want to decrement the pointer by 2 elements. Since a long is 4 bytes, we will decrement p by 2 * 4 = 8 bytes.

p = 0808
p -= 2
p = p – (2 * 4)
p = 0808 – 8
p = 0800

Arithmetic Ex 6

And finally, we overwrite the previous value in x[0] via the pointer with 0xFABF00D1.

Arithmetic Ex 7

Back to top.

Post-Increment/Decrement Syntax Rule


Care must be taken with respect to operator precedence when doing pointer arithmetic:

SyntaxOperationDescription by Example
p++
*p++
*(p++)
Post-Increment Pointerz = *(p++);
is equivalent to:
z = *p;
p = p + 1;
(*p)++Post-Increment
data pointed to
by Pointer
z = (*p)++;
is equivalent to:
z = *p;
*p = *p + 1;

The association of the * operator and ++ operator on pointers is problematic because both * and ++ have the same precedence but they have right-to-left associativity which effectively gives the postfix ++ operator higher precedence than *. Many beginners assume that *p++ will increment the data pointed to by p, when in fact it has no effect on the data but does increment the pointer variable itself. To be explicit, the operation is carried out as *(p++). When used in an expression, the value of the data pointed to by p will be extracted first, then the pointer will be incremented (postfix ++ uses the variable first, then increments it).

To operate on the data pointed to by the pointer, it is necessary to enclose the dereference operator and the pointer variable in parentheses, essentially showing that the two tokens are inseparable and must be considered together first. So, (*p)++ is the same as x++, if p points to x. The increment operation will be carried out on the variable pointed to by pwhile the pointer itself remains unchanged.

Now, you could get really crazy and do something like (*p++)++. This will first take the value pointed to by p and use it in the expression. It then increments both the value pointed to by p and the pointer variable itself. Basically, it is the same as doing:

(*p)++;
p++;

Back to top.

Post-Increment / Decrement Syntax


Remember: *(p++) is the same as *p++

Example

Let's take a look at how the two different operations work based on the syntax used in each one. Here, we have declared and initialized an array of integers called x and a regular integer called y. Then, we declare a pointer p and initialize it with the address of x. (Remember that the address of the array x is the same as the address of its first element).

There are only two lines of code but each line performs two distinct operations.

Pointer Inc 1

On this line, we first use the value pointed to by p which is x[0], to perform the addition operation and store the result of 6 in the variable y.
In other words:

y = 5 + *p
y = 5 + x[0]
y = 5 + 1
y = 6

*p is the same as using x[0] because we initialized p with the address of the array x. The address of the array x is the same as the address of its first element x[0].

Pointer Inc 2

After the addition is performed, the pointer itself is incremented to point to the next integer in the array. Remember that incrementing a pointer will increment it by the multiple of bytes that the type it points to occupies in memory. Since int occupies two bytes, incrementing p will actually increment it by 2.

Pointer Inc 3

On this next line, just like before, we first use the value pointed to by p which is now x[1] = 2, to perform the addition. The result of 7 is stored in y.
In other words:

y = 5 + *p
y = 5 + x[1]
y = 5 + 2
y = 7

Pointer Inc 4

After the addition has been performed, we now increment the value pointed to by p. So, x[1] is incremented from 2 to 3.

On both of these lines of code, the increment took place after the addition operation because the increment operator followed the pointer variable (postfix). If the increment operator were prefixed to the pointer variable, the increment operation would have occurred first, then the value pointed to would be used.

The key thing to understand here is that the parenthesis have nothing to do with the order of operations. They are used to determine what gets incremented – the pointer itself or the value pointed to by the pointer. In both cases, the increment takes place after the pointer is used to retrieve the data it points to.

Pointer Inc 5

Back to top.

Pre-Increment/Decrement Syntax Rule


When doing a pre-increment operation, it works just like the post-increment operation but now the increment operation will take place before the pointer is used; otherwise the same rules apply.

SyntaxOperationDescription by Example
++p
++*p
*(++p)
Pre-Increment Pointerz = *(++p);
is equivalent to:
p = p + 1;
z = *p;
++(*p)Pre-Increment
data pointed to
by Pointer
z = ++(*p);
is equivalent to:
*p = *p + 1;
z = *p;

Back to top.

Pre-Increment / Decrement Syntax


Remember: *(++p) is the same as *++p

Example

Pointer Dec 1

With this program, the prefix increment means that it will be used before the pointer is used. So here, we first increment the pointer, so that it now points to x[1] instead of x[0] as it did originally.

Pointer Dec 2

Now that the pointer has been incremented, we will use the value it points to in the addition operation. So:

y = 5 + *p
y = 5 + x[1]
y = 5 + 2
y = 7

Pointer Dec 3

Now on this line, we first increment the data pointed to by p. So, x[1] is incremented from 2 to 3.

Pointer Dec 4

And now the value pointed to by p is used in the addition operation:

y = 5 + *p
y = 5 + x[1]
y = 5 + 3
y = 8

Pointer Dec 5

Back to top.

Summary


To summarize, the parentheses around the pointer don't affect the order of operations (i.e. whether to increment before or after using the pointer). Only the position of the increment or decrement operator affects the order: prefix makes the increment happen before the pointer is used and postfix makes the increment happen after the pointer is used. The parentheses determine whether the pointer or the item it points to is what gets incremented. The rule is: if the * (dereference operator) is outside the parentheses or no parentheses are used at all, the pointer is what will be incremented. If the * is inside the parentheses, the value pointed to by the pointer is what will be incremented.

Modify the pointer itself

pre-inc: *(++p) or *++p or ++p
post-inc: *(p++) or *p++ or p++

Modify the value pointed to by the pointer

++(*p) and (*p)++

Back to top.