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.
First, we set the pointer to the address of the first element (which is the address of the array itself).
Next, we increment the pointer so that it now points to the next element in the array.
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
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
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
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
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
Now, we assign the value 0xDEADBEEF to x[1] via the pointer which was just incremented.
Increment the pointer again (by 4 bytes).
Assign the value 0xF1D0F00D to x[2] via the pointer.
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
And finally, we overwrite the previous value in x[0] via the pointer with 0xFABF00D1.
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.
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].
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.
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
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.
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
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.
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
Now on this line, we first increment the data pointed to by p. So, x[1] is incremented from 2 to 3.
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
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)++