&arr+1
does, in fact, add 40
to the base address of the array arr
but it's not obvious since the addresses are in hexadecimal or base 16, not decimal.
Now, for what it's worth, I'll add some explanation of each statement to make things clear.
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
The above statement defines arr
to be of type int[10]
, i.e., an array of 10
integers. It then initializes arr
with an array initializer list.
printf("%p,%p\n", arr, &arr);
In the above statement arr
decays (evaluates or implicitly converted) to a pointer to its first element. Therefore its type is int *
. &arr
evaluates to a pointer to arr
. Type of arr
is int[10]
. Therefore, type of &arr
is int (*)[10]
, i.e., a pointer to an array of 10 integers. Parentheses are used because array subscript operator []
has higher precedence than *
operator. So without parentheses int *[10]
means an array of 10 pointers to integers. This is one of the cases where an array does not decay into a pointer to its first element.
Please note that both arr
and &arr
evaluate to the same value, i.e., the base address of the array in the above printf
statement but their types are different and they have different pointer arithmetic. This shows up in the following statement -
printf("%p,%p\n", arr+1, &arr+1);
arr+1
points to the next element. Here element type is int
. Therefore arr+1
evaluates to
arr + (1 * sizeof(int))
&arr + 1
also points to the next element but here the element type is int[10]
- an array of 10 integers
. Therefore &arr + 1
evaluates to
arr + (1 * sizeof(int[10]))