C - Compound Literals in C

Introduction

A compound literal is a feature introduced in the C99 standard that allows you to create an unnamed object, such as an array or structure, directly within an expression. Normally, when you want to create an array or structure, you first declare a variable, give it a name, and then initialize it. Compound literals allow you to create the object without explicitly giving it a variable name.

The basic syntax is:

(type){initializer-list}

For example:

(int[]){10, 20, 30, 40}

This creates an unnamed array containing four integers. The compound literal can then be used through the pointer to its first element.

Why Compound Literals Are Useful

Compound literals are particularly useful when you need a temporary array, structure, or other object for a short operation. They can make programs more concise because you do not have to create a separate variable just to store values that are needed temporarily.

Consider a normal array:

int numbers[] = {10, 20, 30};

Here, numbers is a named array.

With a compound literal:

(int[]){10, 20, 30}

the array is created without giving it a separate name.

This is especially useful when passing data directly to a function.

Compound Literals with Arrays

An array compound literal can be written as:

(int[]){10, 20, 30, 40, 50}

You can access its elements using array indexing:

#include <stdio.h>

int main()
{
    printf("%d\n", ((int[]){10, 20, 30})[1]);

    return 0;
}

The expression:

((int[]){10, 20, 30})[1]

accesses the second element of the temporary array, which is 20.

The extra parentheses are important because the compound literal itself is an expression.

Specifying the Array Size

You can explicitly specify the size of the array:

(int[5]){10, 20, 30, 40, 50}

You can also initialize only some elements:

(int[5]){10, 20}

The remaining elements are initialized to zero.

Conceptually, this is equivalent to:

int numbers[5] = {10, 20};

The difference is that the compound literal does not require you to create a named variable.

Using Compound Literals with Functions

One of the most useful applications of compound literals is passing an array directly to a function.

Consider:

#include <stdio.h>

void display(int arr[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
}

int main()
{
    display((int[]){10, 20, 30, 40}, 4);

    return 0;
}

Here:

(int[]){10, 20, 30, 40}

creates an unnamed array.

That array is immediately passed to the display() function. There is no need to write:

int numbers[] = {10, 20, 30, 40};
display(numbers, 4);

This makes compound literals convenient when the data is needed only for a particular function call.

Compound Literals with Structures

Compound literals can also be used with structures.

Consider this structure:

struct Student
{
    int id;
    float marks;
};

Normally, you might create and initialize a structure like this:

struct Student s = {101, 85.5};

Using a compound literal, you can create an unnamed structure object:

(struct Student){101, 85.5}

For example:

#include <stdio.h>

struct Student
{
    int id;
    float marks;
};

int main()
{
    struct Student s = (struct Student){101, 85.5};

    printf("ID: %d\n", s.id);
    printf("Marks: %.2f\n", s.marks);

    return 0;
}

The compound literal:

(struct Student){101, 85.5}

creates a structure object and initializes its members.

Designated Initializers with Compound Literals

Compound literals can also be combined with designated initializers.

For example:

struct Student
{
    int id;
    float marks;
};

You can write:

(struct Student){
    .marks = 92.5,
    .id = 105
}

The members do not have to be initialized in their declaration order.

A complete example is:

#include <stdio.h>

struct Student
{
    int id;
    float marks;
};

int main()
{
    struct Student s = (struct Student){
        .marks = 92.5,
        .id = 105
    };

    printf("ID: %d\n", s.id);
    printf("Marks: %.2f\n", s.marks);

    return 0;
}

This approach can improve readability when a structure contains many members.

Passing a Structure Compound Literal to a Function

A compound literal can be passed directly to a function that expects a structure.

Example:

#include <stdio.h>

struct Point
{
    int x;
    int y;
};

void display(struct Point p)
{
    printf("X = %d, Y = %d\n", p.x, p.y);
}

int main()
{
    display((struct Point){10, 20});

    return 0;
}

Here:

(struct Point){10, 20}

creates a temporary structure object and passes it to display().

This is useful when you need to pass a structure value only once.

Compound Literals and Pointers

A compound literal can also be used through a pointer.

For example:

#include <stdio.h>

int main()
{
    int *ptr = (int[]){10, 20, 30};

    printf("%d\n", ptr[0]);
    printf("%d\n", ptr[1]);
    printf("%d\n", ptr[2]);

    return 0;
}

The pointer ptr points to the first element of the unnamed array.

The following expression:

(int[]){10, 20, 30}

produces an array object, and in this context it can be used as a pointer to its first element.

Compound Literals for Configuration Data

Compound literals can also be useful for passing configuration information to functions.

For example:

#include <stdio.h>

struct Settings
{
    int width;
    int height;
};

void configure(struct Settings s)
{
    printf("Width: %d\n", s.width);
    printf("Height: %d\n", s.height);
}

int main()
{
    configure((struct Settings){
        .width = 800,
        .height = 600
    });

    return 0;
}

Instead of creating a separate Settings variable, the structure is created directly when calling configure().

Lifetime of a Compound Literal

An important concept is the lifetime of a compound literal.

The storage duration depends on where the compound literal appears.

When a compound literal is used inside a function body, the object generally has automatic storage duration. It remains available until execution leaves the enclosing block.

For example:

int *create_array()
{
    return (int[]){10, 20, 30};
}

This is problematic because the compound literal has automatic storage duration and its lifetime ends when the function's execution leaves its block. Returning its pointer and using it afterward can therefore result in undefined behavior.

Compound literals should therefore not be treated as dynamically allocated memory.

If data needs to remain available after a function returns, dynamically allocated memory or an object with an appropriate storage duration should be used instead.

File-Scope Compound Literals

Compound literals can also be used at file scope in appropriate contexts. Their storage duration differs from compound literals created inside a function.

For example:

int *ptr = (int[]){10, 20, 30};

At file scope, the object has static storage duration.

This distinction is important because the lifetime of the object depends on where the compound literal is declared.

Difference Between a Normal Object and a Compound Literal

Consider the normal approach:

struct Point p = {10, 20};

The structure has a name:

p

You can use it repeatedly:

printf("%d", p.x);
printf("%d", p.y);

With a compound literal:

(struct Point){10, 20}

there is no variable name. It is useful when the object is required only as part of a particular expression.

For example:

display((struct Point){10, 20});

The compound literal is created specifically for the function call.

Advantages of Compound Literals

Compound literals provide several benefits.

First, they reduce unnecessary temporary variables. If an array or structure is needed only once, creating a named variable may be unnecessary.

Second, they make function calls more concise:

process((int[]){1, 2, 3, 4}, 4);

Third, they work well with structures and designated initializers:

(struct Student){
    .id = 101,
    .marks = 88.5
}

Fourth, they are useful when constructing temporary data for calculations or function calls.

Limitations and Precautions

Compound literals should be used carefully.

They are not dynamically allocated objects. You should not assume that they remain available indefinitely.

You should also avoid returning pointers to function-local compound literals:

int *function()
{
    return (int[]){1, 2, 3};
}

The pointer can become invalid once the function's block is left.

Another consideration is readability. While compound literals can make short expressions convenient, excessive use in complicated expressions can make code harder to understand.

Complete Example

The following example demonstrates a structure compound literal and an array compound literal together:

#include <stdio.h>

struct Product
{
    int id;
    float price;
};

void displayProduct(struct Product p)
{
    printf("Product ID: %d\n", p.id);
    printf("Price: %.2f\n", p.price);
}

void displayNumbers(int numbers[], int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("%d ", numbers[i]);
    }

    printf("\n");
}

int main()
{
    displayProduct((struct Product){
        .id = 101,
        .price = 499.50
    });

    displayNumbers((int[]){10, 20, 30, 40, 50}, 5);

    return 0;
}

In this program, no separate structure variable is required for the call to displayProduct(), and no named array is required for the call to displayNumbers().

Conclusion

Compound literals provide a convenient way to create unnamed arrays, structures, unions, and other objects directly within expressions. They are especially useful when temporary data needs to be passed to a function or used for a single operation. The general syntax is:

(type){initializer-list}

They were introduced in C99 and remain useful in modern C programming. However, programmers must understand their storage duration and lifetime, particularly when pointers to compound literals are involved. When used appropriately, compound literals can make C programs shorter, clearer, and more expressive.