Programming lesson
Mastering C++ Structures and Enums: A Step-by-Step Tutorial for Assignment 11
Learn how to use C++ structures, enums, and unions to pass data efficiently with this comprehensive tutorial based on Assignment 11. Includes real-world analogies and code examples.
Introduction: Why Structures Matter in C++
In the world of programming, organizing data is just as important as writing the logic that manipulates it. C++ provides a powerful tool called a structure (or struct) that allows you to group related variables under one name. Think of it like a player profile in a video game: you have a name, a jersey number, and a score all bundled together. Structures make your code cleaner, more readable, and easier to maintain. In this tutorial, we'll explore how to use structures, enums, and unions to solve three common programming tasks, directly inspired by Computer Science 1081 – Assignment #11. Whether you're a student working on your assignment or a developer brushing up on C++ fundamentals, these concepts are essential for building robust applications.
Understanding Structures: The Movie Data Example
Let's start with a simple scenario: storing information about a movie. Instead of creating separate variables for title, director, year, and runtime, we can define a structure called movieData. Here's how you might define it:
struct movieData {
string title;
string director;
int year;
int runtime; // in minutes
};Now you can create variables of type movieData and initialize them in two ways: using an initialization list or member-by-member. The initialization list is concise:
movieData movie1 = {"War of the Worlds", "Byron Haskin", 1953, 88};Member-by-member initialization gives you more control, especially when you need to set values conditionally:
movieData movie2;
movie2.title = "War of the Worlds";
movie2.director = "Stephen Spielberg";
movie2.year = 2005;
movie2.runtime = 118;To display the data, we create a function displayMovie that takes a const reference to avoid copying the entire structure. This is efficient and prevents accidental modification:
void displayMovie(const movieData &m) {
cout << "Title: " << m.title << endl;
cout << "Director: " << m.director << endl;
cout << "Released: " << m.year << endl;
cout << "Running Time: " << m.runtime << " minutes" << endl;
}This pattern is fundamental: define a structure, initialize it, and pass it to functions by reference. It's like creating a profile for a character in a game and then printing their stats. In the context of Assignment 11, you'll do exactly this with two movies of your choice. Maybe you pick a classic like Casablanca (1942) and a modern blockbuster like Dune: Part Two (2024) – the choice is yours!
Arrays of Structures: Tracking Team Stats
Now let's scale up. Instead of one movie, imagine you have 12 players on a basketball team. Each player has a name, number, and points scored. Using an array of structures is the perfect way to manage this data. Define a structure called player:
struct player {
string name;
int number;
int points;
};Then create an array of 12 players:
player team[12];To fill the array, write a function that prompts the user for input. Because arrays decay to pointers when passed to functions, you can pass it by reference to modify the original. However, a simpler approach is to pass the array and its size:
void inputPlayers(player p[], int size) {
for (int i = 0; i < size; i++) {
cout << "Player's name: ";
getline(cin, p[i].name);
cout << "Player's number: ";
cin >> p[i].number;
cout << "Points scored: ";
cin >> p[i].points;
cin.ignore(); // clear newline
}
}After input, display a table of all players and calculate total points. Also find the player with the highest points:
void displayStats(const player p[], int size) {
int total = 0;
int maxPoints = 0;
int maxIndex = 0;
cout << "NAME\t\tNUMBER\tPTS SCRD" << endl;
for (int i = 0; i < size; i++) {
cout << p[i].name << "\t\t" << p[i].number << "\t" << p[i].points << endl;
total += p[i].points;
if (p[i].points > maxPoints) {
maxPoints = p[i].points;
maxIndex = i;
}
}
cout << "TOTAL POINTS: " << total << endl;
cout << "The player who scored the most points is: " << p[maxIndex].name << " #" << p[maxIndex].number << endl;
}This is similar to how a sports app might display a leaderboard. For instance, during the 2026 NBA playoffs, you could track players like Luka Dončić or Jayson Tatum using such a structure. The key takeaway: arrays of structures let you handle collections of related data efficiently.
Advanced: Using Enums and Unions for Payroll
The third program introduces a more advanced concept: enums and unions. Imagine you need to calculate pay for two types of workers: hourly and salaried. Both share some common info (like gross pay) but have different specific fields. An enum allows you to define a type that can hold one of several named constants. A union allows you to store different data types in the same memory location, but only one at a time. Combined, they create a flexible structure.
Define an enum for the worker type:
enum WorkerType { HOURLY, SALARIED };Now define the outer structure containing the enum, a double for gross pay, and a union of two sub-structures:
struct Worker {
WorkerType type;
double grossPay;
union {
struct {
double hours;
double rate;
} hourly;
struct {
double salary;
double bonus;
} salaried;
};
};Note: In C++, anonymous unions (without a name) allow you to access members directly, like worker.hours. However, for clarity, you might name the union. The sample output suggests a named union, but the assignment says you can nest structs and unions. A common pattern is to have the union contain two named structs:
struct Worker {
WorkerType type;
double grossPay;
union {
struct {
double hours;
double rate;
} hourlyData;
struct {
double salary;
double bonus;
} salariedData;
} data;
};Then you access fields like worker.data.hourlyData.hours. The assignment says you can use a single definition, so the anonymous union approach is fine as long as it compiles. Let's use the anonymous version for simplicity.
Now write functions to get input for each type:
void getHourly(Worker &w) {
cout << "Enter the number of hours worked: ";
cin >> w.hours;
cout << "Enter the hourly pay rate: ";
cin >> w.rate;
w.grossPay = w.hours * w.rate;
}
void getSalaried(Worker &w) {
cout << "Enter the salary amount: ";
cin >> w.salary;
cout << "Enter the bonus amount: ";
cin >> w.bonus;
w.grossPay = w.salary + w.bonus;
}And a print function:
void printWorker(const Worker &w) {
if (w.type == HOURLY) {
cout << "Hourly Worker" << endl;
cout << "Hours: " << w.hours << endl;
cout << "Rate: $" << fixed << setprecision(2) << w.rate << endl;
} else {
cout << "Salaried Worker" << endl;
cout << "Salary: $" << w.salary << endl;
cout << "Bonus: $" << w.bonus << endl;
}
cout << "---" << endl;
cout << "Gross Pay: $" << w.grossPay << endl;
}In main, ask the user which type, then call the appropriate input function:
int main() {
Worker emp;
char choice;
cout << "(H)ourly or (S)alaried? ";
cin >> choice;
if (choice == 'H' || choice == 'h') {
emp.type = HOURLY;
getHourly(emp);
} else {
emp.type = SALARIED;
getSalaried(emp);
}
printWorker(emp);
return 0;
}This design is reminiscent of how modern payroll apps handle different employee types. For example, a gig economy platform like Uber might use a similar structure to store driver earnings (hourly) vs. salaried employees. Enums and unions give you the flexibility to handle multiple variants with a single data type.
Best Practices and Common Pitfalls
When working with structures, always remember to pass them by const reference to functions that only read data. This avoids unnecessary copying and prevents accidental changes. For arrays of structures, use loops to initialize and process data. With unions, be careful: only one member can hold a value at a time. Writing to one member and reading from another leads to undefined behavior. That's why the enum is crucial – it tells you which part of the union is active.
Another tip: use setprecision and fixed from <iomanip> to format currency output nicely. And always cin.ignore() after reading numbers if you plan to use getline for strings, to avoid the newline character messing up input.
Real-World Connections
Structures and unions aren't just for homework – they're used in real-world software. For instance, in game development, a structure might represent a game object with properties like position, health, and type. An enum could define whether it's a player, enemy, or item. A union could store different data for different types, like a player's inventory or an enemy's AI state. Similarly, in AI applications, structures can hold model parameters, and unions can handle different data types in neural network layers.
As of May 2026, with the rise of AI-powered apps like ChatGPT and Midjourney, understanding how to organize data efficiently is more important than ever. These concepts are the building blocks of larger systems.
Conclusion
By mastering structures, enums, and unions, you're not just completing Assignment 11 – you're gaining skills that apply to countless programming scenarios. Start with simple structures like movieData, then scale up to arrays of structures like player, and finally combine enums and unions for flexible data types like Worker. Practice these patterns, and you'll be ready to tackle more complex projects with confidence. Remember to test your code with sample inputs and handle edge cases. Happy coding!