Even though they aren't the same thing, there is a close relationship between arrays and pointers in C. The array subscripting operation a[i]
is defined in terms of pointer arithmetic:
a[i] == *(a + i)
That is, take the address a
, offset i
elements of the array's base type from that address, and dereference the result. For example, if a
is an array of int
, the expression a + 1
evaluates to the address of the next integer object following the one stored at a
, which may be anywhere from 2, 4, or 8 bytes away.
Arrays are not pointers; however, except when it is the operand of the sizeof
or unary &
operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element in the array.
So, given the code
int a[10];
a[2] = 2;
In the statement a[2] = 2
, the expression a
is not the operand of the sizeof
or unary &
operators, so it is converted ("decays") from type int [10]
to int *
, and it evaluates to the address of the first element of a
. We then offset 2 elements of type int
from that address and assign the value 2 to that location. Note that this conversion applies to the expression a
, not the array object to which it refers.
So how does all that relate to your code?
In C, a non-bitfield object is composed of a contiguous sequence of one or more bytes. Objects of char
type take up 1 byte by definition, so an object of any multibyte type (int
, long
, float
, double
, etc.) can be treated as an array of char
(or unsigned char
).
A picture may help - I took your code and used a little utility I wrote to dump the contents of each object in memory:
Item Address 00 01 02 03
---- ------- -- -- -- --
a 0x7ffffa8a29cc 01 04 00 00 ....
p 0x7ffffa8a29c0 cc 29 8a fa .)..
0x7ffffa8a29c4 ff 7f 00 00 ....
p0 0x7ffffa8a29b8 cc 29 8a fa .)..
0x7ffffa8a29bc ff 7f 00 00 ....
The binary representation of 1025
is 0x0401
. As you can see, the object a
is 4 bytes wide and contains the byte sequence {0x01, 0x04, 0x00, 0x00}
. This is on an x86 system, which is little-endian, so the least significant byte comes first in the sequence.
Both p
and p0
store the address of a
. I'm on a 64-bit system, so pointer values are 8 bytes wide.
*p0
evaluates to the value of first byte in a
, which in this case is 0x01
. p0[1]
is equivalent to *(p0 + 1)
, and evaluates to the value of the second character value following p0
, which in this case is 0x04
.