For the first question: flexible arrays are useful for reducing memory allocations (instead of allocating a structure and a buffer you allocate just a structure).
An example may make things more easy to understand.
Let's imagine the following scenario: we have a custom file format in which the first 32 bit integer represents a size N
and the next N
bytes are some payload we are interested in, so:
4 // the next 4 bytes are some data we need to parse
1 2 3 4
8 // the next 8 bytes represent another chunk of data
1 2 3 5 6 7 8
This can be represented by the following structure:
struct file_chunk {
int count;
char *data;
}
We don't know how many chunks a file will have, so for each chunk we have to do two allocations: one for a file_chunk
structure, and another for the data
buffer:
file_chunk *allocate_file_chunk(int Count) {
struct file_chunk *chunk = malloc(sizeof(*chunk));
chunk->data = malloc(Count);
return chunk;
}
But we know that we always have a 32-bit integer N
followed by N
bytes, so we can do the following:
struct file_chunk {
int count;
char data[]
}
file_chunk *allocate_file_chunk(int Count) {
return malloc(sizeof(struct file_chunk) + Count * sizeof(char));
}
Now our structure looks exactly like the section we read from the file.
The feature was introduced in C99. Alternatively, you may see structures defined with an array of size 1
for compilers that do not support flexible array members:
struct file_chunk {
int count;
char data[1]
}
This makes computing the size needed for an allocation slightly more complicated:
size_t file_chunk_size = sizeof(struct file_chunk) + Count * sizeof(char) - sizeof(char);
As for the second question: you can omit the trailing ,
. It just makes adding new entries at the end easier (and reduces the lines changed when looking at a diff).