CVariable-Length Arrays

Variable-Length Arrays

Before C99, array sizes had to be known at compile time. C99 introduced variable-length arrays (VLAs), a feature that allows an array's size to be an ordinary expression evaluated while the program is running, not just a compile-time constant. VLAs are convenient, but they come with real risks that every C programmer should understand before relying on them.
Declaring a VLA

A VLA looks just like a normal array declaration, except the size inside the brackets can be a variable whose value is only known at runtime:

C
#include <stdio.h>

int main(void) {
    int n;
    printf("How many numbers? ");
    scanf("%d", &n);

    int arr[n]; // VLA -- size "n" is a runtime value, valid since C99

    for (int i = 0; i < n; i++) {
        arr[i] = i * i;
    }
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}
VLAs Live on the Stack
Not the same as malloc
A VLA is allocated on the stack (the same place ordinary local variables live), and it is automatically freed when it goes out of scope — there is no manual cleanup required. This is fundamentally different from malloc(), which allocates from the heap and requires an explicit free() call. Do not confuse the two: a VLA cannot outlive the block it was declared in, and it cannot be resized or returned from the function as a valid pointer.
Stack Overflow Risk
A user-controlled VLA size is a real security concern
The stack has a limited, relatively small size (often just a few megabytes). Because a VLA is allocated on the stack, requesting a very large or unchecked size can exhaust the stack entirely, causing a crash — this is a stack overflow, not to be confused with an out-of-bounds array access. If the VLA's size comes directly from user input without any validation, an attacker (or just an unlucky user) can trigger this crash on purpose or by accident. This is a classic, well-documented vulnerability pattern. Always validate and cap any runtime value before using it as a VLA size, or use heap allocation (malloc) instead for potentially large sizes.

C
int n;
scanf("%d", &n);

int arr[n]; // DANGEROUS if n is unchecked -- a huge or negative n
            // can crash the program or invoke undefined behavior

// Safer: validate first
if (n <= 0 || n > 10000) {
    printf("Invalid size\n");
    return 1;
}
int safeArr[n]; // still bounded, but at least sanity-checked
VLAs Became Optional in C11
Not guaranteed to be supported everywhere
C99 made VLA support mandatory, but the C11 standard downgraded support for VLAs to an optional feature. A conforming C11 compiler is allowed to omit VLA support entirely, and some embedded or safety- critical toolchains do exactly that (a compiler that supports VLAs defines the macro __STDC_NO_VLA__ as 0, or leaves it undefined; if it is defined as 1, VLAs are unsupported). If you are writing portable code that must compile everywhere, check for VLA support first, or avoid VLAs altogether in favor of malloc()-based dynamic arrays.
  • A VLA lets an array size be a runtime expression, e.g. int arr[n];, since C99

  • VLAs are allocated on the stack and freed automatically -- unlike malloc(), which uses the heap and needs free()

  • An unchecked or user-controlled VLA size risks a stack overflow -- a real, exploitable vulnerability pattern

  • Always validate/cap a runtime size before using it as a VLA size

  • C11 made VLA support optional, so portable code should check for support or avoid VLAs