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 Variable-Length Array (VLA) in C is an array data structure whose length is determined at runtime rather than at compile time. Introduced in the C99 standard, VLAs allow the dimension of an array to be specified using a non-constant integer expression. The term “variable” refers exclusively to the evaluation of the size at runtime; once a VLA is instantiated, its size remains fixed for its entire lifetime.

Syntax and Declaration

A VLA is declared similarly to a standard array, but the size specifier is a variable or an expression evaluated during execution.
void allocate_vla(int n) {
    // 'n' is evaluated at runtime to determine the array size
    int dynamic_array[n]; 
}

Technical Constraints and Rules

Working with VLAs introduces specific compiler rules and memory behaviors that differ from standard fixed-size arrays: 1. Struct and Union Membership VLAs cannot be members of a struct or union. This is a strict language constraint. Developers frequently confuse VLAs with Flexible Array Members (FAMs), but FAMs are structurally different (they must be the last member of a struct and have an incomplete type [], relying on heap allocation).
struct InvalidStruct {
    int n;
    int vla[n]; // ERROR: VLAs cannot be struct or union members
};
2. Memory Allocation and Safety Unlike dynamic memory allocation via malloc, VLA allocation failure cannot be detected. Because VLAs are typically allocated on the stack frame, evaluating a size expression that exceeds available stack memory results in an uncatchable stack overflow and undefined behavior. There is no mechanism to return a NULL pointer if the allocation fails. 3. Control Flow and Scope Jumping It is illegal to jump into the scope of a VLA from outside of its scope using goto or switch statements. Doing so bypasses the runtime evaluation and allocation of the array, leaving the VLA in an unallocated or invalid state.
void jump_example(int n) {
    goto label; // ERROR: Jumps into the scope of 'vla'
    
    int vla[n]; // Scope of VLA begins here
    
label:
    return;
}
4. Size Evaluation and Undefined Behavior The expression defining the size of a VLA must evaluate to an integer value strictly greater than zero. If the size expression evaluates to zero or a negative number, the program exhibits Undefined Behavior. 5. Storage Duration VLAs must have automatic storage duration. They cannot be declared at file scope (globally) and cannot use the static or extern storage class specifiers.
int n = 10;
int global_vla[n]; // ERROR: VLAs cannot have static storage duration

void function(int size) {
    static int static_vla[size]; // ERROR: VLAs cannot be static
    int local_vla[size];         // VALID: Automatic storage duration
}
6. Initialization Unlike fixed-size arrays, VLAs cannot be initialized using an initializer list at the point of declaration. They contain indeterminate (garbage) values until explicitly assigned.
#include <string.h>

void init_vla(int n) {
    // int arr[n] = {0}; // ERROR: Variable-sized object may not be initialized
    
    int valid_arr[n];
    memset(valid_arr, 0, sizeof(valid_arr)); // VALID: Manual initialization
}
7. The sizeof Operator and Side Effects For standard arrays, sizeof is evaluated at compile time, and its operand is never executed. For VLAs, the sizeof operator is evaluated at runtime. The runtime environment calculates the total bytes based on the evaluated length expression multiplied by the size of the data type. Crucially, because the operand of sizeof is evaluated at runtime when applied to a VLA, any side effects within the sizeof operand will execute.
#include <stddef.h>

void measure_vla(int n) {
    int arr[n];
    
    // Evaluated at runtime: n * sizeof(int)
    size_t array_bytes = sizeof(arr); 
    
    // Side effects execute: 'n' is incremented at runtime
    size_t dynamic_size = sizeof(int[n++]); 
}
8. Multidimensional VLAs VLAs support multiple dimensions. Any or all of the dimensions can be variable. The compiler handles the underlying pointer arithmetic for row-major memory access dynamically.
void process_matrix(int rows, int cols) {
    // Both dimensions evaluated at runtime
    double matrix[rows][cols]; 
    
    matrix[rows - 1][cols - 1] = 3.14;
}

Function Prototypes and VLA Parameters

When passing multidimensional VLAs to functions, the variable dimensions must be declared in the parameter list before they are used in the array declarator.
// VALID: 'rows' and 'cols' are declared before being used in the array type
void compute(int rows, int cols, int matrix[rows][cols]);

// ERROR: 'rows' and 'cols' are used before they are declared
void compute_invalid(int matrix[rows][cols], int rows, int cols);
In function prototypes (declarations without definitions), the size expression can be omitted and replaced with an asterisk * to denote a VLA type without specifying the exact variable name.
// Prototype using '*' to indicate a VLA
void compute(int, int, int [*][*]);

Standardization Note

While introduced as a mandatory feature in C99, VLAs were made an optional feature in the C11 standard to accommodate implementations where stack memory is highly constrained (e.g., embedded systems). Compilers indicate the lack of VLA support by defining the __STDC_NO_VLA__ macro.
Master C with Deep Grasping Methodology!Learn More