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?
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 aftera
in memory (which doesn't exist), and&a-1
is creating a pointer to the array-of-5-int
immediately beforea
in memory (which also doesn't exist). In memory, it looks like this (where each cell represents oneint
):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 the10
value. Adding one to it then makes a pointer pointing at the nextint
-a+1
points at the20
value.*(a+1)
then fetches that value, so the first number printed is 20.As
ptr
is also a pointer-to-int
, that means thatptr - 1
creates a pointer to theint
immediately beforeptr
- in this case, it'll be pointing at the 50. So the second number printed is 50.Similarly,
t + 1
creates a pointer to theint
immediately aftert
- 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.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" bysizeof(a)
(which might e.g. be 20 ifint
are 4 bytes and the compiler needs no padding for alignment purposes -- reasonable hypotheses, though far from certain of course.So, after
ptr
is a pointer to int at the memory address "sizeof(a) more than the address a", andt
similarly for "sizeof(a) less than the address of a". Therefore...:Quite possibly a segmentation violation, otherwise
20
followed by two completely arbitrary integer values. Sinceptr
andt
are pointers toint
, the address arithmetic scaling for their-1
and+1
does not compensate that done on&a
(the scaling in terms of memory addresses is bysizeof(int)
, notsizeof(a)
!), soptr-1
andt+1
are pointing to (alleged;-)int
s that are respectively "a fewint
s after the end ofa
" and "a fewint
s before the start ofa
".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 ofa
; so the output (unless there's a segmentation fault, which @NullUserException thinks is very unlikely but on this point we disagree;-) would start with20 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;-)."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:
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).
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 variablea
in memory. Bad idea.&a-1
is the thing stored beforea
in memory. Again, bad idea.*(a+1)
is the thing at the location pointed to by a, plus one integer. That would bea[1]
, or 20.*(ptr-1)
isa
, becauseptr
is&a+1
, soptr-1
is&a
. It's the pointer value ofa
. Printing it as%d
is a mistake. If you were to say**(ptr-1)
, you'd get a more-meaningful10
from theprintf
.*(t+1)
is alsoa
, as per the above but with the pluses and minuses switched.