1

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?

ShowTsai
  • 45
  • 6
  • 1
    `&arr` has type *pointer-to-array* `int [5]` so `*(&arr + 1)` is the address of the first element in the next `5 int` array after `arr` and the type you are printing is `int *` so the values are `5 int` (20-bytes) away from each other. (and technically you invoke *Undefined Behavior* due to the mismatch in *conversion specifier* and type. `"%p"` is the proper specifier for pointers (though `"%lu"` should be sufficiently wide)) – David C. Rankin Apr 12 '20 at 07:55
  • 1
    This is just a suggestion, you might want to edit this and change the title to a question. It's a bit vague. – thepufferfish Apr 12 '20 at 07:58
  • Good call, but to what? *"C - Why the difference when printing Array Addresses"*? – David C. Rankin Apr 12 '20 at 08:00
  • 2
    Because the distance between `*(&arr + 1)` and `arr` is **5 elements**. – pmg Apr 12 '20 at 08:02
  • Does this answer your question? [How does this piece of code determine array size without using sizeof( )?](https://stackoverflow.com/questions/56154380/how-does-this-piece-of-code-determine-array-size-without-using-sizeof) – RobertS supports Monica Cellio Apr 12 '20 at 08:06
  • 2
    @DavidC.Rankin It is also UB because of this: C11, 6.5.6/9: "*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.*" – RobertS supports Monica Cellio Apr 12 '20 at 08:08
  • Ooh good point.... – David C. Rankin Apr 12 '20 at 08:12

2 Answers2

0

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); 
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

There are two points in your interesting question :

  1. How does operation on pointers work ?
  2. What is the difference between arr and &arr ?

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

Stef1611
  • 1,978
  • 2
  • 11
  • 30