You'll probably want to refer to this: Operators in C and C++ - Operator precedence
The question didn't specify, but we will assume that pointers are 4 bytes - sizeof(void*) == 4
.
1.
int **i=(int **)0x04;
**i = ???
i
is a pointer to a (pointer to int
). When we say **i
, we are de-referencing the pointer twice - or reading the value that the pointer points to.
First note that **i == *(*i)
. So we first read a pointer-sized (4-byte) value from memory at address 0x04. This is 10 00 00 00
- interpreted as a little-endian value, that is 0x10. So now we are left with *((int*)0x10)
. That means we read an int
-sized (4-byte) value from memory at address 0x10. 78 0c 00 00
interpretted in little-endian is the value 0xC78.
2.
struct i2c {
int i;
char *c;
} *p = (struct i2c*)0x10;
p->c[2] = ???
This one's a little trickier. I'll assume that you understand that structures are just a collection of variables that (excluding padding, which doesn't apply here) are laid out one after another in memory.
Our pointer p
points to a struct i2c
object at 0x10 in memory. That means at address 0x10 is the int
, named p->i
. And immediately following that, at address 0x14, is the char *
, named p->c
.
The expression p->c[2]
means: "First get the char *c
from the structure that p
points to. Then, get the char
at index 2 from the array that p->c
points to."
So first, we'll get p->c
. I already mentioned this char*
is at address 0x14. There we find the pointer 08 00 00 00
, or 0x8.
Now, we have a char *
that points to address 0x8, and we want the char
at index 2 in that array. To get the address of an array element, we use this formula:
&(x[y]) == (char*)x + (y * sizeof(x[0]))
In other words, the offset (from the start of the array) of the n
th element in the array is n
times the size of each element.
Since char
s are 1 byte, p->c[2]
is at 0x8 + 2 = 0xA
. There we find the value 0x62
, which is the ASCII character 'b'
.
3.
short **pps=(short **)0x1c;
&(*pps)[1] = ???
With our knowledge operator precedence, we read &(*pps)[1]
as "First dereference pps
, which is a pointer-to-short (or an array of shorts). Then, we want the address of the element at index 1."
At address 0x1C we have 18 00 00 00
, or 0x18. So now we have a pointer to an array of shorts, and this array starts at address 0x18. Using our formula from above, and knowing that short
s are 2 bytes in size, we calculate element 1 to be at address 0x18 + (1 * 2) == 0x1A
.
At address 0x1A is 4c 03
, or 0x034C. However, the problem wasn't asking us for the value of element 1 - that would be solving (*pps)[1]
. Instead, it asked for &(*pps)[1]
or the address of that element. So, we simply go back to the end of the previous paragraph, where we said the address was 0x1A.
4.
++p->i = ??
For this one, you really need to know the operator precedence. It should be clear that this could be interpreted two different ways:
- a) Increment the pointer
p
1, and then dereference p
to get its member i
- b) Dereference
p
to get its member i
, then increment the integer value
From the precedence chart, we see that ->
has a precedence of 2, while ++
(the Prefix increment), has a lower precedence of 3. That means we need to apply the ->
first, then increment. Thus, option b) was correct.
So, first let's get p->i
. We already said in part 2. that since p
points to address 0x10, and i
is the first member in struct i2c
, p->i
is at address 0x10. There we find 78 0c 00 00
, or 0xC78.
Finally, we need to apply the ++
operator, and increment that value to 0xC79.
.....
1 - Pointer arithmetic means you treat a pointer like an array. So p + 3
doesn't mean "p
plus 3 bytes", it means &p[3]
, or "p
plus (3 * sizeof(*p)) bytes".