C arrays and std::array
Picture a row of identical lockers in a changing room. The row has one shared name, each locker has its own number, and you find a thing by that number. The lockers stand right next to each other, and their count does not change: there is no room to squeeze a new locker into the row.
Five scores can be stored in five variables, but they cannot be added up in a loop: each has its own name. An array stores several values of one type under one name, like a row of lockers, and each value is reached by its position:
#include <iostream>
int main() {
int scores[5] = {90, 75, 60, 85, 70};
int sum = 0;
for (int s : scores) {
sum = sum + s;
}
std::cout << scores[0] << ' ' << scores[4] << '\n'; // 90 70
std::cout << sum << '\n'; // 380
}int scores[5] declares an array of five int values that sit next to each other in memory. Elements are numbered from zero, so the last one is scores[4]. The range-for loop visits all five elements.
This array is built into the language itself: C++ inherited it from the C language, so it is called a C array.
Size belongs to the type
The number in square brackets belongs to the type: scores has the type int[5], and int[3] is a different type. That is why the size must be known at compile time: it is a literal or a constexpr variable. sizeof(scores) gives the size of the whole array in bytes, and if you divide it by the size of one element, you get the element count:
int scores[5] = {90, 75, 60, 85, 70};
std::cout << sizeof(scores) / sizeof(scores[0]) << '\n'; // 5A C array does not check its bounds. A position outside the array, such as scores[5], gives undefined behavior: there is no locker with that number, and the standard does not define what the program gets.
An array as a parameter
A C array cannot be copied into a function parameter. Instead, the function receives a pointer to the first element. This is called array-to-pointer decay. The parameter int a[5] means the same as int* a, and the compiler ignores the number in the brackets.
Inside the function, sizeof(a) therefore gives the size of a pointer, not of the array, and says nothing about the length. The length is passed to the function as a separate parameter, like n in the pointer exercises.
std::array
std::array<int, 5> from <array> stores the same five int values in a row, yet is copied and passed to a function whole, the same way an int variable is. It does not turn into a pointer, and size() returns the number of elements. It is passed by const reference, like other objects that are expensive to copy.
#include <array>
#include <iostream>
int total(const std::array<int, 5>& values) {
int sum = 0;
for (int v : values) {
sum = sum + v;
}
return sum;
}
int main() {
std::array<int, 5> scores = {90, 75, 60, 85, 70};
std::cout << scores.size() << ' ' << total(scores) << '\n'; // 5 380
}The angle brackets hold the element type and the number of elements. Here, too, the size is part of the type, so total accepts only an array of exactly five int values.
Common mistake
The number of elements is computed inside a function:
int count(int a[5]) {
return sizeof(a) / sizeof(a[0]); // ✗
}warning: sizeof on array function parameter will return size of 'int *' instead of 'int[5]' [-Wsizeof-array-argument]This is a warning, not an error: the function compiles, but a inside it is a pointer. sizeof(a) gives the size of a pointer, and the result does not depend on the array's length. Pass the length as a second parameter or use std::array.
Key points
- A C array stores elements of one type in a row, and its size is part of its type.
- A position outside the array gives undefined behavior.
- As a function parameter, a C array turns into a pointer, so the length is passed separately.
- A
std::arrayis copied whole, andsize()returns the number of its elements.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.