This question already has an answer here:

Recently I came across a structure definition,

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[0];

and now I don't know the reason for list[0] being declared. What I am interested in is why is this used. Does it have any advantage? If yes, what is it?

marked as duplicate by Antti Haapala c Nov 18 '17 at 7:10


  • 2
    Zero-size objects are illegal in C. Either use [1] and waste a tiny bit of space (or calculate to make up for it), or use [] (but then your code requires a C99 compiler). – R.. Jan 14 '11 at 17:24
  • Here's the section from the gcc manual on Arrays of Length Zero: gcc.gnu.org/onlinedocs/gcc/Zero-Length.html – Pierz Jun 29 '16 at 17:01

The use is for dynamic-length arrays. You can allocate the memory using malloc(), and have the array reside at the end of the structure:

struct arr *my_arr = malloc(sizeof *my_arr + 17 * sizeof *my_arr->list);
my_arr->cnt = 17;
my_arr->list[0].size = 0;
my_arr->list[1].name = "foo";

Actually being able to use 0 for the length is (as pointed out in a comment) a GCC extension. In C99, you can leave out the size literal altogether for the same effect.

Before these things were implemented, you often saw this done with a length of 1, but that complicates the allocation a bit since you must compensate when computing the memory needed.

  • 5
    To add to that, being a 0-length array, list doesn't contribute to the size of the structure. sizeof(struct arr) == 4 – Jeff Mercado Jan 14 '11 at 11:56
  • 4
    The ability to use a length 0 is a GCC feature. The C99 equivalent is to leave the length out completely, as in struct { ... } list[]; – Bart van Ingen Schenau Jan 14 '11 at 12:05
  • struct list { int size; int *name; }; struct arr { int cnt; struct list *list_ptr; }; is this an equivalent? – hue Jan 14 '11 at 12:34
  • 3
    @hue: no - that would have your list array stored and malloc'ed elsewhere in memory. This has the list immediately following the structure. – ijw Jan 14 '11 at 13:12
  • 4
    @hue: Er... You just got two answers that describe that advantage. It lets you allocate the memory for the struct and for variable-length the array at the end of the struct as one continuous memory block, with one call to malloc. If you used a pointer, you'd either have to allocate memory separately (two malloc calls, likely non-continuous) or use some other tricks (to achieve proper alignment etc.) – AnT Jan 14 '11 at 18:12

It is called "struct hack". You can search for it on SO or on the Net


Note that formally it is always illegal to declare arrays of size 0 in C. The code you provided formally is not even compilable. Most C compilers will accept 0-sized array declaration as an extension though, specifically because it is often used in "lazy" version of "struct hack" (it can rely on sizeof to determine how much memory to allocate, since 0-sized array supposedly does not affect the total size of the struct).

An arguably better implementation of struct hack uses an array of size 1

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[1];

It is "better" because it is formally compilable at least. In order to allocate memory for a struct with N elements in the list, standard offsetof macro is used

arr *a = malloc(offsetof(arr, list) + N * sizeof a->list);

In C99 version of the language specification the "struct hack" is supported through size-less array declaration (with empty []), since 0-sized array declarations are illegal in C99 as well.

  • Is there anything in the standard that would forbid a compiler which sees a declaration unsigned char foo[1]; from compiling all accesses to foo[x] as though they were foo[0]? While people answering "struct-hack" questions regard as academic the issue of whether the size-1-array version is "undefined behavior", the aforementioned optimization could be useful, especially in some embedded-systems contexts, if it's legal. Would it be (adding in the caveat that a compiler might want to explicitly disable it for the last element of an indirectly-accessed struct)? – supercat Jan 13 '12 at 23:54
  • @supercat if I understand your question, it would silently cause some strange behavior, that &(foo[999]) == &(foo[0]) for example. It's assumed that a[b] === (&a[0])+b – Steven R. Loomis Feb 27 '13 at 6:46
  • @StevenR.Loomis: The assumption you only make only holds if b is less than the number of elements in a. If a pointer yielded by an array within a structure may only be indexed within the smaller of either the array's declared size or the allocated space, then the scenario you describe would be Undefined Behavior. If I were in charge of standards, I would specify that accessing an array outside its specified range would be Undefined Behavior except in the specific case that a single-element array at the end of an struct may use a non-zero index if that struct is... – supercat Feb 27 '13 at 15:52
  • ...the last item in a section of memory received by malloc, calloc, etc. Such a rule would require that compilers continue to support old code using the "struct hack", but would permit most of the optimizations that struct array enforcement would permit (just just the single-element case I mentioned, but also many other scenarios involving aliasing, etc. For example, given struct {int a[1], b;} foo; foo.b=3; x=foo.a[something()]; foo.b=0; should the compiler be required to store the 3 into memory before accessing foo.a[], or should it be allowed to omit the store? – supercat Feb 27 '13 at 15:57
  • @supercat but the runtime doesn't know how many elements are "in" a, my assumption was just a restatement of how I understand C to interpret array subscripts. I would actually say that the scenario is defined behavior (I'm utilizing it right now). Now the value of b[999] or b[-100] may be undefined, but the behavior I would hold is defined. I would not expect the compiler to detect range errors here. – Steven R. Loomis Feb 27 '13 at 17:19

Another advantage is if your structure describes on-disk/on-network data. If cnt is 0, the data size may only be the length of cnt.

I'm here just to confirm what I dreaded, that list[0] is not valid.
