C - Flexible Array Members in Structures



Flexible Array Members is used to handle arrays inside structures without defining their size. These arrays get their size at runtime. A structure in C is a user-defined data type where we define multiple members of different data types together under one name.

Below is the syntax for declaring a structure in C −

struct StructName {
    data_type member1;
    data_type member2;
    // ...
};

Here, each member can have a different data type.

Flexible array members extend structures by holding a dynamically sized array at the end of their fixed-size members and all together stored in one block of memory. In this chapter, we'll see how they work inside the structures.

Flexible Array Members in Structure

A flexible array member is an array inside a structure without a fixed size, and its memory is allocated dynamically at runtime using malloc(), calloc(), or similar functions and it is declared using empty square brackets [].

The flexible array member must be declared at the end of the structure, and there must be at least one other member before declaring it.

Following is the syntax for declaring a flexible array member inside a structure −

struct StructName {
    data_type member1;
    data_type flexible_array[]; // flexible array member
};

Here, data_type is the data type of the array, and arrayName[] is the flexible array with no fixed size.

Memory Allocation for Flexible Array Member

A flexible array member does not have a fixed size, so the compiler does not allocate any memory for it inside the structure. The sizeof operator only calculates the size of the fixed members of the structure without including the flexible array member. That's why we need to allocate memory manually when creating such structures.

The total memory required is calculated as −

Total Memory = sizeof(structure) + (number of elements x sizeof(element type))

Here, sizeof(structure) gives the memory for the fixed members, and (number of elements x sizeof(element type)) gives the memory for the flexible array. Adding them gives the total memory to allocate.

Example 1: Allocating Memory for a Flexible Array Member

Below is an example where we define a structure with one fixed member and a flexible array, and allocate memory for the flexible array.

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

struct Example {
    int id; 
    int arr[]; // flexible array member 
};

int main() {
    int size = 5;
    // Allocate memory for structure + flexible array
    struct Example *e = malloc(sizeof(struct Example) + size * sizeof(int));

    if (e != NULL) {
        printf("Total allocated memory: %zu bytes\n", sizeof(struct Example) + size * sizeof(int));
        free(e);
    }
    return 0;
}

Here, sizeof(struct Example) gives 4 bytes for the id member. Then, we calculate the memory for the flexible array: 5 x sizeof(int) = 20 bytes. The total memory allocated is 4 + 20 = 24 bytes. The output is −

Total allocated memory: 24 bytes

Example 2: Accessing a Flexible Array in a Structure

In this example, we define a Student structure with one fixed member (id) and a flexible array member (marks). We allocate memory dynamically for the flexible array and access its elements. If we access elements beyond the allocated size it will cause undefined behavior, so we only access marks[0] to marks[2].

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

struct Student {
    int id;
    int marks[]; // flexible array member
};

int main() {
    int subjects = 3;

    // Allocate memory for structure + flexible array
    struct Student *s = malloc(sizeof(struct Student) + subjects * sizeof(int));

    if (s != NULL) {
        s->id = 102;
        s->marks[0] = 80;
        s->marks[1] = 75;
        s->marks[2] = 88;

        printf("Student ID: %d\n", s->id);
        printf("Marks: %d, %d, %d\n", s->marks[0], s->marks[1], s->marks[2]);
        printf("Total allocated memory: %zu bytes\n", sizeof(struct Student) + subjects * sizeof(int));
        free(s);
    }
    return 0;
}

Following is the output of the above program −

Student ID: 102
Marks: 80, 75, 88
Total allocated memory: 16 bytes

Dynamic Resizing of Flexible Array Members

Flexible arrays can be resized using the realloc() function. This function either expands the existing memory block or allocates a new block and copies the existing data automatically.

To resize a flexible array, we call realloc() function with the new total memory size using the formula −

sizeof(structure) + (new_number_of_elements x sizeof(element_type))
Note: Always store the result of realloc() function in a temporary pointer. If it fails, your original pointer remains safe. Also, update the size counter after resizing and initialize only the newly added elements.

Example 3: Dynamic Resizing of Flexible Array Members

In this example, we create a Student structure to hold 3 marks initially. Later, we resize the flexible array to hold 6 marks using realloc(). The marks we already stored in remain unchanged, so we don't need to copy them manually.

#include <stdio.h>
#include <stdlib.h>
 
struct Student {
    int id;
    int count;      // This field helps track current array size
    int marks[];    // Flexible array member
};

int main() {
    // Step 1: Initial allocation for 3 marks
    int initial_elements = 3;
    struct Student *s = malloc(sizeof(struct Student) + initial_elements * sizeof(int));
    
    if (s != NULL) {
        s->id = 101;
        s->count = initial_elements;  // Store current array size
        
        // Display initial sizes
        printf("Structure size: %zu bytes\n", sizeof(struct Student)); // Output: 8 bytes (id + count)
        printf("Initial array elements: %d\n", s->count);              // Output: 3
        printf("Initial total memory: %zu bytes\n", 
           sizeof(struct Student) + initial_elements * sizeof(int)); // Output: 20 bytes
        
        // Step 2: Resize to hold 6 marks
        int new_elements = 6;
        struct Student *temp = realloc(s, sizeof(struct Student) + new_elements * sizeof(int));
        
        if (temp != NULL) {
            s = temp;
            s->count = new_elements;  // Update array size tracker
            
            // Display new sizes
            printf("\nAfter resizing:\n");
            printf("Structure size: %zu bytes\n", sizeof(struct Student)); // Still 8 bytes
            printf("New array elements: %d\n", s->count);                  // Output: 6
            printf("New total memory: %zu bytes\n", 
               sizeof(struct Student) + new_elements * sizeof(int));   // Output: 32 bytes
        }
        
        free(s);
    }
    return 0;
}

Below is the output showing the structure size and the total memory for both the initial and resized flexible array.

Structure size: 8 bytes
Initial array elements: 3
Initial total memory: 20 bytes

After resizing:
Structure size: 8 bytes
New array elements: 6
New total memory: 32 bytes

In this chapter, we learned about flexible array members in C structures. They are declared at the end of a structure and handle variable-length data, save memory, and adapt to different data sizes easily. We also saw how to allocate, access, and resize them.

Advertisements