Flexible Array Members in C
This article is intended for intermediate and advanced C programmers. It explains what Flexible Array Members (FAMs) are, why they were introduced in C99, and how they enable structures to represent variable-sized objects using a single contiguous memory allocation.
1. What Are Flexible Array Members?
In C, every object created from the same structure type normally occupies exactly the same amount of memory. This works well when every member has a fixed size. However, some members, such as names, messages, filenames, or network payloads, can vary in length. Flexible Array Members (FAMs), introduced in C99, solve this problem by allowing the final part of a structure to have a size determined when the object is allocated.
Case 1: Fixed Arrays
Consider a simple structure representing a student.
The name member can store up to 100 characters.
+------+----------------------------------------+
| ID | Name[100] |
+------+----------------------------------------+
This approach is simple, but it has two obvious disadvantages.
- Most names are much shorter than 100 characters, resulting in wasted memory.
- If a name exceeds 100 characters, it cannot be stored without truncation or risking a buffer overflow.
Case 2: Pointers
A natural alternative is to replace the array with a pointer.
Now the name can be any length.
Student *s = malloc(sizeof(Student));
s->id = 1;
s->name = malloc(strlen("Christopher") + 1);
strcpy(s->name, "Christopher");
The memory layout becomes
Student object
+------+------------+
| ID | name ------+----------+
+------+------------+ |
|
|
v
+------------------------+
| "Christopher" |
+------------------------+
This eliminates the fixed-size limitation, but introduces a different problem.
The student is now represented by two separate memory allocations:
- one allocation for the structure
- another allocation for the name
Consequently:
- two calls to
malloc()are required, - two calls to
free()are required, - the structure and its name may be located far apart in memory.
In many applications, however, the name is not an independent object. It is simply part of the student.
This is precisely the problem that Flexible Array Members were designed to solve.
Case 3: Empty Array (FAM)
Instead of storing a pointer, the final member is declared as an array with no specified size.
Although name appears to be an ordinary array, no storage is reserved for it when the compiler determines the size of the structure. Instead, the required space is supplied when the structure is allocated.
Student *s =
malloc(sizeof(Student) + strlen("Christopher") + 1);
s->id = 1;
strcpy(s->name, "Christopher");
The resulting memory layout is
+------+------------------------+
| ID | "Christopher" |
+------+------------------------+
^
|
Student object
Compared to the pointer-based approach:
- only one memory allocation is required,
- only one call to
free()is needed, - the structure and its variable-length data occupy one contiguous block of memory.
Conceptually, a Flexible Array Member allows a structure to represent a single variable-sized object, rather than a fixed-size object that points to separately allocated memory.
The following section explains the syntax and language rules governing Flexible Array Members, including why they must appear as the final member of a structure and how they affect the result of the sizeof operator.
2. Declaring Flexible Array Members
A Flexible Array Member is declared by specifying an array with no size as the last member of a structure.
Unlike an ordinary array, the compiler does not allocate storage for name as part of the structure. Instead, name serves as a placeholder indicating that additional storage may follow the fixed portion of the structure.
This is why the declaration is known as a Flexible Array Member. Its size is determined when the structure is allocated, not when the structure type is defined.
Flexible Array Members Must Be the Last Member
A Flexible Array Member can appear only as the final member of a structure.
For example,
is valid.
However,
is invalid.
The compiler cannot determine where age should be placed because the size of name is not known when the structure type is defined.
A Structure Can Have Only One Flexible Array Member
Since a Flexible Array Member must be the last member, a structure can contain at most one Flexible Array Member.
The following declaration is invalid.
There is no way to determine where lastName begins because the size of firstName is unknown.
The Flexible Array Member Contributes Nothing to sizeof
One of the most important properties of a Flexible Array Member is that it does not contribute to the size of the structure.
Consider the following declaration.
The memory layout known to the compiler is
The flexible array member is not included because its size is unknown.
Therefore,
returns only the size of the fixed portion of the structure.
This differs from an ordinary array.
whose layout is
+------+----------------------------------------+
| ID | Name[100] |
+------+----------------------------------------+
Here,
includes both the id member and the 100-byte array because every object of the structure has the same fixed size.
Flexible Array Members Cannot Be Used as Standalone Objects
Since a Flexible Array Member has no storage of its own, declaring an automatic or static object of the structure type is generally not useful.
The object contains storage only for the fixed members.
There is no space for name, so attempting to store characters in it results in undefined behavior.
Instead, structures containing Flexible Array Members are almost always created by dynamically allocating sufficient memory for both the fixed members and the flexible array.
3. Allocating Structures with Flexible Array Members
Unlike ordinary arrays, a Flexible Array Member does not occupy any storage within the structure itself. Therefore, whenever an object containing a Flexible Array Member is created, sufficient memory must be allocated for both:
- the fixed portion of the structure, and
- the flexible array.
Consider the following structure.
Suppose we want to store the name "Christopher".
The total memory required is:
- the size of the
Studentstructure, and - enough space for all characters in the name, including the terminating null character.
The allocation is therefore
The + 1 reserves space for the terminating '\0'.
Once allocated, the object can be initialized normally.
The resulting memory layout is
+------+------------------------+
| ID | "Christopher" |
+------+------------------------+
^
|
Student object
Although name is declared as an array with no specified size, it behaves exactly like an ordinary character array because the additional memory immediately follows the fixed portion of the structure.
For example,
No special syntax is required to access the Flexible Array Member.
Flexible Array Members Are Not Limited to Characters
Flexible Array Members can store any data type.
For example,
Suppose we want to store ten integers.
The memory layout becomes
+---------+---------------------------------------+
| count | values[10] |
+---------+---------------------------------------+
^
|
IntArray object
The elements can be accessed exactly like an ordinary array.
Since values occupies contiguous memory immediately after the fixed members, array indexing works exactly as expected.
Deallocating a Structure with a Flexible Array Member
Unlike pointer-based designs, there is no separate allocation for the flexible array.
For example, using a pointer requires two deallocations.
However, with a Flexible Array Member, both the structure and its variable-length data belong to the same memory block.
Therefore, only a single call to free() is required.
This is one of the primary advantages of Flexible Array Members. They simplify memory management by treating the fixed members and the variable-length data as a single object.
4. Common Usage Patterns
Flexible Array Members are useful whenever a structure contains data whose size is not known until runtime. Rather than storing a pointer to separately allocated memory, the variable-length data becomes part of the structure itself.
The following are some common applications.
Variable-Length Strings
One of the simplest uses of a Flexible Array Member is storing strings whose length varies.
Instead of reserving a large fixed-size array for every student, memory is allocated according to the actual length of the name.
Memory layout:
This avoids both wasted memory and the need for a separate allocation for the string.
Variable-Length Binary Buffers
Flexible Array Members are frequently used to store arbitrary binary data.
Suppose a buffer must store 512 bytes.
Memory layout:
+---------+--------------------------------------+
| size | 512 bytes |
+---------+--------------------------------------+
Since the data immediately follows the structure, the entire buffer can be treated as a single object.
Network Packets
Network protocols often contain a fixed-size header followed by a payload whose size depends on the packet being transmitted.
Memory layout:
+--------+---------+-----------------------------+
| type | length | payload |
+--------+---------+-----------------------------+
The length field indicates the number of bytes stored in the payload.
This design closely matches the layout of many real network packets and avoids maintaining a separate pointer for the payload.
File or Database Records
Variable-length records are common in file formats and databases.
Different records may contain filenames of different lengths.
Record 1
+-----------+-------------+
| recordId | "log.txt" |
+-----------+-------------+
Record 2
+-----------+--------------------------------+
| recordId | "annual_report_2025.pdf" |
+-----------+--------------------------------+
Although both objects are instances of the same structure type, each occupies only the memory required for its filename.
Custom Containers
Flexible Array Members are commonly used when implementing custom containers whose capacity is determined during creation.
When creating the container, memory is allocated according to the required capacity.
Memory layout:
+----------+------+----------------------------------+
| capacity | size | elements[100] |
+----------+------+----------------------------------+
The container metadata and storage occupy one contiguous memory block, simplifying allocation and deallocation.
Flexible Array Members are therefore widely used in systems programming, networking, embedded software, file formats, memory allocators, and other performance-critical applications where variable-length data naturally belongs to the object that owns it.
5. Advantages and Limitations
Flexible Array Members provide an efficient way to represent variable-sized objects. They reduce memory overhead, improve cache locality, and simplify memory management. However, they also come with several restrictions imposed by the C standard.
Advantages
Efficient Memory Utilization
Unlike fixed-size arrays, a Flexible Array Member occupies only as much memory as is actually required.
For example,
A student named "Tom" occupies less memory than a student named "Christopher" because each object is allocated according to the actual length of the name.
This avoids the wasted space associated with large fixed-size arrays.
Single Memory Allocation
A pointer-based design requires two allocations.
With a Flexible Array Member, both the structure and its variable-length data are allocated together.
This reduces allocation overhead and simplifies memory management.
Improved Cache Locality
Since the flexible array immediately follows the fixed members of the structure, all related data resides in one contiguous memory block.
Sequential access is generally more cache-friendly than accessing separately allocated memory through pointers.
Simplified Deallocation
Pointer-based structures require multiple calls to free().
A structure containing a Flexible Array Member requires only one.
This reduces the likelihood of memory leaks and simplifies ownership.
Limitations
Must Be the Last Member
A Flexible Array Member must always be the final member of a structure.
Attempting to place another member after the flexible array is not permitted.
Only One Flexible Array Member
Since it must appear last, a structure can contain only one Flexible Array Member.
The following declaration is invalid.
Dynamic Allocation Is Required
A Flexible Array Member has no storage unless additional memory is allocated.
Therefore,
creates storage only for the fixed members.
Attempting to use
results in undefined behavior because no memory exists for the flexible array.
The Programmer Must Calculate the Allocation Size
The compiler does not automatically determine how much memory should be allocated.
The programmer must explicitly calculate the required size.
Allocating too little memory results in undefined behavior.
Cannot Be Resized Automatically
A Flexible Array Member does not grow or shrink automatically.
If more space is required, the entire object must be reallocated.
Since the structure and its flexible array form a single memory block, both are resized together.
Flexible Array Members are an excellent choice when variable-length data naturally belongs to the structure that owns it. They are widely used in systems programming, networking, embedded software, file formats, and custom memory allocators because they combine efficiency with a simple and intuitive memory layout.
The next section concludes the discussion with a summary of the key concepts covered in this article.
6. Summary
In this article, you learned how Flexible Array Members (FAMs) provide an efficient way to represent variable-sized objects in C by allowing the final member of a structure to have a size determined when the object is allocated.
The key concepts covered include:
- Every object created from an ordinary structure type normally has the same size.
- Fixed-size arrays are simple but may waste memory or impose unnecessary size limits.
- Using pointers removes the size limitation but requires separate memory allocations for the structure and its variable-length data.
- A Flexible Array Member is declared as an array with no specified size and must appear as the last member of a structure.
- A Flexible Array Member contributes nothing to the result of the
sizeofoperator. - Objects containing Flexible Array Members must be dynamically allocated with sufficient space for both the fixed members and the flexible array.
- The flexible array behaves like an ordinary array once the object has been allocated.
- Since the structure and its variable-length data occupy a single contiguous memory block, only one allocation and one deallocation are required.
- Flexible Array Members are commonly used for variable-length strings, binary buffers, network packets, file records, and custom containers.
- Although Flexible Array Members improve memory efficiency and cache locality, they require careful allocation size calculations and can only appear as the final member of a structure.
Flexible Array Members are a simple yet powerful feature introduced in C99. They allow programmers to model variable-length data as part of a single object instead of managing multiple related memory allocations. When used appropriately, they lead to cleaner data structures, simpler memory management, and more efficient programs, making them a valuable tool in systems programming, networking, embedded software, and performance-critical applications.
Relevant Links
C/C++ Material on this website
(such as memory managment, pointers, embedded C programming etc.)