user2879534
user2879534

Reputation: 99

Pointer to a reference plus one of array

I just read some question about pointer. Here is the code:

int a[5]={1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);//second line
cout<<(*p)<<endl;

My compiler output is 0. What is *p? Is it the pointer to array a? and what is &a+1 means?

Upvotes: 3

Views: 12133

Answers (4)

smRaj
smRaj

Reputation: 1306

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

what is *p? :

In your code, *p is a pointer to an unknown element of type int.

Lets reason it out:

&a is a valid pointer expression. An integer can be added to a pointer expression.

Result of &a : points to the whole array a[5]. Its type is int (*)[5]

Result of sizeof *(&a) is 5, which is the size of the array.

Result of &a +1 is pointer expression which holds the address of the 1st int beyond the one &a currently points to.

Hence, 1 object past the &a is what *p points to. Hence it is unknown element of type int. So, accessing unknown element is undefined behaviour. This also answers why your output is zero.


Side Note:

If you really wanted to access the second element in the array, you should add 1 to pointer which points to the first element of array. a points to the first element in the array and size is sizeof(int*).

Result of a+1 is the address of the second element in the array.

Result of *(a+1) is the value of the second element in the array. 2

Upvotes: 1

tay10r
tay10r

Reputation: 4357

This is what your declaration statement means:

                           p
                           |
                           v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->

But you're trying to get this (I assume):

     p
     |
     v
a[0] a[1] a[2] a[3] a[4] |
---------(Length)------->

You need to remove the second set of parenthesis from your declaration statement to get a[1]:

int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;

The reason you're getting the wrong value has to do with the sizeof operator, operator precedence, and pointer arithmetic. Let me explain those before I explain the error.


Sizeof Operator

The sizeof operator evaluates the size (in bytes) of a datatype. Immediate example:

sizeof (char)  // always returns 1
sizeof (int)   // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8

And note this interesting example:

int a[5];
sizeof (a) // returns sizeof (int) * 5

Operator Precedence

Operator precedence is the order in which a series of operators are evaluated. Anything in parenthesis will be evaluated first. After parenthesis are evaluated, it's up to the operator precedence to determine what order the expression will be solved.

Here's the relevant operators and they're order in the precedence table:

Operator    Description    Associativity

()          Parenthesis    Left-to-right
(cast)      Cast           Right-to-left
&           Address of     Right-to-left
+, -        Plus, Minus    Right-to-left

Pointer Arithmetic

Pointer arithmetic is mostly about adding, subtracting and multiplying pointers with integers (or other pointers). What you need to know (for the scope of this question) is this:

int * p;

p = p + 1;

Even though it says + 1, it is actually adding sizeof (int) to the pointer. This was a design choice by the writers of the C standard because it is much more common that programmers want to add sizeof (int) to the pointer (which brings them to the next integer in an array) than to add 1 (which brings the pointer in between the first and second element in the array).

More generally put:

datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);

Here's a relevant example:

int a[5];
a = a + 1;
// actually means
a = a + sizeof (a);
// remember that sizeof (a) is going to be sizeof (int) * 5?

Declaration Statement

Back to your declaration statement:

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

You may already see what's wrong with it: a + 1 really means a + sizeof (a), which brings you out of scope of the array. This may be 0 (often it is) or it may be some other random value.

What you might not have noticed is that this:

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

Actually gives you the second element in the array. This has to do with operator precedence. If you look at the operator precedence table that I put in a link, casts have a higher precedence than & and + operators. So if a is cast as a (int *) instead of a[5] before the rest of the expression is evaluated, then it becomes equivalent to this:

int * a;
a = a + 1; /* and this would
    give you the second element
    in the array */

So simply put, if you want to access the second element in your array, change:

int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;

Upvotes: 10

Filipe Gon&#231;alves
Filipe Gon&#231;alves

Reputation: 21213

The operator & is used to take the address of a variable. Thus, &a is of type pointer to array of 5 ints: int (*)[5].

Pointer arithmetic means that when you have a pointer p, then p+1 will point to the next element, which is sizeof(*p) bytes away. This means that &a+1 points to 5*sizeof(int) blocks away, namely, the block after the last element in the array.

Casting &a+1 to int * means that now you want this new pointer to be interpreted as a pointer to int instead of pointer to array of 5 ints. You're saying that, from now on, this pointer references something that is sizeof(int) bytes long, so if you increment it, it will move forward sizeof(int) units.

Therefore, *p is accessing a[5], which is an out of bounds position (one beyond the last), so the program has undefined behavior. It printed 0, but it could have crashed or printed something else. Anything can happen when undefined behavior occurs.

Upvotes: 5

Maroun
Maroun

Reputation: 95958

&a is the address of the array.

&a + 1 is also an address, but what is this 1? It's a pointer that points sizeof a bytes from a. So it's like writing int *p = &a[5];, then you're casting it to int *.

Now why 0? Because a[5] happens to be 0 - Note that it's out of bounds and could be anything else (Undefined behavior).

Note that arrays are zero-based, meaning that the indexes are from 0. So actually a[4] is the last element, a[5] is out of bounds.

Upvotes: 8

Related Questions