2

Quoting from this site,

Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object.

Code:

 struct line {
   int length;
   char contents[0];
 };

 struct line *thisline = (struct line *)malloc(sizeof (struct line) + this_length);
 thisline->length = this_length;

I really did not understand what they have meant by this: "last element of a structure that is really a header for a variable-length object". Can someone elaborate on that sentence?

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • I thought normally you answer questions not the other way around :D (p.s. good question) – Rizier123 Dec 28 '14 at 11:15
  • 2
    A header is a thing that is at the beginning of something. You have a variable amount of memory that you allocate dynamically; at the beginning of it are your normal struct fields (the header), and the remainder of the memory is the array. – Kerrek SB Dec 28 '14 at 11:15
  • 2
    The thing is that you can `malloc` more space than just `struct line`, and then, using the fact that memory returned by `malloc` is contiguous, refer to that extra space via `thisline->contents[i]`. – Daniel Kamil Kozar Dec 28 '14 at 11:16
  • @KerrekSB , So I can use `contents` as if it were a member of the structure having size `this_length`? – Spikatrix Dec 28 '14 at 11:27
  • 1
    @CoolGuy Yes, that's exactly how it works. – Sergey Kalinichenko Dec 28 '14 at 11:27
  • [Do not cast the result of malloc in C](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – phuclv Dec 28 '14 at 12:22

3 Answers3

4

Zero-length arrays (which have been replaced with flexible array members in C99) let you allocate structures with variable size in a single allocation instead of two allocations. Without flexible array members you would be forced to do this:

struct line {
   int length;
   char *contents;
};

struct line *thisline = malloc(sizeof (struct line));
thisline->length = this_length;
thisline->contents=malloc(this_length);

Flexible array member saves you from making the second allocation, and also from having to call free a second time.

In addition to its convenience, this little trick helps you save on memory overhead. Each time you allocate a block of memory, malloc needs to store some "bookkeeping" information for the use of free. In addition, the blocks the malloc allocates are sized at specific increments, leaving small unused portions at the end of each block. By reducing the number of allocations in half you can reduce the overhead by a significant fraction.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

It is old C. With current C99 or C11 standard you can use flexible array members (which should be the last member of a struct) like:

struct line {
  unsigned length;
  char contents[];
};

and you need a convention about the occupied size of the flexible array. If contents is a C string (like we all expect), you could suppose its size is length+1 (since you need a terminating null byte). Then you should comment that.

See also this & that

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

I really did not understand what they have meant by this: "last element of a structure that is really a header for a variable-length object".

It means this is OK (in GNU C):

 struct line {
   int length;
   char contents[0];  // OK, last member of the structure
 };

but this is not:

 struct line {
   char contents[0];  // Wrong, not the last member of the structure
   int length;
 };
ouah
  • 142,963
  • 15
  • 272
  • 331