Reputation: 8015
We have
int a[5]={10, 20, 30, 40, 50};
I would like to know how does the following two code segment do?
int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);
If we have
printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1));
What should be the result?
Upvotes: 7
Views: 394
Reputation: 59111
"What should be the result"?
Next time you want to know what a tiny code snippet like this should do, check this out: http://ideone.com/4fCud
The result I got out of that was:
20 50 134520820
Edit:
When you run a program, see output like this, and find yourself asking, "where did that value come from?" you may have run into undefined behavior.
In this case the third value doesn't point to where you might think it would point. It is reading uninitialized memory (most likely), memory owned by code that is in your process space, but outside your program (a library you loaded, or the C runtime), or memory that simply has nothing to do with this program (less likely, because of protected memory).
Upvotes: 0
Reputation: 881675
All the problems come from the use of &a
, which is a pointer to "an array of five integers", so that pointer arithmetic (when you think in terms of addresses) gets "scaled" by sizeof(a)
(which might e.g. be 20 if int
are 4 bytes and the compiler needs no padding for alignment purposes -- reasonable hypotheses, though far from certain of course.
So, after
int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);
ptr
is a pointer to int at the memory address "sizeof(a) more than the address a", and t
similarly for "sizeof(a) less than the address of a". Therefore...:
printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1));
What should be the result?
Quite possibly a segmentation violation, otherwise 20
followed by two completely arbitrary integer values. Since ptr
and t
are pointers to int
, the address arithmetic scaling for their -1
and +1
does not compensate that done on &a
(the scaling in terms of memory addresses is by sizeof(int)
, not sizeof(a)
!), so ptr-1
and t+1
are pointing to (alleged;-) int
s that are respectively "a few int
s after the end of a
" and "a few int
s before the start of a
".
There's no way to know whether at those arbitrary addresses there is any memory which the process is allowed to address (whence the possibility for segmentation violatons), and, if any accessible memory is there, what its contents "seen as an int
" might possibly be.
Edit: @caf points out that ptr - 1
is not invalid -- it correctly points to the last element of a
; so the output (unless there's a segmentation fault, which @NullUserException thinks is very unlikely but on this point we disagree;-) would start with 20 50
before the third, "arbitrary" junk. Point is, per the C standard, it is valid to compute (though not to use) the pointer "just one past the end" of an array, and the sizeof an array must be exactly that array's length time the sizeof its elements (padding is allowed for an element's type, if needed, and if so it shows in the element's own sizeof, but not for the array as a whole). Subtle, but important;-).
Upvotes: 4
Reputation: 239041
Since the type of a
is array-of-5-int
s, that means that the type of &a
is pointer-to-array-of-5-int
s.
When you add or subtract 1 from a pointer, you ask it to point to the next or previous object of that type in memory. So &a+1
is creating a pointer to the array-of-5-int
immediately after a
in memory (which doesn't exist), and &a-1
is creating a pointer to the array-of-5-int
immediately before a
in memory (which also doesn't exist). In memory, it looks like this (where each cell represents one int
):
Address: &a-1 &a &a+1
Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? |
When a
is used in the expression *(a+1)
, it is converted to a pointer to its first element - so a pointer-to-int
pointing at the 10
value. Adding one to it then makes a pointer pointing at the next int
- a+1
points at the 20
value. *(a+1)
then fetches that value, so the first number printed is 20.
As ptr
is also a pointer-to-int
, that means that ptr - 1
creates a pointer to the int
immediately before ptr
- in this case, it'll be pointing at the 50. So the second number printed is 50.
Similarly, t + 1
creates a pointer to the int
immediately after t
- in this case, it's the second ?
in the above diagram. This is an uninitialised value - it could print anything at all, or even crash the program.
Address: &a-1 &a &a+1
t t+1 a a+1 ptr-1 ptr
Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? |
Upvotes: 6
Reputation: 98469
Let's look at it piece by piece.
&a
means the address of a. So, it gets the address of the address of the integer 10.
&a+1
is the next pointer over from that. So it's the thing stored after the variable a
in memory. Bad idea.
&a-1
is the thing stored before a
in memory. Again, bad idea.
*(a+1)
is the thing at the location pointed to by a, plus one integer. That would be a[1]
, or 20.
*(ptr-1)
is a
, because ptr
is &a+1
, so ptr-1
is &a
. It's the pointer value of a
. Printing it as %d
is a mistake. If you were to say **(ptr-1)
, you'd get a more-meaningful 10
from the printf
.
*(t+1)
is also a
, as per the above but with the pluses and minuses switched.
Upvotes: -1