SrcForge

Lesson 23

Structures and Unions

Covers structure and union syntax, memory layout, initialization, nested structures, and differences between structures and unions.

Lesson content

What are Structures and Unions?

A structure (struct) is a user-defined data type that groups variables of different data types into a single unit. Each member has its own separate memory location.

A union is also a user-defined data type, but all its members share the same memory location. At any given time, only one member can hold a valid value.

  • A structure is like a house with multiple rooms. Each room stores different items independently.
  • A union is like a single room that can be rearranged for different purposes. Only one arrangement is useful at a time.

Why do they exist?

  • Keeping related information together
  • Improving code readability
  • Reducing memory usage (using unions)
  • Modeling real-world entities

Real-world use cases

  • Structures: student records, employee information, product details, bank accounts, game objects
  • Unions: memory optimization, embedded systems, hardware programming, communication protocols, interpreting the same memory in different ways

Prerequisites

  • Variables
  • Data types
  • Functions
  • Arrays
  • Pointers (basic understanding)
  • Classes (optional but helpful)

Structure syntax

struct Student
{
    int id;
    string name;
    float marks;
};

Student s1;

s1.id = 101;
s1.name = "Alice";
s1.marks = 92.5f;

Each member has its own storage.

Union syntax

union Data
{
    int number;
    float decimal;
    char letter;
};

Data d;

All members share the same memory block.

Structure memory

struct Example
{
    int x;
    char y;
    double z;
};

// Each member occupies separate memory.
// Padding may be added for alignment.

Union memory

union Example
{
    int x;
    float y;
    char z;
};

// Size equals the largest member.

Structure vs union

  • Memory allocation: separate for each member (structure) vs shared by all members (union)
  • All members usable together: yes for structure, no for union
  • Memory efficient: less for structure, more for union
  • Data safety: better for structure, overwriting possible for union
  • Typical use: general programming for structure, memory optimization for union

Initializing structures

Student s =
{
    1,
    "John",
    95.0f
    };

Initializing unions

Data d;

d.number = 100;

// Later:
d.decimal = 3.14f;

// The previous value of number is overwritten
// because both members share the same memory.

Example 1: Structure

#include <iostream>
#include <string>
using namespace std;

struct Student
{
    int id;
    string name;
    float marks;
};

int main()
{
    Student s;

    s.id = 101;
    s.name = "Alice";
    s.marks = 94.5f;

    cout << s.id << endl;
    cout << s.name << endl;
    cout << s.marks << endl;

    return 0;
}

Example 2: Array of structures

#include <iostream>
#include <string>
using namespace std;

struct Student
{
    string name;
    int age;
};

int main()
{
    Student students[2];

    students[0].name = "Tom";
    students[0].age = 20;

    students[1].name = "Emma";
    students[1].age = 22;

    for (int i = 0; i < 2; i++)
    {
        cout << students[i].name << " ";
        cout << students[i].age << endl;
    }

    return 0;
}

Example 3: Union

#include <iostream>
using namespace std;

union Data
{
    int number;
    float decimal;
};

int main()
{
    Data d;

    d.number = 100;

    cout << d.number << endl;

    d.decimal = 5.5f;

    cout << d.decimal << endl;

    return 0;
}

Example 4: Nested structures

#include <iostream>
#include <string>
using namespace std;

struct Address
{
    string city;
    string country;
};

struct Employee
{
    string name;
    Address address;
};

int main()
{
    Employee emp;

    emp.name = "David";
    emp.address.city = "London";
    emp.address.country = "UK";

    cout << emp.name << endl;
    cout << emp.address.city << endl;
    cout << emp.address.country << endl;

    return 0;
}

Example 5: Checking structure and union sizes

#include <iostream>
using namespace std;

struct StructExample
{
    int number;
    char letter;
    double value;
};

union UnionExample
{
    int number;
    char letter;
    double value;
};

int main()
{
    cout << sizeof(StructExample) << endl;

    cout << sizeof(UnionExample) << endl;

    return 0;
}

Common mistakes and pitfalls

  • Accessing an uninitialized structure member. Fix: initialize members before use
  • Assuming all union members keep their values. Fix: remember writing to one member overwrites the previous value
  • Ignoring structure padding when estimating memory. Fix: use sizeof() to determine the actual size
  • Forgetting the . operator to access members. Fix: use object.member or pointer->member
  • Reading a different union member than the one most recently written. Fix: only read the member that was last assigned

Best practices

  • Use structures for grouping related data
  • Prefer classes when data hiding and member functions are required
  • Use unions only when memory savings or low-level data representation is necessary
  • Initialize structure members to avoid undefined values
  • Use sizeof() rather than guessing object sizes
  • Consider std::variant (C++17 and later) instead of raw unions for type-safe alternatives

When not to use this

  • You need encapsulation, inheritance, or polymorphism (use classes)
  • Multiple union members must hold valid values simultaneously
  • Type safety is important and a modern alternative like std::variant is available
  • The grouped data requires complex behavior in addition to storage

Summary

  • Structures group related variables, with each member having its own memory
  • Unions group members that share the same memory location
  • Structures are ideal for representing real-world entities
  • Unions are useful for reducing memory usage in specialized scenarios
  • Structure size is typically the sum of its members plus possible padding
  • Union size equals the size of its largest member
  • Access structure members using the . operator (or -> for pointers)
  • Writing to one union member replaces the previous active value

Frequently asked questions

What is the main difference between a structure and a union?

A structure allocates separate memory for every member, allowing all members to store values simultaneously. A union shares one memory block among all members, so only one member's value is considered valid at a time.

Why would I use a union instead of a structure?

Use a union when memory usage is critical and only one of several possible values needs to be stored at any given time, such as in embedded systems or communication protocols.

Can a structure contain another structure?

Yes. This is called a nested structure, and it's commonly used to model complex real-world objects.

How do I find the size of a structure or union?

Use the sizeof operator, such as sizeof(Student) or sizeof(Data). The result includes any padding added by the compiler for alignment.

Should I use struct or class in modern C++?

Use a struct when you're primarily storing data and public access is appropriate. Use a class when you need encapsulation, private data, and member functions. The main language difference is the default access level: members of a struct are public by default, while members of a class are private by default.