In pointer arithmetic, the integer to be added or subtracted to pointer is interpreted not as change of address but as number of elements to move.
#include <stdio.h>
int main(void) {
int array[] = {1, 2, 3, 4, 5};
int *ptr = &array[0];
int *ptr2 = ptr + sizeof(int) * 2; /* wrong */
printf("%d %d\n", *ptr, *ptr2);
return 0;
}
This code does extra scaling in calculating pointer assigned to ptr2
.
If sizeof(int)
is 4, which is typical in modern 32-bit environments, the expression stands for "8 elements after array[0]
", which is out-of-range, and it invokes undefined behavior.
To have ptr2
point at what is 2 elements after array[0]
, you should simply add 2.
#include <stdio.h>
int main(void) {
int array[] = {1, 2, 3, 4, 5};
int *ptr = &array[0];
int *ptr2 = ptr + 2;
printf("%d %d\n", *ptr, *ptr2); /* "1 3" will be printed */
return 0;
}
Explicit pointer arithmetic using additive operators may be confusing, so using array subscripting may be better.
#include <stdio.h>
int main(void) {
int array[] = {1, 2, 3, 4, 5};
int *ptr = &array[0];
int *ptr2 = &ptr[2];
printf("%d %d\n", *ptr, *ptr2); /* "1 3" will be printed */
return 0;
}
E1[E2]
is identical to (*((E1)+(E2)))
(N1570 6.5.2.1, paragraph 2), and &(E1[E2])
is equivalent to ((E1)+(E2))
(N1570 6.5.3.2, footnote 102).
Alternatively, if pointer arithmetic is preferred, casting the pointer to address a different data type can allow byte addressing. Be careful though: endianness can become an issue, and casting to types other than 'pointer to character' leads to strict aliasing problems.
#include <stdio.h>
int main(void) {
int array[3] = {1,2,3}; // 4 bytes * 3 allocated
unsigned char *ptr = (unsigned char *) array; // unsigned chars only take 1 byte
/*
* Now any pointer arithmetic on ptr will match
* bytes in memory. ptr can be treated like it
* was declared as: unsigned char ptr[12];
*/
return 0;
}