1

There is code part below and I have a question about that.

Although I expect the compiler error, the ouput of this program is 2 5. From my point of view, &a+1 statement should lead to compiler error. The reason is that (a + 1) firstly is executed due to operator precedence and (a+1) statement points 2 in the array. Then, the address of operator (&) has (a + 1) operand but (a + 1) is an r-value expression and therefore &a+1 should cause a compiler error.

What is my fault?

int main()
{

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

    int *ptr = (int*)(&a+1);

    printf("%d %d", *(a+1), *(ptr-1));

    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Berat24
  • 33
  • 5
  • 2
    https://en.cppreference.com/w/c/language/operator_precedence - don't mix up unary `+` and the addition operator `+`. Or the `&` address-of unary and the `&` bitwise and. – Mat Feb 06 '22 at 15:21
  • For an array, `&a` is `a` or `&a[0]`. `&a+1` is `a+1`. So, no issues. See: https://stackoverflow.com/questions/70192415/does-the-address-of-a-pointer-change-when-using-malloc/70192569#70192569 – Craig Estey Feb 06 '22 at 15:23
  • 4
    @CraigEstey `&a` is *not* a. The type of `&a` is "pointer to an array of 5 ints", so `&a+1` points to just past the end of `a`. That is why, when cast to an `int*`, the (ptr-1) expression yields the last element. – Adrian Mole Feb 06 '22 at 15:26

3 Answers3

1

You seem to be confused about the actual operator precedence.

The unary address-of operator & has higher precedence than the binary addition operator +. So the in the expression &a+1 the address-of operator is first applied to a which is valid because a is an lvalue, then 1 is added to the result.

The actual precedence rules come from the grammar in the C standard, although it can be tricky for a novice to deduce what they actually are. A good reference for operator precedence can be found here:

https://en.cppreference.com/w/c/language/operator_precedence

From this chart, you can see that the binary bitwise AND operator & does indeed have lower precedence than the binary addition operator +, but the unary address-of operator & has higher precedence.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

Arrays decay to pointer. Any of those pointers reference the same address in memory. The difference is in the type of this pointer.

int arr[5];
  1. arr and &arr[0] have type pointer to int (int *)
  2. &arr has type of pointer to five elements integer array ( int (*)[5])

Then, the address of operator (&) has (a + 1) operand but (a + 1) is an r-value expression and therefore &a+1 should cause a compiler error.

No, the & operator is applied to a not to a + 1. &a + 1 === (&a) + 1

In your case &a is a pointer to 5 int elements. &a + 1 references the next array of 5 int elements, not the next element of the array a. Then you assign this value to int * pointer and derefence the previous int value. As pointer ptr is referencing the element one past the last element of the the array a so the previous element is the last element of the array a

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 2
    The conversion of `&a+1` to `int *` is not fully defined by the C standard. (It is partially defined in C 2018 6.3.2.3 7.) In particular, `(int *) (&a+1)` is not defined to be yield a value equivalent to `a + 5`. So “As pointer `ptr` is referencing the element one past the last element of the the array `a` so the previous element is the **last** element of the array `a`” is not guaranteed by the C standard. – Eric Postpischil Feb 06 '22 at 15:42
  • @EricPostpischil IMO your interpretation goes too far. `It is one past minus one` which is 100% fine. Otherwise, any reference would not be guaranteed line in this example. https://godbolt.org/z/rfzjaYP6a – 0___________ Feb 06 '22 at 15:51
0

Here you define the object a to be an array of 5 integers.

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

Here, you use &a, which mean, a pointer to an object which is an array of 5 integers -- sizeof(a)=5*sizeof(int).

The object &a+1 is a pointer to an array of 5 integers as well (if you do (&a+1)-a you will get sizeof(a)), which is 5*sizeof(int). So, ptr will point 5 integers beyond a (which is the same asa[0]).

    int *ptr = (int*)(&a+1);

Next, you access *(ptr-1), but this time the pointer arithmetics will subtract only sizeof(int) from ptr, as ptr has type pointer to int -- you will access an integer at an address ptr[-1], which falls inside the first array of five elements, (&a)[0], it points on its last integer.

    printf("%d %d", *(a+1), *(ptr-1));

*(a+1) is simple, it is just a[1], of type integer.

     &(a[1])       ptr-1 ptr
     |              |    |
     V              V    V
+----+----+----+----+----+----+----+----+----+----+
|    |    |    |    |    |    |    |    |    |    |
+----+----+----+----+----+----+----+----+----+----+
^                        ^                        ^
+------------------------+------------------------+
|                        |                        |
&a                       &a+1                     &a+2
alinsoar
  • 15,386
  • 4
  • 57
  • 74