0

I saw an array with no size mentioned in the indices within a structure definition here. Then I tried repeating same for a sample code

struct some {
char a[];
};

and it throws an error: flexible array member in otherwise empty struct.

So I tried adding another member

struct some {
unsigned int x;
char a[];
};

and it compiles successfully; the observation that I made was sizeof(struct some) = sizeof(unsigned int). Which means, a does not get any share in memory.

  • What is flexible array in C?
  • What is the use of such arrays when there's no memory allocated?
  • Is it a C standard or GNU's option?

And, is there any use in using comma , in the end while initializing an array?

struct other array[] = {
  {....},
  {....},
};
Vishwajith.K
  • 85
  • 1
  • 10
  • Do not ask unrelated questions in one post. – Eric Postpischil Feb 16 '21 at 10:42
  • They can be useful for dynamically allocated memory, for example `struct some *foo = malloc(offsetof(struct some, a[100]));` will allocate a block of memory for a `struct some` with storage for 100 elements of the flexible array member `a`. – Ian Abbott Feb 16 '21 at 10:45

2 Answers2

1

What is flexible array in C?

Declaring an array with empty [] as the last member of a structure defines a flexible array member. The base size of the structure does not include any space for the array (although it may include padding that is necessary for alignment), but you can allocate as much space as desired when allocating space for the entire structure (using malloc or related routines) and use the array as if it contained as many elements as you have provided space for.

What is the use of such arrays when there's no memory allocated?'

You are responsible for allocating the space yourself.

Is it a C standard or GNU's option?

It is standard C.

And, is there any use in using comma , in the end while initializing an array?

It is a convenience to allow for easy editing or generations of lists of initializers using macros or other means.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
1

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).

icebp
  • 1,608
  • 1
  • 14
  • 24