Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A flexible array member (FAM) is a C99 language feature that permits the final element of a struct to be declared as an incomplete array type (an array whose size is unknown). It provides a standardized compiler mechanism for defining variable-sized structures within a single, contiguous block of memory.
#include <stddef.h>

struct Vector {
    size_t length;
    /* Flexible array member */
    int data[]; 
};

Structural Constraints

To satisfy the C standard, a flexible array member must adhere to strict structural rules:
  • Position: It must be the strictly final member of the struct.
  • Prerequisites: The struct must contain at least one named member prior to the FAM. A struct cannot consist solely of a flexible array.
  • Composition: A struct containing a FAM cannot be a member of another struct, nor can it be an element of an array.
  • Initialization: A FAM cannot be statically initialized using standard brace-enclosed initializer lists.

Memory Layout and sizeof Behavior

When the sizeof operator is applied to a struct containing a FAM, the result evaluates to the size of the structure excluding the flexible array. However, the compiler may append padding to the structure to satisfy the alignment requirements of the flexible array’s data type. Therefore, sizeof(struct Vector) may be greater than the sum of the sizes of the preceding members, but it will never account for the elements of the array itself. Applying the sizeof operator directly to the flexible array member (e.g., sizeof(vec->data)) results in a compile-time error because the array is an incomplete type.

Allocation Mechanics

Because the compiler does not implicitly allocate memory for the incomplete array type, instances of the struct must be dynamically allocated. The total allocation size is calculated by adding the base size of the struct to the total byte size required for the desired array elements.
#include <stdlib.h>
#include <stddef.h>

struct Vector {
    size_t length;
    int data[];
};

void allocate_vector(void) {
    size_t num_elements = 10;
    
    /* Calculate total contiguous memory required: base struct size + array size */
    size_t total_size = sizeof(struct Vector) + (num_elements * sizeof(int));

    /* Allocate the memory block */
    struct Vector *vec = malloc(total_size);
    
    if (vec != NULL) {
        vec->length = num_elements;
        
        /* Memory is contiguous; vec->data[0] through vec->data[9] are now valid */
        for (size_t i = 0; i < vec->length; i++) {
            vec->data[i] = 0; 
        }
        
        free(vec);
    }
}

Assignment and Copying Semantics

When a structure containing a flexible array member is assigned by value (e.g., *vec_copy = *vec_original;), the compiler only copies the base members of the struct. The elements of the flexible array are silently ignored during the assignment. Similarly, using sizeof(struct Vector) in memory operations like memcpy will only copy the base structure and any padding, omitting the flexible array portion. To duplicate the entire structure including the array elements, memory operations must use the dynamically calculated total size.
#include <string.h>
#include <stddef.h>

struct Vector {
    size_t length;
    int data[];
};

void copy_vector(struct Vector *vec_copy, const struct Vector *vec_original) {
    /* 
     * INCORRECT APPROACHES:
     * *vec_copy = *vec_original;
     * memcpy(vec_copy, vec_original, sizeof(struct Vector));
     * 
     * These operations copy only 'length' and padding, ignoring 'data' elements.
     */

    /* CORRECT APPROACH: Copies the base struct and the flexible array elements */
    size_t total_size = sizeof(struct Vector) + (vec_original->length * sizeof(int));
    memcpy(vec_copy, vec_original, total_size);
}

Pointer Arithmetic and Access

Once allocated, the FAM behaves identically to a standard array. The compiler resolves accesses to vec->data[i] by computing the offset from the start of the struct, stepping over the preceding members and any compiler-inserted padding, directly into the dynamically allocated tail memory.
Master C with Deep Grasping Methodology!Learn More