1

I am having troubles with the following code:

int a[] = {1, 2, 3, 4};
  
fprintf(stdout,
        "a      : %lu\n"
        "*a     : %d\n"
        "&a     : %ld\n"
        "**(&a) : %d\n",
        (unsigned long int)a,
        *a,
        (unsigned long int)&a,
        **(&a)
);

Output:

a      : 140726063647232
*a     : 1
&a     : 140726063647232
**(&a) : 1

i know that &a is a pointer to the 1 D array. And &a's type is int (*)[4]. I am confused with how comes **(&a): 1.

Adam
  • 2,820
  • 1
  • 13
  • 33
anbocode
  • 53
  • 6
  • 3
    You should use `%p` for pointers, not `%lu`. – Barmar Jun 30 '20 at 04:59
  • If you are relative new to programming languages: in C an array is a pointer too. For basic language concepts, typing, some other language would probably be better. At least pedagogically. – Joop Eggen Jun 30 '20 at 05:10
  • 1
    `**(&a)` is 100% equivalent to `*a` and that's about it. It's just obfuscation - writing bad code on purpose. – Lundin Jun 30 '20 at 06:06
  • @Lundin, The obfuscation is deliberate in order to teach one about dereferencing and referencing. – Anshuman Kumar Jun 30 '20 at 06:11
  • @AnshumanKumar Then why wasn't it written as either `**&a` or `*(*(&a))`? The former would be the cleanest and the latter could make sense if you expect the student not to grasp precedence/associativity. Something in between though? – Lundin Jun 30 '20 at 06:20
  • Well, I am not the author of the code @Lundin. However, in the my first year at college, I had encountered such verbage in an introductory programming course. – Anshuman Kumar Jun 30 '20 at 07:25

3 Answers3

1

&a is a pointer to an array. *p gets what the pointer points to, so *&a gets the array, a.

An array treated as a pointer degenerates into a pointer to its first element, so *a is 1.

Since *&a is just a, **&a is the same as *a, which is 1.

ikegami
  • 367,544
  • 15
  • 269
  • 518
1

Another way to look at it is through the resulting type after each address of or dereference operation. A basic rule for array access is Array-pointer conversion. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) which applies on access to any array (subject to the 4 exceptions listed [3 in the C18 standard -- _Alignofis no longer listed]).

The key is to understand that an array, on access, is converted to a pointer to the first element (subject to limited exception - not relevant here). If you take the address of an array, the address is the same as that of the first element, but the type of pointer is completely different.

     a   - pointer to int
    &a   - pointer-to-array int[4], proper type: int (*)[4]

When you dereference a, you get the first element:

    *a   - int

Why? *a is short for the full derefernce operation with an offset of 0, e.g. *(a + 0) which is equivalent to a[0] in index notation.

When you dereference your pointer-to-array int[4], you get your array back:

 *(&a)   - int[4] -> converted to pointer to first element.

which then, by operation of, 6.3.2.1(p3) is converted to a pointer to the first element. Dereference again and you get the first element:

**(&a)   - int

It's worth learning now as it will save you a lot of bewilderment later.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1
  1. if you whish to print an address yous hould use the %p conversion specifier for the printf or fprintf function.
  2. on the other hand, printing integer data type with the same functions above, you should use the %d conversion specifier. then you can omit all the up-cast to unsigned long int data type.
  3. c arrays decays to pointer of the same data type in your case (not in all cases arrays can decays to pointer). in your prints you have used this fact, e.g when dereference the array *a. this fact in c enable us to writhe the folowing statement: int* a_ptr = a; AND int* ptr = &a[0];. now a_ptr and ptr are equal! pointing to the same address in memory.
  4. printing a is like printing the a_ptr value and like printing the ptr value. which ends in printing the &a[0].
  5. printing *a is like printing *a_ptr and like printing *ptr and since ptr = &a[0]; then , *ptr == *&a[0]==a[0] so in simple words its a[0] which is 1.
  6. priniting &a. now what is &a ? its a pointer to array of integeres! and to be more precised its a pointer to array of 4 integeres, which is int (*)[4] so when printing the address of a its like printing the dereference of *(int (*)[4]) which is the the address of the array simple a. be aware that the data types are comletley different! a and &a!
  7. printing **(&a) is the same as *(*(int (*)[4])) is the same as *(a) which is the same as *(a+0) which the same as *ptr which is : a[0] which is 1.

fix the code snippet to be:

int a[] = {1, 2, 3, 4};

fprintf(stdout,    /*you can use printf instead of fprintf(srdout,)*/
    "a      : %p\n"
    "*a     : %d\n"
    "&a     : %p\n"
    "**(&a) : %d\n",
       a,
      *a,
      &a,
   **(&a)
);
Adam
  • 2,820
  • 1
  • 13
  • 33