Pointer Arithmetic

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.

PointerArithmetic.png

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

PointerArithmetic2.png

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

PointerArithmetic3.png

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

PointerArithmetic4.png

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

PointerArithmetic5.png

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

PointerEx.png

This first line adds 4 to the element pointed to by p which in this case is x[0]. 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

ArithmeticEx2.png

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

ArithmeticEx3.png

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

ArithmeticEx4.png

Increment the pointer again (by 4 bytes).

ArithmeticEx5.png

Assign the value 0xF1D0F00D to x[2] via the pointer.

ArithmeticEx6.png

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

ArithmeticEx7.png

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

ArithmeticEx8.png

Post-Increment/Decrement Syntax Rule

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

Syntax Operation Description by Example
p++
*p++
*(p++)
Post-Increment Pointer z = *(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 p while 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++;

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.

PointerInc.png

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].

PointerInc2.png

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.

PointerInc3.png

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

PointerInc4.png

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.

PointerInc5.png

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.
Syntax Operation Description by Example
++p
++*p
*(++p)
Pre-Increment Pointer z = *(++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;

Pre-Increment / Decrement Syntax

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

Example

PointerDec.png

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.

PointerDec2.png

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

PointerDec3.png

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

PointerDec4.png

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

PointerDec5.png

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)++

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.