Introduction to Nested Structures
Nested structures allow you to place one structure inside another, creating hierarchical data models that mirror real-world relationships.
What is a Nested Structure?
A nested structure (also called an embedded structure) is a structure that contains one or more other structures as its members. This allows you to group related data at multiple levels, creating complex data hierarchies.
Why Use Nested Structures?
In real-world programming, data often has natural hierarchical relationships. Consider an employee record - it has basic information (ID, name) plus an address (which itself has street, city, and zip code). Nested structures let you model this relationship cleanly.
- Logical grouping - Related data stays together
- Reusability - Inner structures can be reused
- Readability - Code mirrors real-world entities
- Maintainability - Changes are localized
- Address in Person - street, city, zip
- Date in Event - day, month, year
- Coordinates in Shape - x, y points
- Author in Book - name, contact info
Real-World Example: Student Record
Let's visualize how nested structures work with a student record that contains personal info and an address:
// Without nested structures - flat and repetitive
struct Student_Flat {
int rollNo;
char name[50];
char street[100]; // Address field 1
char city[50]; // Address field 2
int zipCode; // Address field 3
};
// With nested structures - organized and reusable
struct Address {
char street[100];
char city[50];
int zipCode;
};
struct Student {
int rollNo;
char name[50];
struct Address addr; // Nested structure!
};
Address
structure in other places (like Employee, Customer, Supplier) without duplicating code.
Visual Representation
| struct Student | |||||||||
|---|---|---|---|---|---|---|---|---|---|
|
rollNo int |
name char[50] |
|
|||||||
Practice Questions: Introduction
Answer: Nested structures offer several advantages over flat structures:
- Reusability: The inner structure can be reused in multiple outer structures
- Organization: Related fields are logically grouped together
- Maintainability: Changes to the inner structure automatically apply everywhere it's used
- Readability: Code better mirrors real-world data relationships
Answer: Here are three examples:
- Order with Customer: An Order structure containing a Customer structure with name, email, and phone
- Employee with Date of Birth: An Employee structure containing a Date structure with day, month, and year
- Rectangle with Points: A Rectangle structure containing two Point structures for top-left and bottom-right corners
Answer: Yes, nested structures can contain multiple levels of nesting. Example: A Company with a headquarter Address and a branch Office that also has its own Address.
Show Solution
struct Address {
char street[100];
char city[50];
int zipCode;
};
struct Office {
char name[100];
struct Address location; // Address nested in Office
};
struct Company {
char companyName[100];
struct Office headquarter; // Office (with nested Address) in Company
struct Office branch;
};
Answer:
- Nested Structure: One structure contains a single instance of another structure (1:1 relationship)
- Array of Structures: A variable holds multiple instances of the same structure type (1:many relationship)
Example:
// Nested: Person has ONE Address
struct Person { struct Address addr; };
// Array: Company has MANY employees
struct Company { struct Employee employees[100]; };
Defining Nested Structures
Learn the syntax and different approaches for defining structures that contain other structures as members.
Method 1: Separate Definition (Recommended)
The most common and reusable approach is to define the inner structure separately, then use it as a member type in the outer structure.
// Step 1: Define the inner structure first
struct Date {
int day;
int month;
int year;
};
// Step 2: Use it in the outer structure
struct Employee {
int empId;
char name[50];
float salary;
struct Date joinDate; // Nested structure member
struct Date birthDate; // Can use same type multiple times!
};
Date structure can now be used in Employee, Event, Invoice, or any other structure.
Method 2: Inline Definition
You can define a structure directly inside another structure. This is useful when the inner structure is only used in one place and won't be reused elsewhere.
struct Product {
int productId;
char name[100];
float price;
// Inline nested structure definition
struct {
int quantity;
int reorderLevel;
char warehouse[20];
} inventory; // Anonymous inner struct with member name
};
Method 3: Using typedef with Nested Structures
Combine typedef with nested structures for cleaner, more readable code
without repeating the struct keyword.
// Define inner structure with typedef
typedef struct {
char street[100];
char city[50];
char state[30];
int zipCode;
} Address;
// Define outer structure with typedef
typedef struct {
int customerId;
char name[50];
char email[100];
Address billingAddr; // No 'struct' keyword needed!
Address shippingAddr; // Reusing the same type
} Customer;
Complete Example: Book with Author
#include <stdio.h>
#include <string.h>
// Inner structure: Author information
typedef struct {
char name[50];
char email[50];
int booksWritten;
} Author;
// Outer structure: Book with nested Author
typedef struct {
char title[100];
char isbn[20];
float price;
int pages;
Author author; // Nested structure
} Book;
int main() {
// Declare and initialize a book
Book myBook;
// Set book details
strcpy(myBook.title, "The C Programming Language");
strcpy(myBook.isbn, "978-0131103627");
myBook.price = 59.99;
myBook.pages = 272;
// Set nested author details
strcpy(myBook.author.name, "Brian Kernighan");
strcpy(myBook.author.email, "bwk@example.com");
myBook.author.booksWritten = 12;
// Display the book info
printf("Book: %s\n", myBook.title);
printf("ISBN: %s\n", myBook.isbn);
printf("Price: $%.2f\n", myBook.price);
printf("Pages: %d\n", myBook.pages);
printf("Author: %s\n", myBook.author.name);
printf("Author Email: %s\n", myBook.author.email);
return 0;
}
Multi-Level Nesting
You can nest structures multiple levels deep, though it's best to keep nesting to 2-3 levels for readability.
// Level 1: Coordinates
typedef struct {
float latitude;
float longitude;
} Coordinates;
// Level 2: Address with Coordinates
typedef struct {
char street[100];
char city[50];
Coordinates location; // Nested level 1
} Address;
// Level 3: Store with Address
typedef struct {
char storeName[50];
int storeId;
Address address; // Nested level 2 (contains level 1)
} Store;
// Access deeply nested member:
// store.address.location.latitude
Practice Questions: Defining Nested Structures
Task: Create a Date struct with day, month, year. Then create an Event struct with name, venue, and a Date member.
Show Solution
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
char name[100];
char venue[100];
Date eventDate; // Nested Date structure
} Event;
// Usage:
Event conference = {"Tech Summit 2025", "Convention Center", {15, 3, 2025}};
Task: Create Country containing State containing City. Each should have a name and relevant properties.
Show Solution
typedef struct {
char name[50];
int population;
} City;
typedef struct {
char name[50];
City capital; // Nested City
int numDistricts;
} State;
typedef struct {
char name[50];
State largestState; // Nested State (which contains City)
long totalPopulation;
} Country;
// Accessing deeply nested:
// country.largestState.capital.population
Task: Create a Server structure with an inline anonymous structure for connection settings.
Show Solution
typedef struct {
char hostname[100];
int serverId;
// Inline anonymous nested structure
struct {
int port;
int maxConnections;
int timeout;
int useSSL; // 1 for true, 0 for false
} connectionSettings;
int isRunning;
} Server;
// Usage:
Server webServer;
webServer.connectionSettings.port = 443;
webServer.connectionSettings.useSSL = 1;
webServer.connectionSettings.maxConnections = 1000;
Answer:
- With typedef: Can use
Date d;directly (no need forstruct Date d;) - Without typedef: Must use
struct Date d;every time you declare
Using typedef is cleaner and more convenient for nested structures since you'll be accessing them frequently.
Accessing Nested Structure Members
Master the dot operator chaining and arrow operator techniques to access deeply nested structure members.
Using the Dot Operator Chain
To access members of a nested structure, chain the dot operator (.)
from the outermost structure to the innermost member. Each dot moves one level deeper.
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
int empId;
char name[50];
Date joinDate; // Nested structure
} Employee;
int main() {
Employee emp;
// Set outer structure members normally
emp.empId = 101;
strcpy(emp.name, "Priya Sharma");
// Access nested structure members with dot chaining
emp.joinDate.day = 15; // outer.inner.member
emp.joinDate.month = 6;
emp.joinDate.year = 2023;
// Read nested values
printf("Employee %d joined on %d/%d/%d\n",
emp.empId,
emp.joinDate.day,
emp.joinDate.month,
emp.joinDate.year);
return 0;
}
outerVariable.innerMember.nestedMember -
Read left to right: "emp's joinDate's day"
Using the Arrow Operator with Pointers
When working with pointers to structures, use the arrow operator (->)
for the pointer level, then dot operators for nested access.
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
int id;
char name[50];
Address addr;
} Customer;
void printCustomer(Customer *ptr) {
// Arrow for pointer, then dot for nested struct
printf("ID: %d\n", ptr->id);
printf("Name: %s\n", ptr->name);
printf("City: %s\n", ptr->addr.city); // ptr->nested.member
printf("ZIP: %d\n", ptr->addr.zipCode);
}
int main() {
Customer c1 = {101, "Rahul Patel", {"Mumbai", 400001}};
printCustomer(&c1); // Pass address
// Modify through pointer
Customer *cptr = &c1;
cptr->addr.zipCode = 400002; // Change nested value
return 0;
}
Operator Combinations Summary
| Scenario | Syntax | Example |
|---|---|---|
| Variable with nested struct | var.nested.member |
emp.addr.city |
| Pointer to struct with nested struct | ptr->nested.member |
empPtr->addr.city |
| Dereference pointer then access | (*ptr).nested.member |
(*empPtr).addr.city |
| Nested pointer member | var.nestedPtr->member |
emp.addrPtr->city |
Multi-Level Access Example
typedef struct {
float lat;
float lng;
} Coordinates;
typedef struct {
char street[100];
char city[50];
Coordinates coords; // Level 2 nesting
} Address;
typedef struct {
char name[50];
Address home; // Level 1 nesting
Address office;
} Person;
int main() {
Person p = {
"Amit Kumar",
{"123 MG Road", "Delhi", {28.6139, 77.2090}}, // home
{"456 CP Street", "Delhi", {28.6315, 77.2167}} // office
};
// Three-level access: person -> address -> coordinates
printf("Name: %s\n", p.name);
printf("Home: %s, %s\n", p.home.street, p.home.city);
printf("Home Location: %.4f, %.4f\n",
p.home.coords.lat, p.home.coords.lng);
printf("Office: %s, %s\n", p.office.street, p.office.city);
printf("Office Location: %.4f, %.4f\n",
p.office.coords.lat, p.office.coords.lng);
// Modify a deeply nested value
p.home.coords.lat = 28.6200;
return 0;
}
Copying Nested Structures
When you assign one structure variable to another, all nested structure data is copied completely - C performs a shallow copy of all bytes.
typedef struct {
char city[50];
int zip;
} Address;
typedef struct {
int id;
Address addr;
} Customer;
int main() {
Customer c1 = {101, {"Mumbai", 400001}};
Customer c2;
// Complete copy - including nested structure
c2 = c1;
// Modifying c2 does NOT affect c1
c2.id = 102;
strcpy(c2.addr.city, "Delhi");
c2.addr.zip = 110001;
printf("c1: ID=%d, City=%s\n", c1.id, c1.addr.city); // 101, Mumbai
printf("c2: ID=%d, City=%s\n", c2.id, c2.addr.city); // 102, Delhi
return 0;
}
Practice Questions: Accessing Nested Members
Given:
struct Date { int day, month, year; };
struct Employee { int empId; struct Date birthDate; };
Employee emp = {101, {15, 6, 1990}};
Task: Write code to access and print the birth month and year of emp. Calculate the age (assuming current year is 2025).
Expected output: Birth month: 6, Birth year: 1990, Age: 35
Show Solution
typedef struct {
int day, month, year;
} Date;
typedef struct {
int empId;
Date birthDate;
} Employee;
int main() {
Employee emp = {101, {15, 6, 1990}};
// Access nested members using dot operator
printf("Birth month: %d\n", emp.birthDate.month); // 6
printf("Birth year: %d\n", emp.birthDate.year); // 1990
int age = 2025 - emp.birthDate.year;
printf("Age: %d\n", age); // 35
return 0;
}
Given:
struct Address { char city[50]; int zipCode; };
struct Employee { int empId; Address addr; };
Employee emp = {101, {"Bangalore", 560001}};
Task: Write a function that takes an Employee pointer and updates the city and zipCode. Call it to relocate emp to "Mumbai" with zip 400001.
Expected output: Employee 101 relocated to Mumbai - 400001
Show Solution
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
int empId;
Address addr;
} Employee;
void relocateEmployee(Employee *ptr, const char *newCity, int newZip) {
// Use arrow operator for pointer access
strcpy(ptr->addr.city, newCity);
ptr->addr.zipCode = newZip;
printf("Employee %d relocated to %s - %d\n",
ptr->empId, ptr->addr.city, ptr->addr.zipCode);
}
int main() {
Employee emp = {101, {"Bangalore", 560001}};
relocateEmployee(&emp, "Mumbai", 400001);
return 0;
}
Given:
struct Point { int x, y; };
struct Circle { Point center; int radius; };
struct Drawing { char name[30]; Circle shape; };
Drawing d = {"My Circle", {{100, 200}, 50}};
Task: Write a function that takes a Drawing pointer and prints center coordinates, radius, and calculates area (π × r²). Use both arrow and dot operators.
Expected output: Drawing: My Circle, Center: (100, 200), Radius: 50, Area: 7850
Show Solution
#include
typedef struct {
int x, y;
} Point;
typedef struct {
Point center;
int radius;
} Circle;
typedef struct {
char name[30];
Circle shape;
} Drawing;
void analyzeDrawing(Drawing *d) {
// Arrow for pointer, dot for each nested level
printf("Drawing: %s\n", d->name);
printf("Center: (%d, %d)\n",
d->shape.center.x, // Three levels: ptr->level1.level2.member
d->shape.center.y);
printf("Radius: %d\n", d->shape.radius);
double area = 3.14159 * d->shape.radius * d->shape.radius;
printf("Area: %.0f\n", area);
}
int main() {
Drawing d = {"My Circle", {{100, 200}, 50}};
analyzeDrawing(&d);
return 0;
}
Given:
struct Address { char city[50]; int zipCode; };
struct Person { char name[50]; Address addr; };
Person people[4] = {
{"Alice", {"NYC", 10001}},
{"Bob", {"LA", 90001}},
{"Charlie", {"NYC", 10002}},
{"Diana", {"Chicago", 60601}}
};
Task: Write code to search the array and print all people living in "NYC". Access nested members using array index and dot operator.
Expected output: Alice lives in NYC, Charlie lives in NYC
Show Solution
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
char name[50];
Address addr;
} Person;
int main() {
Person people[4] = {
{"Alice", {"NYC", 10001}},
{"Bob", {"LA", 90001}},
{"Charlie", {"NYC", 10002}},
{"Diana", {"Chicago", 60601}}
};
const char *searchCity = "NYC";
printf("People living in %s:\n", searchCity);
// Access nested member through array
for (int i = 0; i < 4; i++) {
if (strcmp(people[i].addr.city, searchCity) == 0) {
printf("%s lives in %s\n", people[i].name, people[i].addr.city);
}
}
return 0;
}
Initializing Nested Structures
Explore various methods to initialize nested structures including nested braces, designated initializers, and member-by-member assignment.
Method 1: Nested Braces Initialization
The most common approach is to use nested curly braces that match the structure hierarchy. Each inner brace initializes the corresponding nested structure.
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
int empId;
char name[50];
float salary;
Date joinDate;
} Employee;
int main() {
// Nested braces - matches structure hierarchy
Employee emp1 = {
101, // empId
"Priya Sharma", // name
75000.00, // salary
{15, 6, 2023} // joinDate (nested braces)
};
// Can also be written on one line
Employee emp2 = {102, "Rahul Patel", 68000.00, {10, 3, 2022}};
printf("%s joined on %d/%d/%d\n",
emp1.name, emp1.joinDate.day,
emp1.joinDate.month, emp1.joinDate.year);
return 0;
}
Method 2: Designated Initializers (C99)
C99 introduced designated initializers that let you specify member names explicitly. This is especially useful for nested structures as it improves readability.
typedef struct {
char city[50];
char state[30];
int zipCode;
} Address;
typedef struct {
int customerId;
char name[50];
Address billingAddr;
Address shippingAddr;
} Customer;
int main() {
// Designated initializers - very readable!
Customer c1 = {
.customerId = 1001,
.name = "Amit Kumar",
.billingAddr = {
.city = "Mumbai",
.state = "Maharashtra",
.zipCode = 400001
},
.shippingAddr = {
.city = "Pune",
.state = "Maharashtra",
.zipCode = 411001
}
};
printf("Ship to: %s, %s - %d\n",
c1.shippingAddr.city,
c1.shippingAddr.state,
c1.shippingAddr.zipCode);
return 0;
}
Method 3: Member-by-Member Assignment
For runtime initialization or when values are computed, assign each member individually after declaration.
typedef struct {
int day, month, year;
} Date;
typedef struct {
int rollNo;
char name[50];
Date dob;
float cgpa;
} Student;
int main() {
Student s;
// Outer members
s.rollNo = 2024001;
strcpy(s.name, "Neha Gupta");
s.cgpa = 8.75;
// Nested structure members
s.dob.day = 25;
s.dob.month = 12;
s.dob.year = 2002;
printf("%s (Roll: %d)\n", s.name, s.rollNo);
printf("DOB: %d/%d/%d\n", s.dob.day, s.dob.month, s.dob.year);
printf("CGPA: %.2f\n", s.cgpa);
return 0;
}
Method 4: Assigning Inner Structure Directly
You can create a temporary inner structure and assign it to the nested member in one go.
typedef struct {
char city[50];
int zip;
} Address;
typedef struct {
int id;
char name[50];
Address addr;
} Person;
int main() {
Person p;
p.id = 1;
strcpy(p.name, "Vikram Singh");
// Create and assign entire nested structure
Address homeAddr = {"Jaipur", 302001};
p.addr = homeAddr; // Assign entire struct at once
// Or use compound literal (C99)
p.addr = (Address){"Jodhpur", 342001};
printf("%s lives in %s\n", p.name, p.addr.city);
return 0;
}
Practice Questions: Initialization
Given:
struct Author { char name[50]; int yearBorn; };
struct Book { char title[100]; Author author; float price; };
Task: Initialize a Book variable with "C Programming Language" by "Brian Kernighan" (born 1942), priced at 599.99 using nested braces. Print the book details.
Expected output: Title: C Programming Language, Author: Brian Kernighan (1942), Price: 599.99
Show Solution
typedef struct {
char name[50];
int yearBorn;
} Author;
typedef struct {
char title[100];
Author author;
float price;
} Book;
int main() {
// Initialize Book with nested Author using nested braces
Book myBook = {
"C Programming Language",
{"Brian Kernighan", 1942}, // Nested Author initialization
599.99
};
printf("Title: %s\n", myBook.title);
printf("Author: %s (%d)\n", myBook.author.name, myBook.author.yearBorn);
printf("Price: %.2f\n", myBook.price);
return 0;
}
Given:
struct Point { int x, y; };
struct Rectangle { Point topLeft; Point bottomRight; char color[20]; };
Task: Initialize a Rectangle with topLeft at (10, 20), bottomRight at (100, 80), and color "blue" using designated initializers. Print the rectangle dimensions and color.
Expected output: Rectangle: (10,20) to (100,80), Color: blue, Width: 90, Height: 60
Show Solution
typedef struct {
int x, y;
} Point;
typedef struct {
Point topLeft;
Point bottomRight;
char color[20];
} Rectangle;
int main() {
// Use designated initializers (C99)
Rectangle rect = {
.topLeft = {.x = 10, .y = 20},
.bottomRight = {.x = 100, .y = 80},
.color = "blue"
};
int width = rect.bottomRight.x - rect.topLeft.x;
int height = rect.bottomRight.y - rect.topLeft.y;
printf("Rectangle: (%d,%d) to (%d,%d)\n",
rect.topLeft.x, rect.topLeft.y,
rect.bottomRight.x, rect.bottomRight.y);
printf("Color: %s\n", rect.color);
printf("Width: %d, Height: %d\n", width, height);
return 0;
}
Given:
struct Date { int day, month, year; };
struct Student { int rollNo; char name[50]; Date dateOfBirth; float gpa; };
Task: Initialize an array of 3 students with nested Date of birth using nested braces. Calculate and display ages of all students (assuming current year is 2025).
Expected output: Priya (2003) - Age 22, Rahul (2002) - Age 23, Neha (2001) - Age 24
Show Solution
typedef struct {
int day, month, year;
} Date;
typedef struct {
int rollNo;
char name[50];
Date dateOfBirth;
float gpa;
} Student;
int main() {
// Initialize array with nested Date structures
Student students[3] = {
{1001, "Priya Singh", {10, 5, 2003}, 8.5},
{1002, "Rahul Patel", {22, 11, 2002}, 8.2},
{1003, "Neha Gupta", {15, 8, 2001}, 8.8}
};
printf("Student Ages:\n");
for (int i = 0; i < 3; i++) {
int age = 2025 - students[i].dateOfBirth.year;
printf("%s (%d) - Age %d\n",
students[i].name,
students[i].dateOfBirth.year,
age);
}
return 0;
}
Given:
struct Date { int day, month, year; };
struct Person { char name[50]; Date birthDate; };
Task: Initialize a Person with name "Arjun" and only specify day (15) and month (6) of birthDate, leaving year uninitialized. Print all fields and observe default value for year.
Expected output: Name: Arjun, DOB: 15/6/0 (year defaults to 0)
Show Solution
typedef struct {
int day, month, year;
} Date;
typedef struct {
char name[50];
Date birthDate;
} Person;
int main() {
// Partial initialization - uninitialized members get default values
Person p = {"Arjun Kumar", {15, 6}}; // year not initialized
printf("Name: %s\n", p.name);
printf("DOB: %d/%d/%d\n",
p.birthDate.day, // 15 (initialized)
p.birthDate.month, // 6 (initialized)
p.birthDate.year); // 0 (default/uninitialized)
// Better approach - always initialize all fields
Person p2 = {"Priya Singh", {25, 12, 2000}};
printf("\nCorrected DOB: %d/%d/%d\n",
p2.birthDate.day,
p2.birthDate.month,
p2.birthDate.year);
return 0;
}
Arrays with Nested Structures
Learn how to create and manage arrays of structures that contain nested structures for complex data collections.
Declaring Arrays of Nested Structures
Combine arrays with nested structures to store collections of complex records, like a list of students with their addresses or employees with their dates.
typedef struct {
int day, month, year;
} Date;
typedef struct {
int empId;
char name[50];
Date joinDate;
float salary;
} Employee;
int main() {
// Array of 3 employees (each has nested Date)
Employee team[3] = {
{101, "Priya Sharma", {15, 6, 2020}, 75000},
{102, "Rahul Patel", {10, 3, 2021}, 68000},
{103, "Neha Gupta", {20, 9, 2022}, 72000}
};
// Access: array[index].nested.member
printf("First employee: %s\n", team[0].name);
printf("Joined: %d/%d/%d\n",
team[0].joinDate.day,
team[0].joinDate.month,
team[0].joinDate.year);
return 0;
}
Iterating Through the Array
void printAllEmployees(Employee arr[], int count) {
printf("\n%-5s %-20s %-15s %s\n", "ID", "Name", "Join Date", "Salary");
printf("---------------------------------------------------\n");
for (int i = 0; i < count; i++) {
printf("%-5d %-20s %02d/%02d/%04d Rs.%.2f\n",
arr[i].empId,
arr[i].name,
arr[i].joinDate.day,
arr[i].joinDate.month,
arr[i].joinDate.year,
arr[i].salary);
}
}
int main() {
Employee team[3] = {
{101, "Priya Sharma", {15, 6, 2020}, 75000},
{102, "Rahul Patel", {10, 3, 2021}, 68000},
{103, "Neha Gupta", {20, 9, 2022}, 72000}
};
printAllEmployees(team, 3);
return 0;
}
Searching in Arrays of Nested Structures
// Find employees who joined in a specific year
int findByJoinYear(Employee arr[], int count, int year) {
int found = 0;
printf("Employees who joined in %d:\n", year);
for (int i = 0; i < count; i++) {
if (arr[i].joinDate.year == year) {
printf(" - %s (ID: %d)\n", arr[i].name, arr[i].empId);
found++;
}
}
if (found == 0) {
printf(" No employees found.\n");
}
return found;
}
int main() {
Employee team[5] = {
{101, "Priya", {15, 6, 2021}, 75000},
{102, "Rahul", {10, 3, 2022}, 68000},
{103, "Neha", {20, 9, 2021}, 72000},
{104, "Amit", {5, 1, 2023}, 65000},
{105, "Meera", {12, 7, 2022}, 70000}
};
findByJoinYear(team, 5, 2021); // Finds Priya and Neha
findByJoinYear(team, 5, 2022); // Finds Rahul and Meera
return 0;
}
Sorting by Nested Member
#include <string.h>
// Sort employees by join date (year, then month, then day)
void sortByJoinDate(Employee arr[], int count) {
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - i - 1; j++) {
Date d1 = arr[j].joinDate;
Date d2 = arr[j + 1].joinDate;
// Compare: year first, then month, then day
int swap = 0;
if (d1.year > d2.year) swap = 1;
else if (d1.year == d2.year && d1.month > d2.month) swap = 1;
else if (d1.year == d2.year && d1.month == d2.month && d1.day > d2.day) swap = 1;
if (swap) {
Employee temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
Employee team[3] = {
{102, "Rahul", {10, 3, 2022}, 68000},
{101, "Priya", {15, 6, 2020}, 75000},
{103, "Neha", {20, 9, 2021}, 72000}
};
printf("Before sorting:\n");
for (int i = 0; i < 3; i++)
printf("%s - %d/%d/%d\n", team[i].name,
team[i].joinDate.day, team[i].joinDate.month, team[i].joinDate.year);
sortByJoinDate(team, 3);
printf("\nAfter sorting by join date:\n");
for (int i = 0; i < 3; i++)
printf("%s - %d/%d/%d\n", team[i].name,
team[i].joinDate.day, team[i].joinDate.month, team[i].joinDate.year);
return 0;
}
Practice Questions: Arrays with Nested Structures
Given:
struct Author { char name[50]; int yearPublished; };
struct Book { char title[100]; Author author; float price; };
Task: Create an array of 3 books with authors and prices. Loop through and print all book titles with author names.
Expected output: 1. The C Bible by Kernighan, 2. Data Structures by Tanenbaum, 3. Clean Code by Martin
Show Solution
typedef struct {
char name[50];
int yearPublished;
} Author;
typedef struct {
char title[100];
Author author;
float price;
} Book;
int main() {
Book library[3] = {
{"The C Bible", {"Kernighan", 1988}, 599.00},
{"Data Structures", {"Tanenbaum", 2009}, 450.00},
{"Clean Code", {"Robert Martin", 2008}, 699.00}
};
printf("Library Catalog:\n");
for (int i = 0; i < 3; i++) {
printf("%d. %s by %s (%.2f)\n",
i + 1,
library[i].title,
library[i].author.name,
library[i].price);
}
return 0;
}
Given:
struct Date { int day, month, year; };
struct Student { int rollNo; char name[50]; Date birthday; };
Student class[4] = {{1, "Priya", {15, 6, 2002}}, {2, "Rahul", {22, 6, 2001}}, ...};
Task: Write a function to find and print all students with birthday in June (month = 6). Display their names and birth dates.
Expected output: Birthdays in June: Priya - 15 June, Rahul - 22 June, Amit - 5 June
Show Solution
typedef struct {
int day, month, year;
} Date;
typedef struct {
int rollNo;
char name[50];
Date birthday;
} Student;
void findBirthdaysInMonth(Student arr[], int count, int month) {
char* monthNames[] = {"", "January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December"};
printf("Birthdays in %s:\n", monthNames[month]);
int found = 0;
for (int i = 0; i < count; i++) {
if (arr[i].birthday.month == month) {
printf(" %s - %d %s\n", arr[i].name,
arr[i].birthday.day, monthNames[month]);
found++;
}
}
if (found == 0) printf(" No birthdays found.\n");
}
int main() {
Student class[4] = {
{1, "Priya", {15, 6, 2002}},
{2, "Rahul", {22, 6, 2001}},
{3, "Neha", {10, 12, 2002}},
{4, "Amit", {5, 6, 2003}}
};
findBirthdaysInMonth(class, 4, 6); // June birthdays
return 0;
}
Given:
struct Author { char name[50]; char country[30]; };
struct Book { char title[100]; Author author; float price; };
Array of 5 books with multiple authors, some authors appear twice
Task: Write a function to search the library array and calculate the average price of all books by a specific author. Return 0 if author not found.
Expected output: Average price of books by Robert Martin: 699.00
Show Solution
typedef struct {
char name[50];
char country[30];
} Author;
typedef struct {
char title[100];
Author author;
float price;
} Book;
float getAuthorAveragePrice(Book arr[], int count, const char *authorName) {
float total = 0;
int found = 0;
for (int i = 0; i < count; i++) {
if (strcmp(arr[i].author.name, authorName) == 0) {
total += arr[i].price;
found++;
}
}
return found > 0 ? total / found : 0;
}
int main() {
Book library[5] = {
{"Clean Code", {"Robert Martin", "USA"}, 699.00},
{"Code Complete", {"Steve McConnell", "USA"}, 749.00},
{"Refactoring", {"Martin Fowler", "UK"}, 599.00},
{"The Pragmatic Programmer", {"Hunt & Thomas", "USA"}, 649.00},
{"Design Patterns", {"Gang of Four", "USA"}, 799.00}
};
float avg = getAuthorAveragePrice(library, 5, "Robert Martin");
printf("Average price by Robert Martin: %.2f\n", avg); // 699.00
// Test with author having multiple books
// (In this case, each author has only one book)
return 0;
}
Given:
struct Address { char city[50]; int zipCode; };
struct Employee { int empId; char name[50]; Address addr; };
Array of 4 employees with different cities: Bangalore (2), Mumbai (1), Delhi (1)
Task: Write a function to count how many employees live in "Bangalore". Loop through array, check nested city field, and return count.
Expected output: Employees in Bangalore: 2
Show Solution
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
int empId;
char name[50];
Address addr;
} Employee;
int countEmployeesInCity(Employee arr[], int count, const char *city) {
int cityCount = 0;
for (int i = 0; i < count; i++) {
if (strcmp(arr[i].addr.city, city) == 0) {
cityCount++;
printf(" %s (ID: %d) - %s\n", arr[i].name, arr[i].empId, arr[i].addr.city);
}
}
return cityCount;
}
int main() {
Employee team[4] = {
{101, "Alice", {"Bangalore", 560001}},
{102, "Bob", {"Bangalore", 560002}},
{103, "Charlie", {"Mumbai", 400001}},
{104, "Diana", {"Delhi", 110001}}
};
printf("Employees in Bangalore:\n");
int count = countEmployeesInCity(team, 4, "Bangalore");
printf("Total: %d employees\n", count); // 2
return 0;
}
Functions and Nested Structures
Understand how to pass nested structures to functions and return them, enabling modular and reusable code design.
Passing Nested Structures by Value
When you pass a nested structure to a function, the entire structure (including all nested data) is copied. Changes inside the function do NOT affect the original.
typedef struct {
int day, month, year;
} Date;
typedef struct {
int empId;
char name[50];
Date joinDate;
} Employee;
// Receives a COPY of the entire structure
void printEmployee(Employee e) {
printf("ID: %d\n", e.empId);
printf("Name: %s\n", e.name);
printf("Joined: %02d/%02d/%04d\n",
e.joinDate.day, e.joinDate.month, e.joinDate.year);
}
int main() {
Employee emp = {101, "Priya Sharma", {15, 6, 2023}};
printEmployee(emp); // Pass by value
return 0;
}
Passing Nested Structures by Pointer
For large structures or when you need to modify the original, pass a pointer. Use arrow operator for the outer struct, dot for nested members.
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
int custId;
char name[50];
Address addr;
} Customer;
// Receives a POINTER - can modify original
void updateAddress(Customer *c, const char *newCity, int newZip) {
strcpy(c->addr.city, newCity); // ptr->nested.member
c->addr.zipCode = newZip;
}
// Read-only access with const pointer
void printCustomer(const Customer *c) {
printf("Customer: %s\n", c->name);
printf("Address: %s - %d\n", c->addr.city, c->addr.zipCode);
}
int main() {
Customer cust = {1001, "Rahul Patel", {"Mumbai", 400001}};
printCustomer(&cust);
updateAddress(&cust, "Pune", 411001);
printf("\nAfter update:\n");
printCustomer(&cust);
return 0;
}
Returning Nested Structures
Functions can return structures with nested members. This is useful for creating and initializing complex objects.
typedef struct {
int day, month, year;
} Date;
typedef struct {
int orderId;
float amount;
Date orderDate;
} Order;
// Function to create an order with today's date
Order createOrder(int id, float amount, int d, int m, int y) {
Order newOrder;
newOrder.orderId = id;
newOrder.amount = amount;
newOrder.orderDate.day = d;
newOrder.orderDate.month = m;
newOrder.orderDate.year = y;
return newOrder; // Returns entire structure
}
// Alternative using compound literals (C99)
Order createOrderAlt(int id, float amount, Date date) {
return (Order){id, amount, date};
}
int main() {
Order o1 = createOrder(1001, 2599.99, 30, 1, 2025);
printf("Order #%d\n", o1.orderId);
printf("Amount: Rs. %.2f\n", o1.amount);
printf("Date: %02d/%02d/%04d\n",
o1.orderDate.day, o1.orderDate.month, o1.orderDate.year);
// Using alternative function
Date today = {30, 1, 2025};
Order o2 = createOrderAlt(1002, 1599.00, today);
return 0;
}
Complete Example: Student Management System
#include <stdio.h>
#include <string.h>
typedef struct {
int day, month, year;
} Date;
typedef struct {
char city[50];
char state[30];
int pin;
} Address;
typedef struct {
int rollNo;
char name[50];
Date dob;
Address addr;
float cgpa;
} Student;
// Create a new student
Student createStudent(int roll, const char *name, Date dob, Address addr, float cgpa) {
Student s;
s.rollNo = roll;
strncpy(s.name, name, 49);
s.dob = dob;
s.addr = addr;
s.cgpa = cgpa;
return s;
}
// Display student details
void displayStudent(const Student *s) {
printf("\n========== Student Record ==========\n");
printf("Roll No: %d\n", s->rollNo);
printf("Name: %s\n", s->name);
printf("DOB: %02d/%02d/%04d\n", s->dob.day, s->dob.month, s->dob.year);
printf("Address: %s, %s - %d\n", s->addr.city, s->addr.state, s->addr.pin);
printf("CGPA: %.2f\n", s->cgpa);
printf("====================================\n");
}
// Update student address
void updateStudentAddress(Student *s, Address newAddr) {
s->addr = newAddr; // Copy entire nested structure
}
int main() {
Date dob = {15, 8, 2002};
Address addr = {"Delhi", "Delhi", 110001};
Student student = createStudent(2024001, "Arun Kumar", dob, addr, 8.5);
displayStudent(&student);
// Update address
Address newAddr = {"Mumbai", "Maharashtra", 400001};
updateStudentAddress(&student, newAddr);
printf("\nAfter address update:");
displayStudent(&student);
return 0;
}
Practice Questions: Functions and Nested Structures
Given: A Date structure with day, month, year fields.
Task: Write a function printDate() that receives a Date structure by value and prints it in DD/MM/YYYY format. Call it with today's date (30/01/2025).
Expected output:
Today is: 30/01/2025
Show Solution
typedef struct {
int day, month, year;
} Date;
void printDate(Date d) {
printf("%02d/%02d/%04d", d.day, d.month, d.year);
}
int main() {
Date today = {30, 1, 2025};
printf("Today is: ");
printDate(today); // Pass by value - function receives a COPY
printf("\n");
return 0;
}
Given: Person structure with nested Address (city, zipCode). Initial person: Vikram from Delhi (110001).
Task: Write a relocate() function that takes a Person pointer and modifies the nested Address fields. Relocate Vikram to Bangalore (560001) and print confirmation message.
Expected output:
Before: Vikram lives in Delhi
After: Vikram relocated to Bangalore - 560001
Show Solution
typedef struct {
char city[50];
int zipCode;
} Address;
typedef struct {
char name[50];
Address addr;
} Person;
void relocate(Person *p, const char *city, int zipCode) {
strcpy(p->addr.city, city); // ptr->nested.member
p->addr.zipCode = zipCode;
}
int main() {
Person p = {"Vikram", {"Delhi", 110001}};
printf("Before: %s lives in %s\n", p.name, p.addr.city);
relocate(&p, "Bangalore", 560001); // Pass by pointer to modify original
printf("After: %s relocated to %s - %d\n", p.name, p.addr.city, p.addr.zipCode);
return 0;
}
Given: Point structure (x, y) and Circle structure with nested Point center, radius, and color.
Task: Write createCircle() function that constructs and returns a Circle with center at (100, 200), radius 50, color "red". Write printCircle() to display all details.
Expected output:
Circle at (100, 200) with radius 50, color: red
Show Solution
typedef struct {
int x, y;
} Point;
typedef struct {
Point center; // Nested structure
int radius;
char color[20];
} Circle;
// Function returns entire nested structure
Circle createCircle(int x, int y, int r, const char *col) {
Circle c;
c.center.x = x; // Assign to nested member
c.center.y = y;
c.radius = r;
strcpy(c.color, col);
return c; // Returns entire Circle (including nested Point)
}
void printCircle(const Circle *c) {
printf("Circle at (%d, %d) with radius %d, color: %s\n",
c->center.x, c->center.y, c->radius, c->color);
}
int main() {
Circle myCircle = createCircle(100, 200, 50, "red");
printCircle(&myCircle);
return 0;
}
Given: Employee structure with nested Address (street, city, zipCode). Employee ID 101, name "Varun", address "123 Main St, Bangalore, 560001".
Task: Write displayEmployeeAddress() function that receives Employee pointer and prints employee ID, name, and all nested address fields on separate lines.
Expected output:
Employee: Varun (ID: 101)
Address: 123 Main St
City: Bangalore
ZIP: 560001
Show Solution
typedef struct {
char street[100];
char city[50];
int zipCode;
} Address;
typedef struct {
int empId;
char name[50];
Address addr; // Nested structure
} Employee;
void displayEmployeeAddress(const Employee *emp) {
printf("Employee: %s (ID: %d)\n", emp->name, emp->empId);
printf("Address: %s\n", emp->addr.street); // ptr->nested.member
printf("City: %s\n", emp->addr.city);
printf("ZIP: %d\n", emp->addr.zipCode);
}
int main() {
Employee emp = {101, "Varun", {"123 Main St", "Bangalore", 560001}};
displayEmployeeAddress(&emp); // Pass by pointer for read-only access
return 0;
}
Interactive Demo: Nested Structure Visualizer
Build a nested structure visually and see the generated C code with proper initialization.
Build Your Structure
Generated C Code
// Click "Generate Code" to see the result
typedef struct {
int day;
int month;
} Date;
typedef struct {
int id;
char name[50];
Date joinDate;
} Employee;
Access Pattern:
emp.joinDate.day
Interactive: Access Syntax Challenge
Test your understanding by selecting the correct syntax to access nested structure members.
struct Address { char city[50]; int zip; };
struct Person { char name[50]; Address addr; };
Person p;
Question 1 of 5
How do you access the zip code?
Key Takeaways
Hierarchical Data
Nested structures let you model complex hierarchical relationships by embedding one structure inside another
Dot Operator Chaining
Access nested members by chaining the dot operator: outer.inner.member for each level of nesting
Nested Braces Initialization
Use nested curly braces to initialize nested structures at declaration time for clear, readable code
Arrow Operator for Pointers
When working with pointers to nested structures, combine arrow and dot operators appropriately
Arrays of Nested Structures
Combine arrays with nested structures to manage collections of complex hierarchical data
Modular Design
Define inner structures separately and reuse them across multiple outer structures for cleaner code
Knowledge Check
Quick Quiz
Test what you've learned about nested structures in C