Initialization of flexible array member in this way is not allowed as per C standard.

C11: 6.7.2.1 Structure and union specifiers (p20-21):

21 EXAMPLE 2 After the declaration:

struct s { int n; double d[]; };

the structure struct s has a flexible array member d. [...]

22 Following the above declaration:

struct s t1 = { 0 }; // valid
struct s t2 = { 1, { 4.2 }}; // invalid
t1.n = 4; // valid
t1.d[0] = 4.2; // might be undefined behavior

The initialization of t2 is invalid (and violates a constraint) because struct s is treated as if it did not contain member d. [...]

But, GCC allows the static initialization of flexible array:

GCC Manual: 6.17 Arrays of Length Zero:

Instead GCC allows static initialization of flexible array members. This is equivalent to defining a new structure containing the original structure followed by an array of sufficient size to contain the data. E.g. in the following, f1 is constructed as if it were declared like f2.

 struct f1 {
   int x; 
   int y[];
 } f1 = { 1, { 2, 3, 4 } };

 struct f2 {
   struct f1 f1; 
   int data[3];
 } f2 = { { 1 }, { 2, 3, 4 } };
Answer from haccks on Stack Overflow
Top answer
1 of 3
8

You cannot initialize a flexible array member. Per C 2018 6.7.2.1 18, in most situations, a flexible array member is ignored. This is one of those situations: In initialization, it is as if the member does not exist.

Creating a structure with a flexible array member in a declaration statement can only create a structure with zero members in the array. To create a structure with more members in the array, you should dynamically allocate space with malloc or a similar routine. Once you have allocated sufficient space, you may convert the pointer to a pointer to a Category and then assign (rather than initialize) values to its members, including elements of its flexible array member.

(Conceivably, there might be a horrible way to define a union containing a structure with a flexible array member in such a way that sufficient space is provided for elements of the array, by stuffing the union with a char array of the necessary size. You still could not initialize those elements, but you could assign to them. Do not do this.)

To set up some prototype Category objects, you could use:

static const Category category1 = {"Academic Registrar"};
static const Category category2 = {"Financial Services"};
static const Category category3 = {"IT Support", "IT"};
static const Category category4 = {"Parking Police", "PP"};
static const Category category5 = {"Coop Placement", "CP"};

Later, to create a Category with several Ticket elements, you could do:

Category *C = malloc(sizeof *C + nTickets * sizeof(Ticket));
// Test C for NULL in case malloc failed.

// Copy initial data into new Category.
*C = category3;

// Assign values to Ticket elements.
for (int i = 0; i < nTickets; ++i)
{
    C->ticket[i] = rand();
    C->timestamp = 0;
}

Note that you cannot create an array of Category objects, because they have flexible size, and objects in an array can only have a fixed size. So you can only work with one Category at a time. The C pointer above can only point to one Category, not an array of them. But the C->ticket member is an array of Ticket.

Note that I do not necessarily recommend copying data into a Category from prototypes that way. If the data is short, it could just be assigned in code. If the data is long, it might be better to use pointers to data instead of copying all the data into each one. Good solutions depend on circumstances. The above code is given just as an example.

2 of 3
4

For const structures of static duration, a workable approach in most cases is to declare a structure which has the same members as the FAM version, but with the flexible array member replaced by a suitably-sized array, and then construct a union which contains that type as well as the one with the Flexible Array Member. The Common Initial Sequence guarantees imply that either type may be used to inspect the common members, and if an implementation gives any heed whatsoever to footnote 88 of the C11 draft (N1570) which says the purpose of 6.5p7 is to specify the circumstance when things may alias, it will refrain from using the rule as an excuse to break such code, since references to storage that is never modified never alias (aliasing involves situations where re-ordering accesses to an object would affect the semantics thereof; if an object is never modified, the order of accesses will never have any observable effect).

In theory, an implementation would be allowed to place a flexible array member at a different offset from a fixed-sized array, but code could, if desired, use a static assertion to ensure that does not happen. A deliberately-obtuse interpretation might break things, but since the One Program Rule would allow deliberately-obtuse implementations to break just about any program, that's not really saying much.

Discussions

Question about combination of flexible array member and compound literal with explicit size
You can't. You could potentially do something along, but it's a trick and required code duplication: struct test_struct_10 { int len; uint8_t data[10]; }; struct test_struct *test = (struct test_struct*)(struct test_struct_10[1]){ { .len = 10, data = { 1,2,3 } } }; More on reddit.com
🌐 r/C_Programming
9
3
October 20, 2023
Is there a standard way to statically initialize flexible array members in C? - Stack Overflow
Most notable inotify() Linux system call returns an array of flexible array members. Is there a standard way to statically initialize flexible array members in C? More on stackoverflow.com
🌐 stackoverflow.com
c - Non-static initialization of a flexible array member? - Stack Overflow
GCC might have other views on the topic, but it isn’t portable. (In particular, if the array was static or at file scope, you might get away with it with GCC.) You can’t initialize VLA or FAM in a standard-conforming program. ... VLA = variable length array; FAM = flexible array member. More on stackoverflow.com
🌐 stackoverflow.com
c - Error: non-static initialization of a flexible array member in Some Cases but Not Others - Stack Overflow
I'm using the latest version of g++ to compile some test code involving an array of struct pointers where the structs contain an array. Compilation fails when I try to initialize the array of struct More on stackoverflow.com
🌐 stackoverflow.com
Top answer
1 of 3
19

No, flexible arrays must always be allocated manually. But you may use calloc to initialize the flexible part and a compound literal to initialize the fixed part. I'd wrap that in an allocation inline function like this:

Copytypedef struct person {
  unsigned age;
  char sex;
  size_t size;
  char name[];
} person;

inline
person* alloc_person(int a, char s, size_t n) {
  person * ret = calloc(sizeof(person) + n, 1);
  if (ret) memcpy(ret,
                  &(person const){ .age = a, .sex = s, .size = n},
                  sizeof(person));
  return ret;
}

Observe that this leaves the check if the allocation succeeded to the caller.

If you don't need a size field as I included it here, a macro would even suffice. Only that it would be not possible to check the return of calloc before doing the memcpy. Under all systems that I programmed so far this will abort relatively nicely. Generally I think that return of malloc is of minor importance, but opinions vary largely on that subject.

This could perhaps (in that special case) give more opportunities to the optimizer to integrate the code in the surroundings:

Copy#define ALLOC_PERSON(A,  S,  N)                                 \
((person*)memcpy(calloc(sizeof(person) + (N), 1),               \
                 &(person const){ .age = (A), .sex = (S) },     \
                 sizeof(person)))

Edit: The case that this could be better than the function is when A and S are compile time constants. In that case the compound literal, since it is const qualified, could be allocated statically and its initialization could be done at compile time. In addition, if several allocations with the same values would appear in the code the compiler would be allowed to realize only one single copy of that compound literal.

2 of 3
8

There are some tricks you can use. It depends on your particular application.

If you want to initialise a single variable, you can define a structure of the correct size:

Copy   struct  {
        int age;
        char sex;
        char name[sizeof("THE_NAME")];
    } your_variable = { 55, 'M', "THE_NAME" };

The problem is that you have to use pointer casting to interpret the variable as "person"(e.g. "*(person *)(&your_variable)". But you can use a containing union to avoid this:

Copyunion {
 struct { ..., char name[sizeof("THE_NAME")]; } x;
 person p;
} your_var = { 55, 'M', "THE_NAME" };

so, your_var.p is of type "person". You may also use a macro to define your initializer, so you can write the string only once:

Copy#define INIVAR(x_, age_, sex_ ,s_) \
   union {\
     struct { ..., char name[sizeof(s_)]; } x;\
     person p;\
    } x_ = { (age_), (sex_), (s_) }

INIVAR(your_var, 55, 'M', "THE NAME");

Another problem is that this trick is not suitable to create an array of "person". The problem with arrays is that all elements must have the same size. In this case it's safer to use a const char * instead of a char[]. Or use the dynamic allocation ;)

🌐
GNU
gnu.org › software › c-intro-and-ref › manual › html_node › Flexible-Array-Fields.html
Flexible Array Fields (GNU C Language Manual)
Under the C standard, a structure with a flexible array can’t be part of another structure, and can’t be an element of an array. GNU C allows static initialization of flexible array fields.
🌐
Reddit
reddit.com › r/c_programming › question about combination of flexible array member and compound literal with explicit size
r/C_Programming on Reddit: Question about combination of flexible array member and compound literal with explicit size
October 20, 2023 -

Hello everyone!

There is compound literal in C so i can easily declare array like this:

int arr[] = {1, 2, 3};

Or even specify it's length:

int arr[] = (int [10]) {1};

There is also a flexible array member support in struct, so i can do runtime initialization like this:

typedef struct 
{
 int len; 
 uint8_t Data[];
} struct_t;

struct_t test_struct = 
{
 .len = 3,
 .Data = {1, 2, 3} 
};

However i cannot combine flexible array member with explicit compound literal size:

struct_t test_struct = 
{
 .len = 10,
 .Data = (uint8_t [10]) { 0 } 
};

This code gives me error "initialization makes integer from pointer without a cast" in GCC. How can i specify compound literal size for flexible array member? That would be very handy for certain runtime initialization.

Top answer
1 of 2
4

You can't do it with a flexible array member.

Instead, you can use char **argv and initialize it using compound literals.

typedef struct {
    char **argv;
} Entry;

const Entry table[] = {
    { (char *[]) { "a", NULL } },
    { (char *[]) { "a", "b", "c", NULL } }
};

I added NULL to each of the arrays so the application can tell their lengths (the real argv has this as well).

2 of 2
0

You do not store the count of elements of argv. How would you know that the first one has 1 element, and the second one has 3? You have to store that, for example, in another array member.

You can define a structure that has the proper exact same static memory layout as the array of structures with flexible array members that you want to have. Then you can then alias the structure with a pointer to Entry, and use that as an array of entries. Following example does that:

#include <stdlib.h>
#include <assert.h>
#include <stdalign.h>
#include <stddef.h>
#include <stdio.h>

typedef struct {
    unsigned len;
    char *argv[];
} Entry;

// sane iterating
static_assert(alignof(Entry) == alignof(char *), "");

typedef struct {
    unsigned len;
    char *argv[1];
} Entry_1;
static_assert(alignof(Entry_1) == alignof(Entry), "");
static_assert(sizeof(Entry_1) == sizeof(Entry) + 1 * sizeof(char *), "");

typedef struct {
    unsigned len;
    char *argv[3];
} Entry_3;
static_assert(alignof(Entry_3) == alignof(Entry), "");
static_assert(sizeof(Entry_3) == sizeof(Entry) + 3 * sizeof(char *), "");

typedef struct {
    Entry_1 e1;
    Entry_3 e3;
} Entry_init_1_3;
static_assert(offsetof(Entry_init_1_3, e3) == sizeof(Entry_1), "");

const Entry_init_1_3 entry_init_1_3 = {
    { 1, { "a", } },
    { 3, { "b", "c", "d", } },
};

const Entry *const table = (const void *)&entry_init_1_3;
//                         ^^^^^^^^^^^^^^^ I hope I know what I am doing.
const Entry *const table_end = (const Entry*)((const char*)table + sizeof(entry_init_1_3));

const Entry *table_next(const Entry *it) {
    return (const Entry *)(
        (const char *)it + sizeof(Entry) + it->len * sizeof(char *)
    );
}

int main() {
    unsigned entry_idx = 0;
    for (const Entry *it = table;
            it != table_end;
            it = table_next(it), ++entry_idx
    ) {
        for (unsigned x = 0; x < it->len; ++x) {
            fprintf(stderr, "table[%d].argv[%d] = %s\n",
                entry_idx,
                x,
                it->argv[x]
            );
       }
    }
}

Code outputs:

table[0].argv[0] = a
table[1].argv[0] = b
table[1].argv[1] = c
table[1].argv[2] = d

Most notable inotify() Linux system call returns an array of flexible array members.

Is there a standard way to statically initialize flexible array members in C?

No.

If not, is there a preferred way?

Don't use flexible array members. Use pointers, as presented in the other answer.

Top answer
1 of 2
8

If this is an exam, and you must use a Flexible Array Member, then as I indicated in the comments and as @rici explained in his answer, the purpose of the FAM is to provide a placeholder of a given type that then allows you to allocate storage for the struct itself plus storage for some number of your FAM type in a single-allocation. The advantage this provides is a single-allocation/single-free rather than separate allocation for the struct and then allocating for some number of your needed type.

(prior to the FAM, there was what was referred to as the struct hack where an array of size 1 was used in its place for much the same purpose)

The type is critical to how you deal with and allocate for your FAM. In your case your FAM is item *items[]; (an array of pointers to type item -- Item in your code) So you allocate for the struct and then X number of pointers to item.

To initialize each member of items, you must assign a valid address to a struct of type item (or you can separately allocate, copy to the new block, and then assign the starting address for that block to a pointer in items) In your case, you have an array of struct item called fruits. To assign to items, you must assign the address of each struct to each element in items (remember you have storage for pointers, not storage for struct item -- and you must ensure fruits remains in scope for the duration of your use of basket)

Putting those pieces together, you could do something similar to the following:

Copy#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct {
    int low, high;
    char label[16];
} item;

typedef struct {
    size_t length;
    item *items[];
} item_coll;

char *find_first_in_range(item_coll *ic, int rlow, int rhigh) 
{
    for (size_t i = 0; i < ic->length; i++)
        if (ic->items[i]->low >= rlow && ic->items[i]->high <= rhigh)
            return ic->items[i]->label;
    return NULL;
}

int main() {

    item fruits[] = {
        {10, 20, "Apple"},
        {12, 14, "Pear"},
        { 8, 12, "Banana"},
        { 2,  4, "Grape"},
        {15, 35, "Watermelon"}
    };
    size_t nfruits = sizeof fruits/sizeof *fruits;  /* avoid magic-numbers */
    /* allocate storage for basket + nfruits pointers */
    item_coll *basket = malloc (sizeof *basket + 
                                nfruits * sizeof *basket->items);
    if (!basket) {  /* validate allocation succeeded */
        perror ("malloc-basket+5_item_coll");
        return 1;
    }
    basket->length = nfruits;   /* assign length */

    for (size_t i = 0; i < nfruits; i++)  /* assign addresses to structs */
        basket->items[i] = &fruits[i];

    char *label = find_first_in_range (basket, 12, 15);  /* save return */
    if (label)  /* validate not NULL before printing */
        printf ("%s\n", label);

    free (basket);  /* don't forget to free the memory you allocate */

    return 0;
}

(note I have simply used typedefs and removed the struct labels themselves -- it's up to you. Further, you should validate the return from find_first_in_range is not NULL before printing.)

Example Use/Output

Also note I've bracket the high/low range for

Copy$ ./bin/fam_initialization
Pear

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

Copy$ valgrind ./bin/fam_initialization
==6887== Memcheck, a memory error detector
==6887== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6887== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6887== Command: ./bin/fam_initialization
==6887==
Pear
==6887==
==6887== HEAP SUMMARY:
==6887==     in use at exit: 0 bytes in 0 blocks
==6887==   total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==6887==
==6887== All heap blocks were freed -- no leaks are possible
==6887==
==6887== For counts of detected and suppressed errors, rerun with: -v
==6887== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

Look things over and let me know if you have further questions.

2 of 2
3

I strongly suspect you intended this definition:

Copytypedef struct item_coll {
    size_t length; Item *items;
} ItemColl;

i.e. a length and an array of Items, not an array of pointers to Item.

As written, the array of pointers does not have any specified length, which makes the struct effectively incomplete; the compiler cannot tell hiw big it is so you can never actually define one. C11 allows this sort of declaration for convenience. The array of unspecified length -- the "flexible array member" -- must come at the very end of the struct and the struct itself cannot be used inside another struct.

You can use a struct with a flexible array member as a kind of base for a concrete dynamically allocated object whose size can be computed as sizeof (Struct) + n * sizeof (ArrayElement). This is occasionally useful as an optimisation and it is legal; all I will say is that its apparent advantages need to be weighed against the code complications it creates.

🌐
GNU
gcc.gnu.org › onlinedocs › gcc-3.1.1 › gcc › Zero-Length.html
Using the GNU Compiler Collection (GCC)
As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero. Flexible array members may only appear as the last member of a struct that is otherwise non-empty. GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible ...
Find elsewhere
🌐
Rip Tutorial
riptutorial.com › flexible array members
C Language Tutorial => Flexible Array Members
The flexible array member is considered ... a structure type containing a flexible array member, but you must not attempt to initialize the flexible array member since ......
🌐
Quora
quora.com › Why-cant-you-initialize-a-flexible-array-member-in-structs
Why can't you initialize a flexible array member in structs? - Quora
Answer (1 of 3): Because a struct is nothing more than a fixed chunk in memory. all that a struct does is. put several variables of Known space into an address. example struct struct_example { int (4 bytes) x; float (4 bytes) y; char[] (8 bytes) name}; then if i define the variable struct_ex...
🌐
LLVM
lists.llvm.org › pipermail › cfe-users › 2018-February › 001237.html
[cfe-users] Static initialization of flexible array members
March 30, 2018 - Hi! In the user's manual, section GCC extensions not implemented yet, I read: > clang does not support static initialization of flexible array members. This appears to be a rarely used extension, but could be implemented pending user demand.
🌐
LLVM
reviews.llvm.org › D123649
⚙ D123649 Allow flexible array initialization in C++.
Flexible array initialization is a C/C++ extension implemented in many compilers to allow initializing the flexible array tail of a struct type that contains a flexible array. In clang, this is currently restricted to C. But this construct is used in the Microsoft SDK headers, so I'd like to ...
🌐
GNU
gcc.gnu.org › onlinedocs › gcc-3.3.4 › gcc › Zero-Length.html
Arrays of Length Zero - GCC, the GNU Compiler Collection
A structure containing a flexible ... (However, these uses are permitted by GCC as extensions.) GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays....
🌐
Narkive
gcc-help.gcc.gnu.narkive.com › T8njTEOG › initialization-of-nested-flexible-array-members
Initialization of nested flexible array members
The following code did compile under 2.95 but doesn't under 3.3.1: typedef struct { char a; char b; int flexo[]; } EnclosedStruct; typedef struct { int a; int b; EnclosedStruct s; } MyStruct; int main(int argc, char * argv[]) { MyStruct toto = { 10, 20, { 'a', 'b', { 0, 1, 2, 3 } } }; } $ gcc test.c -o test test.c: In function `main': test.c:17: error: initialization of flexible array member in a nested context test.c:17: error: (near initialization for `toto.s.flexo') test.c:17: error: non-static initialization of a flexible array member test.c:17: error: (near initialization for `toto.s') This is however something we *really* need to do, and consider safe since the flexible member is located at the end of the enclosing structure.
🌐
GNU
gcc.gnu.org › onlinedocs › gcc-9.1.0 › gcc › Zero-Length.html
Using the GNU Compiler Collection (GCC): Zero Length
Non-empty initialization of zero-length ... in array” is given, and the excess elements (all of them, in this case) are ignored. GCC allows static initialization of flexible array ......
Top answer
1 of 2
3

First, initialing a flexible array member is a non-standard extension. GCC allows it in cases of objects with static storage duration, i.e. those declared at file scope or with the static keyword, as it can set aside the appropriate amount of space for it at compile time.

Regarding why this generates an error:

const HasArray* collection[] = {
    &(HasArray){.num_elements = 2, .elements = {51, 17}},
    &(HasArray){.num_elements = 4, .elements = {1, 42, 88, 73}}
};

There are ambiguities regarding the storage duration of compound literals prior to C23. In GCC in particular, they always have automatic storage duration. And because GCC only allows flexible array member initialization for objects with static storage duration, you get an error.

The C23 standard clarifies this by stating that the storage duration of a compound literal is that of the enclosing scope. So if you were to compile with GCC 13 or later which has full C23 support, the above would compile cleanly.

2 of 2
3

In standard C, flexible array members (Are flexible array members valid in C++?) are defined as the last element of a struct with an unspecified size, allowing for dynamic sizing.

This occurs because flexible array members cannot be initialized in this manner. The C standard mandates that structures with FAMs must be dynamically allocated to define the size of the flexible array. Static or compound literal initialization of FAMs is not permitted.

In your initial approach:

HasArray x = {.num_elements = 2, .elements = {51, 17}};
HasArray y = {.num_elements = 4, .elements = {1, 42, 88, 73}};
const HasArray* collection[] = {&x, &y};

Some compilers allow this because x and y are defined with known sizes at compile time (because every time you will have the same size of x and y; it is not dynamic like, for example, a scanf with the size or something like that). However, this usage is non-standard and relies on compiler-specific extensions. The C standard does not define behavior for initializing FAMs in this way, making the code non-portable.

So, to be compliant with the standard, you have to dynamically allocate memory for structures with FAMs:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct {
    uint16_t num_elements;
    uint8_t elements[];
} HasArray;

int main() {
    HasArray *x = malloc(sizeof(HasArray) + 2 * sizeof(uint8_t));
    if (x == NULL) {
        perror("Failed to allocate memory");
        return EXIT_FAILURE;
    }
    x->num_elements = 2;
    x->elements[0] = 51;
    x->elements[1] = 17;

    HasArray *y = malloc(sizeof(HasArray) + 4 * sizeof(uint8_t));
    if (y == NULL) {
        perror("Failed to allocate memory");
        free(x);
        return EXIT_FAILURE;
    }
    y->num_elements = 4;
    y->elements[0] = 1;
    y->elements[1] = 42;
    y->elements[2] = 88;
    y->elements[3] = 73;

    const HasArray* collection[] = {x, y};

    printf("%d\n", collection[0]->elements[0]);
    printf("%d\n", collection[0]->elements[1]);

    free(x);
    free(y);
    return 0;
}

So this will give you:

$ gcc main.c
$ ./a.out
51
17
🌐
SEI CERT
wiki.sei.cmu.edu › confluence › x › GtcxBQ
DCL38-C. Use the correct syntax when declaring a flexible array member - SEI CERT C Coding Standard - Confluence
Flexible array members are a special type of array in which the last element of a structure with more than one named member has an incomplete array type; that is, the size of the array is not specified explicitly within the structure. This "struct hack" was widely used in practice and supported ...
🌐
Stack Overflow
stackoverflow.com › questions › tagged › flexible-array-member
Newest 'flexible-array-member' Questions - Stack Overflow
Compilation fails when I try to initialize the array of struct ... ... Ideally, I want to have something like this: struct S { int other_member; // not relevant to question // ... union { void *ptr; char buf[]; }; }; That is, a struct with either a ... ... Paul J. Lucas ... I have a struct like this: typedef struct { int num_files; audio_file files[]; } message_files; and I want to create a macro so I don't have to specify the number of files of a statically known ...
🌐
GNU
gcc.gnu.org › legacy-ml › gcc-help › 2003-10 › msg00085.html
Alexandre Courbot - Initialization of nested flexible array members
October 7, 2003 - The following code did compile under 2.95 but doesn't under 3.3.1: typedef struct { char a; char b; int flexo[]; } EnclosedStruct; typedef struct { int a; int b; EnclosedStruct s; } MyStruct; int main(int argc, char * argv[]) { MyStruct toto = { 10, 20, { 'a', 'b', { 0, 1, 2, 3 } } }; } $ gcc test.c -o test test.c: In function `main': test.c:17: error: initialization of flexible array member in a nested context test.c:17: error: (near initialization for `toto.s.flexo') test.c:17: error: non-static initialization of a flexible array member test.c:17: error: (near initialization for `toto.s') This is however something we *really* need to do, and consider safe since the flexible member is located at the end of the enclosing structure.