Chapter 11: Structures and Unions

📌 Learning Objectives
  • LO 11.1: Define and declare structures
  • LO 11.2: Access structure members and initialize structures
  • LO 11.3: Work with arrays of structures and nested structures
  • LO 11.4: Pass structures to functions
  • LO 11.5: Understand unions and their differences from structures
  • LO 11.6: Use bit fields for memory optimization

11.1 Introduction to Structures

Structures are a powerful feature in C that allow us to group together data items of different types under a single name. Unlike arrays, which store elements of the same type, structures can contain a collection of logically related data items of different types.

Examples where structures are useful:

11.2 Defining a Structure

A structure is defined using the struct keyword. The definition creates a template or format for the structure.

struct book_bank {
    char title[50];
    char author[30];
    int pages;
    float price;
};

Here, struct book_bank is the structure tag, and title, author, pages, and price are structure members or fields.

Memory layout of struct book_bank:

        ┌─────────────────────────────────────────────┐
title   │  C  │  P  │  r  │  o  │  g  │  r  │  a  │  m  │ ... │
        └─────────────────────────────────────────────┘
        ┌─────────────────────────────────────────────┐
author  │  B  │  a  │  l  │  a  │  g  │  u  │  r  │  u  │ ... │
        └─────────────────────────────────────────────┘
        ┌─────────┐
pages   │   350   │
        └─────────┘
        ┌─────────┐
price   │ 250.50  │
        └─────────┘

Arrays vs Structures

ArraysStructures
Collection of elements of same typeCollection of elements of different types
Derived data typeProgrammer-defined data type
Accessed using indexAccessed using member operator (.)
No keyword neededUses struct keyword

11.3 Declaring Structure Variables

After defining the structure, we can declare variables of that type:

struct book_bank book1, book2, book3;

We can also combine definition and declaration in one step:

struct book_bank {
    char title[50];
    char author[30];
    int pages;
    float price;
} book1, book2, book3;

Using typedef with Structures

typedef struct {
    char title[50];
    char author[30];
    int pages;
    float price;
} Book;

Book book1, book2;  // No need for 'struct' keyword

11.4 Accessing Structure Members

Structure members are accessed using the dot operator (.) or member operator.

book1.pages = 350;
book1.price = 250.50;
strcpy(book1.title, "Programming in C");
strcpy(book1.author, "Balagurusamy");

printf("Title: %s\n", book1.title);
printf("Author: %s\n", book1.author);
printf("Pages: %d\n", book1.pages);
printf("Price: %.2f\n", book1.price);

📝 Worked-Out Problem 11.1

Defining and accessing structure members:

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

int main() {
    struct book_bank {
        char title[50];
        char author[30];
        int pages;
        float price;
    };
    
    struct book_bank book1, book2;
    
    // Assign values to book1
    strcpy(book1.title, "Programming in C");
    strcpy(book1.author, "Balagurusamy");
    book1.pages = 350;
    book1.price = 250.50;
    
    // Input values for book2
    printf("Enter book title: ");
    gets(book2.title);
    printf("Enter author name: ");
    gets(book2.author);
    printf("Enter pages: ");
    scanf("%d", &book2.pages);
    printf("Enter price: ");
    scanf("%f", &book2.price);
    
    // Display book information
    printf("\nBook 1:\n");
    printf("Title: %s\n", book1.title);
    printf("Author: %s\n", book1.author);
    printf("Pages: %d\n", book1.pages);
    printf("Price: %.2f\n", book1.price);
    
    printf("\nBook 2:\n");
    printf("Title: %s\n", book2.title);
    printf("Author: %s\n", book2.author);
    printf("Pages: %d\n", book2.pages);
    printf("Price: %.2f\n", book2.price);
    
    return 0;
}

11.5 Structure Initialization

Structure variables can be initialized at compile time:

struct book_bank {
    char title[50];
    char author[30];
    int pages;
    float price;
};

struct book_bank book1 = {"Programming in C", "Balagurusamy", 350, 250.50};
struct book_bank book2 = {"C++ Programming", "Stroustrup", 450, 350.75};

Rules for initialization:

11.6 Copying and Comparing Structure Variables

Two structure variables of the same type can be copied directly:

book2 = book1;  // Copies all members from book1 to book2
⚠️ Important: C does not allow direct comparison of structures using relational operators. The following are illegal:
if (book1 == book2)    // Error
if (book1 != book2)    // Error

To compare structures, we must compare each member individually.

📝 Worked-Out Problem 11.2

Comparing and copying structure variables:

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

struct class {
    int number;
    char name[20];
    float marks;
};

int main() {
    struct class student1 = {101, "John", 85.5};
    struct class student2;
    int equal = 1;
    
    // Copy structure
    student2 = student1;
    
    printf("Student 1: %d %s %.2f\n", student1.number, student1.name, student1.marks);
    printf("Student 2: %d %s %.2f\n", student2.number, student2.name, student2.marks);
    
    // Compare member by member
    if (student1.number != student2.number) equal = 0;
    if (strcmp(student1.name, student2.name) != 0) equal = 0;
    if (student1.marks != student2.marks) equal = 0;
    
    if (equal)
        printf("\nBoth structures are equal\n");
    else
        printf("\nStructures are not equal\n");
    
    return 0;
}
Output:
Student 1: 101 John 85.50
Student 2: 101 John 85.50

Both structures are equal

11.7 Arrays of Structures

We can create arrays of structures to store multiple records of the same type.

struct book_bank library[100];  // Array of 100 books

📝 Worked-Out Problem 11.3

Processing student marks using array of structures:

#include <stdio.h>

struct student {
    int roll_no;
    char name[20];
    int marks[3];  // marks in 3 subjects
    int total;
};

int main() {
    struct student s[3];
    int i, j;
    
    // Input data for 3 students
    for (i = 0; i < 3; i++) {
        printf("Enter details for student %d:\n", i+1);
        printf("Roll No: ");
        scanf("%d", &s[i].roll_no);
        printf("Name: ");
        scanf("%s", s[i].name);
        printf("Enter marks in 3 subjects: ");
        s[i].total = 0;
        for (j = 0; j < 3; j++) {
            scanf("%d", &s[i].marks[j]);
            s[i].total += s[i].marks[j];
        }
    }
    
    // Display results
    printf("\nRoll No\tName\tTotal\tAverage\n");
    for (i = 0; i < 3; i++) {
        printf("%d\t%s\t%d\t%.2f\n", s[i].roll_no, s[i].name, 
               s[i].total, s[i].total / 3.0);
    }
    
    return 0;
}
Output:
Enter details for student 1:
Roll No: 101
Name: John
Enter marks in 3 subjects: 85 90 88
...

Roll No Name Total Average
101 John 263 87.67
102 Alice 270 90.00
103 Bob 245 81.67

11.8 Arrays within Structures

Structures can have arrays as members, as seen in the example above where marks[3] is an array within the structure.

11.9 Structures within Structures (Nested Structures)

Structures can be nested, meaning one structure can contain another structure as a member.

struct address {
    char street[50];
    char city[30];
    int pin;
};

struct employee {
    char name[30];
    int emp_id;
    struct address addr;  // nested structure
    float salary;
};

Accessing nested members:

struct employee emp;
strcpy(emp.name, "Ramesh");
emp.emp_id = 1001;
strcpy(emp.addr.city, "Mumbai");  // Note the double dot operator
emp.salary = 50000.00;

📝 Worked-Out Problem 11.4

Nested structures for employee records:

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

struct address {
    char street[50];
    char city[30];
    int pin;
};

struct employee {
    char name[30];
    int emp_id;
    struct address addr;
    float salary;
};

int main() {
    struct employee emp;
    
    strcpy(emp.name, "Ramesh Kumar");
    emp.emp_id = 1001;
    strcpy(emp.addr.street, "MG Road");
    strcpy(emp.addr.city, "Bangalore");
    emp.addr.pin = 560001;
    emp.salary = 45000.00;
    
    printf("Employee Details:\n");
    printf("Name: %s\n", emp.name);
    printf("Employee ID: %d\n", emp.emp_id);
    printf("Address: %s, %s - %d\n", emp.addr.street, emp.addr.city, emp.addr.pin);
    printf("Salary: %.2f\n", emp.salary);
    
    return 0;
}
Output:
Employee Details:
Name: Ramesh Kumar
Employee ID: 1001
Address: MG Road, Bangalore - 560001
Salary: 45000.00

11.10 Structures and Functions

There are three ways to pass structures to functions:

  1. Pass individual members
  2. Pass the entire structure (by value)
  3. Pass a pointer to the structure (by address)

Passing Individual Members

void display(int roll, char name[], float marks) {
    printf("%d %s %.2f\n", roll, name, marks);
}

Passing Entire Structure (by value)

📝 Worked-Out Problem 11.5

Passing structure to function by value:

#include <stdio.h>

struct stores {
    char name[20];
    float price;
    int quantity;
};

float mul(struct stores product) {
    return product.price * product.quantity;
}

struct stores update(struct stores product, float p_inc, int q_inc) {
    product.price += p_inc;
    product.quantity += q_inc;
    return product;
}

int main() {
    struct stores item = {"Widget", 25.75, 12};
    float value;
    
    printf("Original: %s %.2f %d\n", item.name, item.price, item.quantity);
    value = mul(item);
    printf("Total value = %.2f\n", value);
    
    item = update(item, 5.00, 3);
    printf("After update: %s %.2f %d\n", item.name, item.price, item.quantity);
    value = mul(item);
    printf("New total value = %.2f\n", value);
    
    return 0;
}
Output:
Original: Widget 25.75 12
Total value = 309.00
After update: Widget 30.75 15
New total value = 461.25

Passing Structure Pointer (by reference)

This is more efficient as it avoids copying the entire structure.

void update(struct stores *product, float p_inc, int q_inc) {
    product->price += p_inc;
    product->quantity += q_inc;
}

// In main: update(&item, 5.00, 3);

11.11 Unions

A union is similar to a structure in syntax, but with a major difference in storage. In a union, all members share the same memory location. Only one member can be used at a time.

union item {
    int m;
    float x;
    char c;
};

The size of a union is the size of its largest member. For the above union, if float is 4 bytes, the union will occupy 4 bytes.

Union storage (all members share same memory):

        ┌───────────────────────┐
        │                       │
        │   4 bytes of memory   │
        │                       │
        └───────────────────────┘
          ▲          ▲          ▲
          │          │          │
        m (int)    x (float)  c (char)

📝 Worked-Out Problem 11.6

Demonstrating union:

#include <stdio.h>

union item {
    int m;
    float x;
    char c;
};

int main() {
    union item u;
    
    u.m = 100;
    printf("As integer: %d\n", u.m);
    
    u.x = 45.75;
    printf("As float: %.2f\n", u.x);
    printf("As integer after assigning float: %d (garbage!)\n", u.m);
    
    u.c = 'A';
    printf("As char: %c\n", u.c);
    printf("Size of union: %lu bytes\n", sizeof(u));
    
    return 0;
}
Output:
As integer: 100
As float: 45.75
As integer after assigning float: 1114636288 (garbage!)
As char: A
Size of union: 4 bytes

Note: The integer value becomes garbage after assigning a float because the memory now holds floating-point representation.

Union vs Structure

FeatureStructureUnion
Memory allocationEach member has its own memoryAll members share the same memory
SizeSum of sizes of all members (+ padding)Size of largest member
Member usageAll members can be used simultaneouslyOnly one member at a time
InitializationCan initialize multiple membersCan only initialize first member

11.12 Size of Structures

The sizeof operator can be used to determine the size of a structure:

printf("Size of structure: %lu\n", sizeof(struct book_bank));

Due to word boundaries and alignment requirements, the actual size may be larger than the sum of individual member sizes (slack bytes).

11.13 Bit Fields

Bit fields allow us to pack data into a smaller number of bits, saving memory when dealing with small integer values.

struct personal {
    unsigned int sex : 1;        // 0 or 1
    unsigned int age : 7;         // 0-127
    unsigned int marital_status : 1;  // 0 or 1
    unsigned int children : 3;     // 0-7
};

In this example, sex uses only 1 bit, age uses 7 bits, etc., instead of using full integers.

⚠️ Restrictions on bit fields:
  • Cannot take the address of a bit field (no & operator)
  • Cannot use scanf to read values into bit fields
  • Cannot have arrays of bit fields
  • Bit fields are machine-dependent (bit ordering may vary)

📝 Worked-Out Problem 11.7

Using bit fields:

#include <stdio.h>

struct personal {
    unsigned int sex : 1;
    unsigned int age : 7;
    unsigned int marital_status : 1;
    unsigned int children : 3;
};

int main() {
    struct personal emp;
    int temp;
    
    printf("Enter sex (0-Male, 1-Female): ");
    scanf("%d", &temp);
    emp.sex = temp;
    
    printf("Enter age: ");
    scanf("%d", &temp);
    emp.age = temp;
    
    printf("Enter marital status (0-Unmarried, 1-Married): ");
    scanf("%d", &temp);
    emp.marital_status = temp;
    
    printf("Enter number of children: ");
    scanf("%d", &temp);
    emp.children = temp;
    
    printf("\nEmployee Details:\n");
    printf("Sex: %s\n", emp.sex ? "Female" : "Male");
    printf("Age: %u\n", emp.age);
    printf("Marital Status: %s\n", emp.marital_status ? "Married" : "Unmarried");
    printf("Children: %u\n", emp.children);
    printf("Size of structure: %lu bytes\n", sizeof(emp));
    
    return 0;
}
Output:
Enter sex (0-Male, 1-Female): 0
Enter age: 35
Enter marital status (0-Unmarried, 1-Married): 1
Enter number of children: 2

Employee Details:
Sex: Male
Age: 35
Marital Status: Married
Children: 2
Size of structure: 4 bytes

Note: Without bit fields, this structure might use 16 bytes (4 ints). With bit fields, it uses only 4 bytes.

Important Points to Remember

  • Always place a semicolon at the end of structure definition.
  • Structure members are accessed using the dot operator (.) for variables and arrow operator (->) for pointers.
  • Structures cannot be compared directly using relational operators.
  • Assigning one structure to another of the same type is allowed.
  • When passing structures to functions, passing by pointer is more efficient.
  • Unions save memory but require careful handling to access the correct member.
  • Bit fields are useful for memory-constrained applications but are machine-dependent.
  • The sizeof operator can be used to determine the actual size of a structure.

Chapter Exercises

Review Questions

  1. State true or false:
    a) A struct type in C is a built-in data type.
    b) The tag name of a structure is optional.
    c) Structures may contain members of only one data type.
    d) The keyword typedef is used to define a new data type.
    e) It is legal to copy the content of one structure variable to another of the same type.
    f) Pointers can be used to access members of structure variables.
    g) We can perform mathematical operations on structure variables.
    h) A member in a structure can itself be a structure.
  2. How does a structure differ from an array?
  3. Explain the meaning and purpose of: template, struct keyword, typedef keyword, sizeof operator, tag name.
  4. What is a 'slack byte'? How does it affect the implementation of structures?
  5. Describe three different approaches to pass structures as function arguments.

Multiple Choice Questions

  1. Which of the following is the correct way to access structure members?
    a) Using dot notation: v.x
    b) Using indirection notation: (*ptr).x
    c) Using selection notation: ptr->x
    d) All of the above
  2. Which of the following is true about structures and functions?
    a) A pointer to a structure can be passed as a function argument
    b) It is possible to return a structure variable from a function
    c) The structure variables used in actual and formal arguments must be of the same type
    d) All of the above
  3. Which of the following is incorrect about Union?
    a) The size of a union variable is equal to the size of its largest member
    b) A union can be initialized only with a value of the same type as the first member
    c) Union does not support nesting
    d) At any given point, a union variable can store only one member type
  4. Which operators can be used with structure variables?
    a) =
    b) +
    c) ==
    d) !=
  5. What will be the output of:
    struct test { int x; int y; } t1 = {5, 0};
    t1.y = t1.x++;
    printf("%d, %d", t1.x, t1.y);

    a) 5, 0
    b) 6, 5
    c) 5, 5
    d) Compilation error

Debugging Exercises

Find errors in the following structure definitions and statements:

struct {
    int x;
    int y;
} a, b;

a = {10, 20};  // Error?

struct point p1;
p1.x = 10; p1.y = 20;
struct point p2 = p1;  // Error?

struct student {
    char name[20];
    int roll_no;
    float marks;
} s1;

s1 = {"John", 101, 85.5};  // Error?

union data {
    int i;
    float f;
    char str[20];
} u = {10, 25.5};  // Error?

Programming Exercises

  1. Define a structure called time_struct with members hour, minute, second. Write a program to assign values and display the time in HH:MM:SS format.
  2. Design a function update that accepts a time structure and increments it by one second, handling rollovers.
  3. Define a date structure with day, month, year. Write functions to read a date, validate it, and print it in "April 29, 2002" format.
  4. Write a function nextdate that takes a date and an integer n, and returns the date after n days.
  5. Create a structure cricket with player name, team name, batting average. Store 50 players and print team-wise lists.
  6. Define a structure to represent a vector and write functions to create, modify, add, and display vectors.
  7. Create two structures metric (meters, cm) and british (feet, inches). Write a program to add values from both systems and display in desired format.
  8. Define a structure census with city name, population, literacy level. Write a program to sort and display based on different criteria.
  9. Write a program to demonstrate the difference between structure and union by comparing their sizes and member access.
  10. Create a structure for employee with name, ID, and a union for storing either monthly salary or hourly wage. Write a program to input and display accordingly.

Interview Questions

  1. What is the difference between structure and union in terms of object size?
  2. Which operators have the highest and lowest precedence in structures?
  3. What is a self-referential structure? Give an example.
  4. What are the different ways of creating new data types in C?
  5. Is the following structure definition valid?
    struct abc {
        int x;
        struct abc *ptr;
    };
  6. What is padding in structures? Why does it happen?
  7. Can a structure contain a pointer to itself? What is it called?
  8. What will be the output of:
    struct { char c; int i; } s;
    printf("%lu", sizeof(s));

Case Study: Book Shop Inventory

📝 Case Study: Book shop inventory management

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

struct date {
    int day;
    int month;
    int year;
};

struct record {
    char title[50];
    char author[30];
    struct date publication;
    float price;
    int stock;
};

int look_up(struct record table[], char s1[], char s2[], int m) {
    int i;
    for (i = 0; i < m; i++) {
        if (strcmp(s1, table[i].title) == 0 && 
            strcmp(s2, table[i].author) == 0)
            return i;
    }
    return -1;
}

void get(char string[]) {
    char c;
    int i = 0;
    
    while ((c = getchar()) != '\n' && i < 49)
        string[i++] = c;
    string[i] = '\0';
}

int main() {
    struct record book[] = {
        {"C Programming", "Balagurusamy", {15, 8, 2020}, 350.00, 50},
        {"C++ Programming", "Stroustrup", {10, 5, 2021}, 450.00, 30},
        {"Java Programming", "Herbert Schildt", {20, 3, 2019}, 400.00, 25}
    };
    
    char title[50], author[30];
    int n, pos, copies;
    char ch;
    
    printf("Enter title: ");
    get(title);
    printf("Enter author: ");
    get(author);
    
    pos = look_up(book, title, author, 3);
    
    if (pos == -1) {
        printf("Book not found in inventory.\n");
    } else {
        printf("\nBook Details:\n");
        printf("Title: %s\n", book[pos].title);
        printf("Author: %s\n", book[pos].author);
        printf("Publication Date: %d/%d/%d\n", 
               book[pos].publication.day,
               book[pos].publication.month,
               book[pos].publication.year);
        printf("Price: Rs. %.2f\n", book[pos].price);
        printf("Stock: %d\n", book[pos].stock);
        
        printf("\nEnter number of copies required: ");
        scanf("%d", &copies);
        
        if (copies <= book[pos].stock) {
            printf("Total cost: Rs. %.2f\n", book[pos].price * copies);
            book[pos].stock -= copies;
        } else {
            printf("Required copies not in stock.\n");
        }
    }
    
    return 0;
}
Output:
Enter title: C Programming
Enter author: Balagurusamy

Book Details:
Title: C Programming
Author: Balagurusamy
Publication Date: 15/8/2020
Price: Rs. 350.00
Stock: 50

Enter number of copies required: 5
Total cost: Rs. 1750.00