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.