C Mastery / Compound Literals and Designated Initializers
Part 1 — The Core Language

Compound Literals and Designated Initializers

This chapter covers two C99 features that make initialization and temporary values much more convenient: compound literals and designated initializers.

Why This Matters

Designated initializers make code self-documenting and robust against member reordering. Compound literals let you create temporary struct or array values inline, avoiding separate declarations. Both are widely used in modern C.

Prerequisites

Core Concept

Designated initializers (C99)

A designated initializer names the member or element being initialized, rather than relying on position:

struct Point p = { .x = 1, .y = 2 };
int arr[5] = { [2] = 7, [4] = 9 };

Unmentioned members/elements are initialized to zero (for objects with static or aggregate initialization).

Compound literals (C99)

A compound literal creates an unnamed object of a given type:

(struct Point){ .x = 1, .y = 2 }
(int[]){ 1, 2, 3 }

It can be used anywhere an expression of that type is valid. At block scope it has automatic lifetime; at file scope it has static lifetime.

Syntax

(type-name){ initializer-list }

.member = value
[index] = value

Examples

Designated initializers

#include <stdio.h>

struct Config {
    int retries;
    int timeout;
    int verbose;
};

int main(void)
{
    struct Config c = { .timeout = 30, .verbose = 1 };
    printf("%d %d %d\n", c.retries, c.timeout, c.verbose);
    return 0;
}

Expected output: 0 30 1 (retries defaults to 0).

Compound literal passed to a function

#include <stdio.h>

struct Point { int x; int y; };

void print_point(struct Point p)
{
    printf("(%d, %d)\n", p.x, p.y);
}

int main(void)
{
    print_point((struct Point){ .x = 3, .y = 4 });
    return 0;
}

Expected output: (3, 4).

Compound literal array

#include <stdio.h>

int sum(const int *a, int n)
{
    int s = 0;
    for (int i = 0; i < n; i++) s += a[i];
    return s;
}

int main(void)
{
    printf("%d\n", sum((int[]){1, 2, 3, 4}, 4));
    return 0;
}

Expected output: 10.

How It Works

A designated initializer is translated by the compiler into positional initialization (with the named targets filled in and the rest zeroed). A compound literal is a real object — it has an address, a type, and a lifetime — even though it has no name.

Variations

Nested designated initializers

struct Outer {
    int a;
    struct Inner { int b; int c; } in;
};

struct Outer o = { .in = { .c = 5 } };   /* nested */

Compound literal at file scope

static const int *defaults = (int[]){ 1, 2, 3 };  /* static lifetime */

Common Mistakes

(int)5 is a cast.

(returning a pointer to it is a dangling-pointer bug).

Undefined Behavior

after the block ends (dangling pointer). VERIFIED

type (constraint violation).

Portability

in C89.

standard.

Under the Hood

A block-scope compound literal is typically placed on the stack, like a local variable. A file-scope compound literal goes in static storage. The compiler may optimize a compound literal away if its address is never taken and its value can be computed directly.

Practical Usage

separate variable.

Exercises

1. Initialize a struct with designated initializers, leaving some members defaulted, and print them. 2. Pass a compound literal struct to a function. 3. Demonstrate the lifetime of a block-scope compound literal by returning its address (and explaining the bug). 4. Use a compound literal array with a function.

Deep Challenge

Explain the difference in lifetime and addressability between these two uses, and which is safe:

struct Point *p1(void) { return &(struct Point){1, 2}; }   /* ? */

struct Point *p2(void)
{
    static struct Point p = {1, 2};
    return &p;
}

Then write a correct version of the first using static or allocated storage.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.struct.compound-literal05
c.struct.designated-init05