Why does pointer subtraction yield a number unrelated to the values pointed to?

79 views Asked by At
#include <stdio.h>

void main() {

    int arr[] = {10,20,30,40};
    int *p1 = arr;
    int *p2 = &arr[2];

    printf("%d",p2-p1);
}

Output : 2

I was suprised to see the output as 2. I don't know why the output is 2.

3

There are 3 answers

1
Im Groot On

When you subtract p1 from p2 i.e. (p2 - p1), you're essentially finding the difference between their memory addresses. Since both pointers are pointing to elements within the same array, the difference between their addresses indicates how many elements apart they are in the array. So, p2 - p1 gives you 2, indicating that there are 2 integers (or elements, each element is of 4 bytes because of int).

If you intend to access the value, you can do it by printf("%d",*p2-*p1);

0
shadow On
int arr[] = {10,20,30,40};


arr     | 10  | 20  | 30  | 40
index   |  0  |  1  |  2  |  3
pointer | @+0 | @+1 | @+2 | @+3

int *p1 = arr;
int *p2 = &arr[2];

this mean, p1 points to the first address of the arr which is @ and p2 points to the third element of arr which is @+2

printf("%d",p2-p1);

p2-p1 => @+2 - @ = 2 so output is 2

0
Vlad from Moscow On

In this declaration

int *p1 = arr;

the array designator is implicitly converted to a pointer to its first element. It is equivalent to the following declatayion

int *p1 = &arr[0];

An expression like that arr[i] where i is some integer is evaluated like *( arr + i ). That is the expession a[0] is evaluated like *( a + 0 ) that is the same as *( a ) or *a. And the expression a[2] is evaluated like *( a + 2 ). Applying the address of operator for the expressions you will get that the valie of p1 is equal to a + 0 or a and the value of p2 is equal to the value of the expression a + 2.

So the difference p2 - p1 is the same as ( a + 2 ) - a that is equal to 2.

From the C Standard (6.5.6 Additive operators)

8 When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

Pay attention to that the type of the expression is ptrdiff_t. So you should write

printf("%td",p2-p1);

instead of

printf("%d",p2-p1);