0
1)  #include <stdio.h>
    int main()
  {
       int a[5] = {1,2,3,4,5};
       int *ptr = (int*)(&a+1);
        printf("%d %d", *(a+1), *(ptr-1));
        return 0;
   }

the output is 2 5. &a means the address of a[0] so &a+1 should be the address of a[1]. So ptr should hold the address of a[1]. *(a+1) will be 2 but *(ptr-1) should also be 2. I can't understand how is it printing 5.

dbush
  • 205,898
  • 23
  • 218
  • 273
WRICK
  • 31
  • 4
  • 2
    `&a` means the address of `a`, not `a[0]`. The type of `a` is `int[5]`, so `&a + 1` adds `sizeof(a)` (which is `sizeof(int) * 5`) to that address. You want to use `int *ptr = (int*)(&a[0] + 1);` – Sander De Dycker Jun 26 '18 at 12:47
  • Initialize your `ptr` with `a+1` or `&a[0] + 1`, no need to cast. – Umaiki Jun 26 '18 at 12:49
  • Possible duplicate of [Different Pointer Arithmetic Results when Taking Address of Array](https://stackoverflow.com/questions/33775701/different-pointer-arithmetic-results-when-taking-address-of-array) – Ruud Helderman Jun 26 '18 at 12:55
  • If `ptr` did hold the address of `a[1]`, then `*(ptr - 1)` would be `1`, not `2` – M.M Jun 26 '18 at 21:36

4 Answers4

4

This expression is the important thing: &a+1. That is actually (&a)+1 which is equal to (&a)[1] which will be a pointer to one element past the end of the array.

If we look at it more "graphically" it looks like this, with relevant pointers added:

+------+------+------+------+------+
| a[0] | a[1] | a[2] | a[3] | a[4] |
+------+------+------+------+------+
^      ^                           ^
|      |                           |
|      &a[1] (equal to *(a + 1))   |
|                                  |
&a[0] (equal to a)                 |
|                                  |
&a                                 &a+1

First of all, the type of &a is int (*)[5], so your cast to int * will break strict aliasing (which leads to undefined behavior).

Second of all, since ptr is pointing, effectively, to what would be a[5] then ptr - 1 will point to a[4].

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Does the cast `(int*)(&a+1)` break strict aliasing or is it the subsequent de-referencing the pointer `*(ptr-1)` that may break strict aliasing? – chux - Reinstate Monica Jun 26 '18 at 13:26
  • @chux Without even attempting to dig into the specification, I would say it's the cast, since it tells the compiler that the pointer `&a+1` is something it really isn't. But don't quote me on that! :) – Some programmer dude Jun 26 '18 at 13:29
  • 1
    Thanks - Hmmm, on review I am confident `&a+1`, `(int*)(&a+1)`, and `int *ptr = (int*)(&a+1);` are all well defined per `C11 §6.3.2.3 7`. Yet this minor issue should not take more away from a good answer – chux - Reinstate Monica Jun 26 '18 at 13:36
  • @chux Since you've checked the spec., I'll trust you on that. – Some programmer dude Jun 26 '18 at 13:37
  • @chux Is [this program](https://ideone.com/zA5pMh) well defined by the standard or It is `UB` ? – Michi Jun 26 '18 at 17:29
  • 1
    @Michi Best to post such questions as _questions_ instead of comments. – chux - Reinstate Monica Jun 26 '18 at 17:33
  • 2
    Casts never violate the strict aliasing rule. The rule is about accessing an object of type T through lvalue of type U where there does not exist certain relationship between T and U. – M.M Jun 26 '18 at 21:29
2

&a is not the address of a[0] but the address of a. The values may be the same but the types are different. That is important when it comes to pointer arithmetic.

In the expression &a + 1, you first have &a which has type int (*)[5], i.e. a pointer to an array of size 5. When you add 1 to that it actually adds sizeof(a) bytes to the pointer value. So &a + 1 actually points to one byte past the end of the array. You then cast this expression from int (*)[5] to int * and assign it to ptr.

When you then evaluate *(ptr - 1), the - operator subtracts 1 * sizeof(int) from the byte value of ptr so it now points to the last element of the array, i.e. 5, and that is what is printed.

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

&a gives the address of the array as an array pointer, int (*)[5]. It is a pointer type that points at the array as whole, so if you do pointer arithmetic with it, +1 will mean +sizeof(int[5]) which is not what you intended.

Correct code:

int *ptr = a+1;

Notably, the cast (int*) was hiding this bug. Don't use casts to silence compiler errors you don't understand!

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • `the cast (int*) was hiding this bug` What exactly happens If I change `int *ptr = (int*)(&a+1);` to `int *ptr = *(&a+1);`. Because It seems to be the same . Now `ptr` points to `int (*)[5]` and there is no Cast. – Michi Jun 26 '18 at 16:58
  • There is no bug; the code was attempting (and succeeding) to display the last element of `a`. Your "correct code" would display the first element. – M.M Jun 26 '18 at 21:35
  • @Michi You can't convert implicitly from `int (*)[5]` to `int*`, they aren't compatible pointer types. `int *ptr = *(&a+1);` is fine except it points in the middle of nowhere. – Lundin Jun 27 '18 at 07:03
  • @M.M It is not really clear what the intention is. It is however clear that `&a+1` points beyond the end of the array, not at the last element. `int*` is not compatible with `int (*)[5]` nor do they necessarily alias. I don't think it is well-defined behavior to do pointer arithmetic on an array pointer and then convert to a `int*`. We can point 1 item beyond an array without invoking UB, but in this case, it ends up as 1 array beyond, not 1 int beyond. – Lundin Jun 27 '18 at 07:07
1

Firstly, you said: &a means the address of a[0] so &a+1 should be the address of a[1] ? No you are wrong. &a means address of a not a[0]. And &a+1 means it increments by whole array size not just one elements size and a+1 means address of a[1].

Here

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

lets assume base address of a is 0x100

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116 ..  
   LSB
    |
    a  

When you are doing

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

Where ptr points ? first (&a+1) performed and it got increments by whole array size i.e

(&a+1) == (0x100 + 1*20) /* &a+1 here it increments by array size */
       == 0x120

So now ptr points to

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116  0x120  
    a                                     |
                                         ptr points here

Now when you print like

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

Here

*(a+1) == *(0x100 + 1*4) /* multiplied by 4 bcz of elements is of int type*/
       == *(0x104) /* value at 0x104 location */
       == 2 (it prints 2)

And

*(ptr-1)  == *(0x120 - 1*4)
          == *(0x116) /* prints value at 0x116 memory location */
          == 5

Note :- Here

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

type of &a is of int(*)[5] i.e pointer to an array of 5 elements but you are casting as of int* type, as pointed by @someprogrammerdude it breaks the strict aliasing and lead to undefined behavior.

Correct one is

int *ptr = a+1;
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Achal
  • 11,821
  • 2
  • 15
  • 37