CNested Structures

Nested Structures

A struct member can be any type, and that includes another struct. Nesting structs lets you model data that is naturally hierarchical — an employee has an address, an address has a city, a shape has a center point — without flattening everything into one giant, flat list of fields.

Declaring a struct inside another

C
struct Address {
    char street[50];
    char city[30];
    char zipCode[10];
};

struct Employee {
    char name[50];
    int  id;
    struct Address address;   /* an Address lives inside every Employee */
};

struct Address must be fully declared before it is used as a member type inside struct Employee — the compiler needs to know its size in order to compute the size of struct Employee.

Accessing nested members

Reaching into a nested struct just means chaining the dot operator: each . steps one level deeper into the structure.

C
#include <stdio.h>
#include <string.h>

struct Address {
    char street[50];
    char city[30];
    char zipCode[10];
};

struct Employee {
    char name[50];
    int  id;
    struct Address address;
};

int main(void) {
    struct Employee e;
    strcpy(e.name, "Grace Hopper");
    e.id = 1;
    strcpy(e.address.street, "1 Innovation Way");
    strcpy(e.address.city, "Arlington");
    strcpy(e.address.zipCode, "22201");

    printf("%s (ID %d) lives on %s in %s, %s\n",
           e.name, e.id, e.address.street, e.address.city, e.address.zipCode);

    return 0;
}
Grace Hopper (ID 1) lives on 1 Innovation Way in Arlington, 22201

e.address.city reads as "go into e, then into its address member, then into that address's city member." There is no limit to how deep this chaining can go, though beyond two or three levels it usually signals the data model could be reorganized.

Initializing nested structs directly

Nested structs can be initialized inline using nested braces, or — more readably — with nested designated initializers.

C
struct Employee e1 = {
    "Alan Turing",
    2,
    { "Bletchley Park", "Milton Keynes", "MK3 6EB" }
};

struct Employee e2 = {
    .name = "Katherine Johnson",
    .id = 3,
    .address = {
        .street = "1 Nasa Way",
        .city   = "Hampton",
        .zipCode = "23666"
    }
};
Braces mirror the structure
Each pair of nested braces corresponds to one nested struct. This keeps the initializer readable even when several levels of nesting are involved, since the brace layout visually matches the declaration layout.
A realistic worked example

Nested structs shine when a record naturally decomposes into sub-records. Below, an Employee is built from a Name and an Address, and the program prints a formatted summary.

C
#include <stdio.h>

struct Name {
    char first[20];
    char last[20];
};

struct Address {
    char city[30];
    char country[30];
};

struct Employee {
    struct Name    name;
    struct Address address;
    double salary;
};

void printEmployee(struct Employee emp) {
    printf("%s %s — %s, %s — $%.2f\n",
           emp.name.first, emp.name.last,
           emp.address.city, emp.address.country,
           emp.salary);
}

int main(void) {
    struct Employee emp = {
        .name = { .first = "Ada", .last = "Lovelace" },
        .address = { .city = "London", .country = "England" },
        .salary = 95000.00
    };

    printEmployee(emp);
    return 0;
}
Ada Lovelace — London, England — $95000.00
Nested arrays of structs

Nesting works with arrays too. A struct member can itself be an array of another struct, which is how you would model, say, a company with a fixed list of employees embedded directly inside a Department struct.

Access pattern

Meaning

dept.employees[0].name.first

First name of the first employee in the department

e.address.city

City field, one level of nesting

e.name.first[0]

First character of the first-name array, two levels plus an array index

  • A struct member can be another struct, enabling hierarchical data models.

  • The inner struct type must be fully declared before it is used as a member.

  • Chained dot access (a.b.c) walks into each nested level in turn.

  • Nested designated initializers keep the brace structure readable.

  • There is no hard limit on nesting depth, but deep nesting is a readability smell.

Coming up
The next page pairs structs with pointers — including the arrow operator (`->`), which is how nested and non-nested struct members are accessed once you are working through a pointer instead of a plain variable.