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
