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
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.
#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.
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"
}
};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.
#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 |
|---|---|
| First name of the first employee in the department |
| City field, one level of nesting |
| 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.