C++ Structs and Enums

Group related values into structs, store them in vectors, pass them to functions and name fixed options with enum class.

Lesson 11 of 44Intermediate18 min read

A game character has a name, a level and an amount of health. A product has a name, a price and a stock count. Keeping these in separate variables, or in parallel vectors such as names, prices and stock, quickly gets messy: it's easy to sort one vector and forget the others, and functions need long parameter lists.

A struct lets you create your own type that groups related values, called members, under one name. Once you've defined struct Product, you can create Product variables, store them in a vector<Product> and pass a whole product to a function in one argument. Structs are the first step towards the classes you'll meet in the classes lesson.

This lesson also introduces enum class, a way to give names to a fixed set of options, such as the sizes Small, Medium and Large, so your code says what it means instead of using mysterious numbers.

Defining and using a struct

C++
struct Product {
    string name;
    double price;
    int stock;
};   // note the semicolon

Product pen{"Pen", 1.20, 300};
cout << pen.name << " costs " << pen.price;
pen.stock -= 1;
  • The definition lists each member with its type, and ends with a semicolon after the closing brace.
  • Create a variable with braces, giving values in the same order as the members.
  • Use the dot to read and change members: pen.price.
  • You can give members default values in the definition, such as int stock = 0;, which are used when a value isn't supplied.

Vectors of structs

Structs and vectors work naturally together:

C++
vector<Product> shop = {
    {"Pen", 1.20, 300},
    {"Notebook", 3.50, 120},
};
shop.push_back({"Lamp", 24.50, 22});

for (const Product& p : shop) {
    cout << p.name << endl;
}

Each element is a complete product, so sorting or filtering keeps all of its information together. Loop with const Product& to read each item without copying it, and with Product& when the loop needs to change the items.

Structs and functions

Pass a struct by const reference to read it, and by plain reference to change it, exactly as you learned for vectors in the functions lesson:

C++
double stockValue(const Product& p) {
    return p.price * p.stock;
}

void restock(Product& p, int amount) {
    p.stock += amount;
}

Functions can also return a struct, which is a tidy way to return several values at once, such as a minimum, maximum and average bundled into one Stats struct. A struct can even contain member functions, such as double value() const { return price * stock; }, which leads directly into classes.

enum class

An enumeration defines a type with a fixed list of named values:

C++
enum class Size { Small, Medium, Large };

Size s = Size::Medium;
if (s == Size::Large) { ... }
  • enum class (a scoped enum) requires the type name: Size::Medium. This avoids clashes between enums that use the same words.
  • Behind the scenes each value is a whole number (0, 1, 2), but enum class won't silently convert to int. Use static_cast<int>(s) when you really need the number.
  • Enums work well with switch, so you can handle each option in turn.

Older code uses plain enum without class, which converts to int automatically and mixes its names into the surrounding scope. Prefer enum class in new code.

C++ Structs Syntax

Struct and enum syntax

struct Name {
    type member1;
    type member2 = defaultValue;
};
Name n{value1, value2};
n.member1 = value;

enum class Option { A, B, C };
Option o = Option::B;

C++ Structs Summary

  • struct Name { type member; ... }; defines your own type; don't forget the semicolon.
  • Create values with braces and reach members with a dot.
  • vector<Struct> keeps records together; loop with const Struct&.
  • Pass structs by const& to read and & to change; functions can return structs.
  • enum class Size { Small, Medium }; names fixed options as Size::Small.

C++ Structs Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A product list

C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;

struct Product {
    string name;
    double price;
    int stock;
};

double stockValue(const Product& p) {
    return p.price * p.stock;
}

int main() {
    vector<Product> shop = {
        {"Pen", 1.20, 300},
        {"Notebook", 3.50, 120},
        {"Lamp", 24.50, 22},
    };

    double total = 0;
    for (const Product& p : shop) {
        cout << p.name << ": " << stockValue(p) << endl;
        total += stockValue(p);
    }
    cout << "Total stock value: " << total << endl;
    return 0;
}
Output
Pen: 360
Notebook: 420
Lamp: 539
Total stock value: 1319
Line-by-line explanation
  1. Lines 6 to 10One struct groups the three pieces of information about a product.
  2. Lines 12 to 14The function takes a whole product by const reference.
  3. Lines 17 to 21A vector of products, each written with braces.
  4. Line 25cout prints whole-number doubles without a decimal point.
Example 2

Returning several values in a struct

C++
#include <iostream>
#include <vector>
using namespace std;

struct Stats {
    int min;
    int max;
    double average;
};

Stats summarise(const vector<int>& v) {
    Stats s{v[0], v[0], 0};
    int total = 0;
    for (int x : v) {
        if (x < s.min) s.min = x;
        if (x > s.max) s.max = x;
        total += x;
    }
    s.average = static_cast<double>(total) / v.size();
    return s;
}

int main() {
    Stats s = summarise({72, 95, 61, 88});
    cout << "Min " << s.min << ", max " << s.max << ", average " << s.average << endl;
    return 0;
}
Output
Min 61, max 95, average 79
Line-by-line explanation
  1. Lines 5 to 9A small struct to bundle three results.
  2. Lines 11 to 21The function fills in the struct and returns it.
  3. Line 24One call gives all three values. (72 + 95 + 61 + 88) / 4 is exactly 79.
Example 3

Using enum class with switch

C++
#include <iostream>
using namespace std;

enum class Size { Small, Medium, Large };

double price(Size s) {
    switch (s) {
        case Size::Small:  return 2.50;
        case Size::Medium: return 3.00;
        case Size::Large:  return 3.50;
    }
    return 0;
}

int main() {
    Size order = Size::Large;
    cout << "Large coffee: " << price(order) << endl;
    cout << "Medium is option " << static_cast<int>(Size::Medium) << endl;
    return 0;
}
Output
Large coffee: 3.5
Medium is option 1
Line-by-line explanation
  1. Line 4A scoped enum with three named values.
  2. Lines 7 to 11switch handles each size; return ends the function, so no break is needed.
  3. Line 18static_cast shows the underlying number; Small is 0, so Medium is 1.

Common C++ Structs Mistakes

Missing semicolon after a struct

Don't
struct Point {
    int x;
    int y;
}
Do
struct Point {
    int x;
    int y;
};

The compiler error often appears on the next line, which makes this one confusing.

Changing a copy in a loop

Don't
for (Product p : shop) {
    p.stock += 10;      // changes a copy
}
Do
for (Product& p : shop) {
    p.stock += 10;      // changes the real product
}

Using enum names without the type

Don't
Size s = Medium;          // error with enum class
Do
Size s = Size::Medium;

C++ Structs in Real Projects

Structs in real C++ code

Games use structs for positions, colours and particles, often thousands of them in a vector. Programs that read files or network messages fill a struct for each record, and many libraries return structs such as std::pair or their own result types. Enums describe states like GameState::Playing and GameState::Paused.

C++ Structs FAQ

How do I compare two structs with == in C++?

C++ doesn't compare structs automatically, so a == b is a compile error at first. In C++20, add one line inside the struct, bool operator==(const Point&) const = default;, and the compiler compares every member in order; != comes free. With older compilers, write operator== yourself, as the operator overloading lesson shows.

How do I print a struct with cout?

cout doesn't know how to print your struct, so cout << pen won't compile. The simplest fix is a function such as void print(const Product& p) that prints each member. Once you've met operator overloading, you can write operator<< so that cout << pen works directly.

What are designated initialisers in C++20?

They let you name the members as you set them: Point p{.x = 1, .y = 2};. That's clearer than relying on position, and members you leave out get their default values, so Opt o{.name = "x"}; keeps qty at its default. Unlike C, C++ requires the names in the same order as they're declared in the struct.

How do I sort a vector of structs by one member?

Pass sort a comparison that looks at that member: sort(shop.begin(), shop.end(), [](const Product& a, const Product& b) { return a.price < b.price; });. Swap < for > to sort from highest to lowest. The algorithms and lambdas lesson explains the [](...) { ... } syntax.

Why is sizeof my struct bigger than its members added together?

The compiler adds invisible padding so that each member sits at a memory address that suits its type, which the processor can read faster. A struct holding a char and an int is usually 8 bytes, not 5. Ordering members from largest to smallest often reduces the padding, but you rarely need to worry about it.

C++ Structs Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the struct definition.

 Point {
    int x;
    int y;
}
Predict the outputeasy

What does this print?

struct Box { int w; int h; };
Box b{3, 4};
b.w = 5;
cout << b.w * b.h;
Multiple choicemedium

How should a function that only reads a large struct take it?

Predict the outputmedium

What does this print?

enum class Level { Low, Mid, High };
cout << static_cast<int>(Level::High);
Multiple choicehard

What's the only difference between struct and class in C++?

C++ Structs Quiz

5 questions to check what you learned.

  1. How do you access a struct member?

    • With ->
    • With ::
    • With a dot, like p.name
    • With []
  2. Why use enum class instead of plain enum?

    • Its names are scoped and it won't silently convert to int
    • It's faster
    • It can hold strings
    • It allows more values
  3. What is a good use for a struct?

    • Repeating code
    • Printing output
    • Reading files
    • Grouping related values, such as the name, price and stock of a product
  4. Why loop with Product& instead of Product?

    • It's required for structs
    • To change the items in the vector instead of copies
    • To sort the vector
    • To make the loop shorter
  5. How can a function return three values at once?

    • It can't
    • Use three return statements
    • Return an enum
    • Return a struct containing the three values