Composite Types
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
- Define a
struct Point { double x; double y; }and a function that returns the distance between two points. - Model a playing card as an
enum class Suit { Hearts, Diamonds, Clubs, Spades }and a struct carrying suit and rank. - Store ten readings in a
std::vector<double>and print their average. - Use
std::pairto return both the minimum and the maximum of a vector, then rewrite it with a struct.