This is what is known as the "struct hack". It's a trick that allows you to store variably-sized data in a struct
instance.
You make the last member an array of size 1, like so:
struct foo { int i; char c[1] };
Assuming a 4-byte int
, this type is 5 bytes wide (although it will likely take up 8 bytes to satisfy any alignment requirements), and an instance of struct foo
would look like this:
+---+
i: | |
+---+
| |
+---+
| |
+---+
| |
+---+
c: | |
+---+
However, if you allocate memory for it dynamically with malloc
or calloc
, you can allocate more memory than just what's needed for the struct
type and that extra memory will be considered part of the array (since struct
elements are guaranteed to be laid out in the order declared and array types don't enforce sizes).
struct foo *p = malloc( sizeof *p + strlen( "hello" ));
p->i = 1;
strcpy( p->c, "hello" );
So we allocate enough memory for the struct
type (5 bytes) plus enough memory to store "hello"
, which gives us (assuming little-endian)
+---+ ----+
i: | 1 | |
+---+ |
| 0 | |
+---+ |
| 0 | +---- size of struct foo
+---+ |
| 0 | |
+---+ |
c: |'h'| |
+---+ ----+
|'e'| |
+---+ |
|'l'| |
+---+ |
|'l'| +---- Extra memory for "hello"
+---+ |
|'o'| |
+---+ |
| 0 | |
+---+ ----+
Why do we make c
an array of size 1 instead of a pointer? If we made c
a pointer, like
struct foo { int i; char *c };
then this trick doesn't work, because all c
can store is an address, not data.
C allows "flexible array members", where a size isn't needed in the declaration:
struct foo { int i; char c[] };
However, C++ does not (yet) support this, so you have to specify a non-zero size.