the code:
int arr[5] = {10, 20, 30, 40, 50};
printf("%lu %lu\n", *(&arr + 1), arr); // 6422036 6422016
printf("%lu\n", *(&arr + 1) - arr); // 5
Why the second printf
prints 5 instead of 20?
the code:
int arr[5] = {10, 20, 30, 40, 50};
printf("%lu %lu\n", *(&arr + 1), arr); // 6422036 6422016
printf("%lu\n", *(&arr + 1) - arr); // 5
Why the second printf
prints 5 instead of 20?
Why the second printf prints 5 instead of 20?
Code is living on the edge.
&arr
is the address of the array, so + 1
is the address of the next array: 5 int
later. So far, this is good.
*(&arr + 1)
de-references that address. So we get that next array. Not so good @RobertS supports Monica Cellio. An array passed to a ... function like printf()
is converted to the address of the first element, an int *
.
*(&arr + 1) - arr
subtracts two pointers of the same type int *
that are 5 int
apart leading to difference of 5
of type intptr_t
. Recall that pointer subtraction is the difference of the number of the referenced types (int
in this case), not the difference of the pointer values. 5 not 20.
Code attempts to print a intptr_t
as an unsigned long
with "%lu"
, which might work, might not (UB). Not so good. Better to use "%td"
.
printf("%td\n", *(&arr + 1) - arr);
There are two points in your interesting question :
1 : How does operation on pointers work ?
Try the following code :
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv) {
int simpleInt= 10 ;
printf("Output 1 : %p %p \n", &simpleInt+1, &simpleInt); // 61FE20 and 61FE1C
printf("Output 2 : %lld \n", &simpleInt+1 - &simpleInt); // 1
printf("Output 3 : %lld\n", (uint64_t)(&simpleInt+1) - (uint64_t)(&simpleInt)); // 4
}
Output 1 : Clearly, the difference between the two printed pointer values is 4
Output 2 : You are performing operation on int *
. 1 is added to an operand of type int *
and after an operand of type int *
is substracted. From an " int *
point of view" (if I could simplify it like that), only one is added. So, the output is 1.
Ouput 3 : Each operands of the substraction are casted to a long long unsigned int. So the substraction is done on integers and not on pointers. The ouput is 4, as expected.
2. What is the difference between arr and &arr ?
Let's have a look to the following code
int arr[5] = {10, 20, 30, 40, 50};
printf("Output 1 : %p %p %p \n", arr, &arr, *(&arr) ); //Seems to be the same thing but NOT. int*, int*[5], int*, respectively
// printf("%lld\n", arr - &arr ); // compilation error : int * and int(*)[5]
printf("Output 2 : %lld\n", arr - *(&arr) );
//printf("%lld\n", &arr - *(&arr) ); // compilation error : int(*)[5] and int *
printf("Output 3 : %p %p %p \n", (arr + 1), (&arr + 1), *(&arr + 1) ); // +4, +20, +20
printf("Output 4 : %lld\n", *(&arr + 1) - arr);
printf("Output 5 : %lld\n", (uint64_t)(*(&arr + 1)) - (uint64_t)(arr));
Ouput 1 : The value are the same but not the type of arguments. And this point is very important. The name of an array is a pointer to its first element. In your case, your array is an array of int
, so arr
is a pointer to int : int*
. &arr
is the address of your variable arr
which is an array of 5 integers. So the type of &arr
is int(*)[5]
. And the type of *(&arr)
is int*
Output 2 : Some lines give compilation errors because of the explanation above. And you could do operations on the same pointer type : arr
and *(&arr)
Output 3 : Depending which kind of pointer is incremented, +4 or +20 is obtained. +20 because 1 is added to an operand of type int(*)[5]
: 5 * 4 (sizeof int
= 4)
Output 4 & 5 : As, in the first point (operation on pointer), your are performing a substraction with int*
as operand