Module 6.2

Nested Structures

Master the art of embedding structures within structures to create complex, hierarchical data models. Perfect for representing real-world entities with multiple levels of detail!

40 min read
Intermediate
Hands-on Examples
What You'll Learn
  • Define structures within structures
  • Access nested structure members
  • Initialize nested structures
  • Pass nested structures to functions
  • Build real-world data models
Contents
01

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.

Advantages
  • Logical grouping - Related data stays together
  • Reusability - Inner structures can be reused
  • Readability - Code mirrors real-world entities
  • Maintainability - Changes are localized
Common Use Cases
  • 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!
};
Key Insight: The nested approach lets you reuse the Address structure in other places (like Employee, Customer, Supplier) without duplicating code.

Visual Representation

struct Student
rollNo
int
name
char[50]
struct Address (addr)
street
char[100]
city
char[50]
zipCode
int

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:

  1. Order with Customer: An Order structure containing a Customer structure with name, email, and phone
  2. Employee with Date of Birth: An Employee structure containing a Date structure with day, month, and year
  3. 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]; };
02

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!
};
Best Practice: Define inner structures separately for maximum reusability. The 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
};
Note: Inline anonymous structures cannot be reused elsewhere. You also cannot declare separate variables of this inner type.

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 for struct 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.

03

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;
}
Syntax Pattern: 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;
}
04

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;
}
Advantage: Designated initializers allow you to initialize members in any order and skip members (which get zero-initialized).

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;
}
05

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;
}
06

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?

Score: 0/5
07

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

1 What is the correct way to access the city member of an Address structure nested inside an Employee structure variable emp?
2 Which is a valid way to initialize a nested structure at declaration?
3 If ptr is a pointer to a structure that contains a nested structure date with a member year, which syntax correctly accesses year?
4 What is the main advantage of defining inner structures separately before using them in outer structures?
5 In an array of structures where each structure contains a nested Date structure, how do you access the month of the 3rd element?
6 What happens when you assign one nested structure variable to another?
Answer all questions to check your score