2
#include <stdio.h>

void main() {
    int a[4][3] = {
        { 3, 5, 7 },
        { 2, 4, 67 },
        { 21, 8, 9 },
        { 2, 45, 6 }
    };
    printf("%u ", *(&a[0]+1));
}

The expression (&a[0]+1) gives &a[1] and the output should be 2 but the output of above code is &a[1] why? This may seem silly, but please help me.

chqrlie
  • 131,814
  • 10
  • 121
  • 189

2 Answers2

5

As you note &a[0]+1 is &a[1]. a[1] is an array of 3 int, so &a[1] is the address of an array of 3 int.

That means *&a[1] is an array of 3 int. In C, an array is automatically converted to the address of its first element (except when it is the operand of sizeof, unary &, or _Alignof or is a string literal used to initialize an array). So *&a[1] automatically becomes &a[1][0].

Since this is a pointer, it should not be printed with %u. A proper way to print it would be:

printf("%p\n", (void *) *(&a[0]+1));

However, given that you did use %u, it seems what happened is the program printed the value of the pointer reinterpreted as an unsigned int. This is not behavior you should rely on.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • I believe the C standard states that when the unary operators are combined such as `*&a[1]`, they are both dropped rather than evaluated. – Christian Gibbons Jun 27 '18 at 15:09
  • 2
    @ChristianGibbons: C 2011 (draft N1570] 6.5.3.2 3 says that `&*something` is treated as `something` except that the constraints still apply and the result is not an lvalue. But I do not see a similar statement for `*&something`. And `*&a[1]` does not appear in the code; it is just a way of talking about the expression evaluation. – Eric Postpischil Jun 27 '18 at 15:12
  • Ah, yes, I see now. I ran across it yesterday (footnote 102) and it did mention something similar for `*&something`, but it was specifically for function designators. My mistake. – Christian Gibbons Jun 27 '18 at 15:17
  • But note that `*&something` always evaluates to the same value as `something` by the specifications of the operators' behavior. On the other hand, making a special case for the reverse operator ordering saves `&*something` from producing undefined behavior in the event that `something` has pointer type, but its value is not a valid pointer. – John Bollinger Jun 27 '18 at 15:17
3

The expression (&a[0]+1) gives &a[1]

Yes.

and the output should be 2

No.

but the output of above code is &a[1] why?

You're asking about the effect of

printf("%u ",*(&a[0]+1));

. We've established that (&a[0]+1) is equivalent to &a[1]. It follows that *(&a[0]+1) is equivalent to *(&a[1]), which in turn is equivalent to just a[1]. The value of a[1] is an array, not 2, notwithstanding the fact that 2 is the value of the first array element.

Your context is not among the very few in which array values fail to decay to pointers, so the overall function call is in fact equivalent to

printf("%u ", &a[1][0]);

At this point we hit a snag, however. The %u directive must correspond to an argument of (promoted) type unsigned int, and the actual argument instead has pointer type. This mismatch results in undefined behavior. It is plausible, but by no means guaranteed, that that manifests for you as printing a decimal integer corresponding to part or all of the pointer's bit pattern.

If you want to print the zeroth element of a[1], then it's easiest to write that simply as a[1][0], but you may also write it as *a[1] or **&a[1] or **(&a[0] + 1) or in many other forms.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157