Lesson 2 of 9
std::array is a C array with the sharp edges removed. Same memory layout, same speed, but it
knows its own size and doesn't decay.
#include <array>
#include <iostream>
int main() {
std::array<int, 5> scores = {90, 85, 77, 100, 68};
std::cout << scores[0] << " " << scores[4] << "\n";
std::cout << scores.size() << "\n";
std::cout << scores.front() << " " << scores.back() << "\n";
return 0;
}
90 68
5
90 68
The declaration reads std::array<element type, count>. That's your first look at template
arguments — the angle brackets say "an array of 5 ints" as one complete type. Module 12
explains how they work; for now, just read them.
It doesn't decay
The whole point:
#include <array>
#include <iostream>
void takes_array(const std::array<int, 5>& values) {
std::cout << "inside: " << values.size() << "\n";
}
int main() {
std::array<int, 5> numbers = {1, 2, 3, 4, 5};
std::cout << "outside: " << numbers.size() << "\n";
takes_array(numbers);
return 0;
}
outside: 5
inside: 5
Compare lesson 6.1, where the same thing printed 20 and then 8. The size travels with the object,
so no separate count parameter is needed and there's nothing to get out of sync.
Note the const& — lesson 5.4's rule applies, since copying an array copies every element.
Bounds checking, when you ask for it
operator[] is unchecked, exactly like a C array. But .at() checks:
#include <array>
#include <iostream>
#include <stdexcept>
int main() {
std::array<int, 3> values = {10, 20, 30};
std::cout << values[1] << "\n";
std::cout << values.at(1) << "\n";
try {
std::cout << values.at(10) << "\n";
} catch (const std::out_of_range& e) {
std::cout << "caught: out of range\n";
}
return 0;
}
20
20
caught: out of range
values[10] would be silent undefined behaviour. values.at(10) throws std::out_of_range,
which you can catch (Module 15 covers exceptions properly).
The trade is a comparison per access. Use .at() when the index comes from outside your control
— user input, a file, a network message — and [] in tight loops where you've already checked
the bounds.
The useful members
#include <array>
#include <iostream>
int main() {
std::array<int, 4> values = {5, 3, 9, 1};
std::cout << values.size() << " " << values.empty() << "\n";
std::cout << values.front() << " " << values.back() << "\n";
values.fill(7);
std::cout << values[0] << values[1] << values[2] << values[3] << "\n";
return 0;
}
4 0
5 1
7777
There's also .data(), which hands you a raw pointer — exactly what you need when calling a C
API that expects one.
Copying and comparing actually work
C arrays can't be assigned or compared with ==. std::array can:
#include <array>
#include <iostream>
int main() {
std::array<int, 3> a = {1, 2, 3};
std::array<int, 3> b = a; // real copy
std::array<int, 3> c = {1, 2, 3};
b[0] = 99;
std::cout << std::boolalpha;
std::cout << (a == c) << " " << (a == b) << "\n";
std::cout << a[0] << " " << b[0] << "\n";
return 0;
}
true false
1 99
a == c compares element by element. With C arrays, == would compare addresses — always
false for two distinct arrays, and a bug that compiles silently.
The size is part of the type
// WILL NOT COMPILE
#include <array>
void takes_five(const std::array<int, 5>& values) {
(void)values;
}
int main() {
std::array<int, 3> three = {1, 2, 3};
takes_five(three); // array<int,3> is not array<int,5>
return 0;
}
std::array<int, 3> and std::array<int, 5> are entirely different types. That's good for
safety and inconvenient when you want a function accepting any size — which needs a template
(Module 12) or std::span (lesson 13.11).
std::array versus std::vector
| | std::array | std::vector |
| --- | --- | --- |
| Size | fixed at compile time | grows at run time |
| Memory | on the stack | on the heap |
| Cost | zero overhead | one allocation |
| Use when | the count is known and small | the count varies or is large |
Prefer std::array when the size is genuinely fixed — a 3D coordinate, a chess board, a fixed
lookup table. It's the cheapest correct option. When you don't know the count in advance, you
need lesson 6.3.
Try it
Store the number of days in each month in a std::array<int, 12>, then write a function taking
it by const& that returns the total. Use .at() to look up a month by a number the user might
have got wrong.
Checkpoint
std::array<T, N>is a fixed-size array that carries its size with it.- It does not decay when passed to a function — pass it by
const&. []is unchecked;.at()throwsstd::out_of_range. Use.at()for untrusted indices..size(),.front(),.back(),.fill(),.data()are the members you'll reach for.- Unlike C arrays, it can be copied with
=and compared with==element-wise. - The size is part of the type, so
array<int,3>andarray<int,5>don't interchange.
Questions about this lesson
Log in to ask a question.