The values you get obviously come from the bytes array, but why do you get these values?
unsigned char bytes[12] = { 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12};
Here bytes
can be viewed as an unsigned char*
pointing to the first element of the array, i.e. 1. Now let's break this pointer arithmetic down, shall we?
First of all let's change the type of i
from char*
to unsigned char*
, because that's what it really is, or should be.
unsigned char *i;
i = (unsigned char *) (&(bytes[4]));
The brackets mean access the n-th element, which is the 5th element, because indices start at 0. This means we can rewrite them to a simple addition and dereference.
unsigned char *i;
i = (unsigned char *) (&(*(bytes+4)));
Wait, do we really get the address of the value we obtained from dereferencing the pointer? Yes, we do. We apply both the operation and its inverse. What does that mean? We can simply leave both parts out!
unsigned char *i;
i = (unsigned char *) (bytes+4);
So now i
is a pointer to the 5th element of bytes
, because we started with a pointer to the first element and add 4 to it. Now i[2]
is the same as *(i+2)
. If i
is a pointer to the 5th element, i+2
is a pointer to the 7th element, subsequently i[2]
is the 7th element of bytes
, which happens to be 7.
Now that we got that out of the way, let's head on to the next problem, it's slightly trickier, though. Let's change the code so it's clearer what it does.
struct i_and_c {int x;char c;};
struct i_and_c *p;
p = (struct i_and_c *) (&(bytes[5]));
*p
is indeed a pointer to a struct
of type i_and_c
. Let's simplify this the same way as we did above.
struct i_and_c {int x;char c;};
struct i_and_c *p;
p = (struct i_and_c *) (bytes+5);
Alright, so now we have a pointer to a struct i_and_c
that starts at the 6th element of the bytes
array. WARNING: This is undefined behavior, really, on most machines it will behave like described in the following section, though.
The struct is made up of an int followed by a char. I assumesizeof(int) = 4
and that there is no padding between the int
and the char
, which both needs to be assumed for your given result to be correct.
This means that the int
in the struct will reach from the 6th element of bytes to the 9th element (including it). And the char
will come after that, which means it's the 10th element. Now p->c
is the same as (*p).c
which means you want to get that char. The 10th element of bytes
is 10, so that's what you get as a result.
I hope my explanations helped :)