I have a struct that looks like this:
struct packet {
int a;
char data[500];
};
typedef struct packet packet_t;
I\'m a little confused
I don't know why this was voted down, it's a good question that exposes a confusing behaviour of C.
The confusion comes because normally when you define an array a real pointer is created:
char data[100];
printf("%p\n", data); // print a pointer to the first element of data[]
printf("%p\n", &data); // print a pointer to a pointer to the first element of data[]
So on a typical 32 bit desktop system 4 bytes are allocated for data
, which is a pointer to 100 chars. Data
, the pointer, itself exists somewhere in memory.
When you create an array in a struct no pointer is allocated. Instead the compiler converts references to packet.data
into a pointer at runtime but does not allocate any memory for storing it. Rather it just uses &packet + offsetof(data)
.
Personally I would prefer the syntax to be consistent and require an ampersand, with packet.data generating some kind of compile time error.
Under most circumstances, an expression that has type "N-element array of T
" will be converted to an expression of type "pointer to T
", and its value will be the address of the first element in the array. This is what happens in the first printf
call; the expression packet.data
, which has type char [500]
, is replaced with an expression of type char *
, and its value is the address of the first element, so you're effectively printing &packet.data[0]
.
One exception to this rule occurs when the array expression is an operand of the unary &
operator; the type of the expression &packet.data
is char (*)[500]
(pointer to 500-element array of char
).
The address of an array is the same as the address of the first element, so both calls to printf
display the same value; it's just that the types of the expressions are different. To be pedantic, both expressions should be cast to void *
in the printf
calls (the %p
conversion specifier expects a void *
argument):
printf("%p\n", (void *) packet.data);
printf("%p\n", (void *) &packet.data);
Because it's the only reasonable thing to do besides making &packet.data cause a compile error. Integer a and the data char array are laid out sequentially in the stack, there is no dereferencing involved.
That's because array decays to a pointer pointing to first element in the sequence. So, packet.data
address location is same as &packet.data
or &packet.data[0]
.