Composite Types

Scope: The fundamental types store single values. Composite types group several values into one object: arrays for many values of the same type, structs for a record with named fields, enums for a fixed set of choices, and tuples for small ad-hoc groups.

Arrays

An array stores several values of the same type side by side. You access an element by its index, and indices start at zero — the first element is numbers[0].

int temperatures[5] = {18, 21, 24, 19, 16};  // five ints
std::cout << temperatures[0] << "\n";        // 18 — first element
temperatures[2] = 26;                        // change the third element

C++ arrays do not know their own size; you must remember it. Modern code prefers std::array (fixed size, knows its length) or std::vector (grows), both introduced later in this lesson. For now, prefer iterating with the range-based for you learned in the control flow lesson:

for (int t : temperatures) {
    std::cout << t << " ";
}

Array bounds

Reading or writing outside the declared size is undefined behavior — the most dangerous mistake in systems programming. The compiler does not check bounds, so validate them yourself or use containers that do.

int values[3] = {1, 2, 3};
values[3] = 99;   // BAD: index 3 is out of bounds (valid indices 0..2)

Structs

A struct groups several values into one record with named fields. It turns several loose variables into one logical object that can be copied and passed around whole.

#include <string>

struct Student {
    std::string name;
    int grade;
    bool passed;
};

int main() {
    Student s{"Ada", 95, true};   // aggregate initialization, field order
    std::cout << s.name << " " << s.grade << "\n";
    return 0;
}

Member access

Use the dot . to read or write a field of a struct. The whole struct can be copied with =, which copies every field:

Student s{"Bob", 70, false};
Student copy = s;        // copy — both records are independent
copy.grade = 80;         // changes only the copy
s.passed = true;         // changes only the original

Structs are the foundation of object-oriented programming — the class lesson builds on them, adding functions that belong to the type.

Enums

An enum (enumeration) defines a type whose values come from a fixed list. The scoped form enum class (C++11) is preferred: its values do not leak into the surrounding scope and it does not silently convert to integers.

enum class Color { Red, Green, Blue };   // scoped enum

int main() {
    Color c = Color::Green;
    if (c == Color::Green) {
        std::cout << "Go!\n";
    }
    return 0;
}

Enums replace magic numbers: 0, 1, 2 become readable names, and the compiler rejects invalid values at the call site.

std::pair & std::tuple

For a quick grouping of two or three values without defining a struct, the standard library offers std::pair and std::tuple:

#include <utility>    // std::pair
#include <tuple>      // std::tuple

std::pair<std::string, int> p{"Ada", 95};   // (name, grade)
std::cout << p.first << " " << p.second;

auto t = std::make_tuple("Ada", 95, true);  // three values
std::cout << std::get<0>(t);                // "Ada"

Pairs and tuples are convenient but anonymous — readers cannot tell what first means. For more than two fields, a named struct communicates intent much better.

std::vector first look

std::vector is the workhorse container: a growable array that knows its size and checks nothing at the language level but manages memory safely.

#include <vector>

std::vector<int> scores;        // empty vector of ints
scores.push_back(85);          // append: grows automatically
scores.push_back(92);
std::cout << scores.size();     // 2
std::cout << scores[0];         // 85 — index access like an array

for (int s : scores) {         // range-for works out of the box
    std::cout << s << " ";
}

The standard library lesson explores std::vector and the rest of the STL containers in depth. For now, remember: when you need "an array that grows", reach for std::vector.

Practice

  1. Define a struct Point { double x; double y; } and a function that returns the distance between two points.
  2. Model a playing card as an enum class Suit { Hearts, Diamonds, Clubs, Spades } and a struct carrying suit and rank.
  3. Store ten readings in a std::vector<double> and print their average.
  4. Use std::pair to return both the minimum and the maximum of a vector, then rewrite it with a struct.