Перейти к содержимому
Теория · Строки и массивы · урок 3 из 6

C-массивы и std::array

Пять оценок можно хранить в пяти переменных, но сложить их в цикле не получится: у каждой своё имя. Массив (array) хранит несколько значений одного типа под одним именем, а к каждому значению обращаются по номеру:

C++
#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] объявляет массив из пяти int, которые лежат в памяти подряд. Элементы нумеруются с нуля, поэтому последний — scores[4]. Цикл по диапазону проходит по всем пяти элементам.

Размер — часть типа

Число в квадратных скобках входит в тип: scores имеет тип int[5], а int[3] — уже другой тип. Поэтому размер должен быть известен при компиляции — например, литерал или constexpr-переменная. sizeof(scores) даёт размер всего массива в байтах, а деление на размер одного элемента — число элементов:

C++
int scores[5] = {90, 75, 60, 85, 70};
std::cout << sizeof(scores) / sizeof(scores[0]) << '\n';  // 5

Свои границы C-массив не проверяет. Обращение по номеру за его пределами, например scores[5], — неопределённое поведение.

Массив в параметре

Скопировать C-массив в параметр функции нельзя. Вместо этого функция получает указатель (pointer) на первый элемент — это называют преобразованием массива в указатель (array-to-pointer decay). Параметр int a[5] означает то же, что int* a, а число в скобках компилятор игнорирует.

Поэтому sizeof(a) внутри функции даёт размер указателя, а не массива, и длину по нему не узнать. Её передают в функцию отдельным параметром, как n в задачах на указатели.

std::array

Массив типа std::array<int, 5> из заголовка <array> хранит те же пять int подряд, но копируется и передаётся в функцию целиком, как int. В указатель он не превращается, а size() возвращает число элементов. Передают его по const-ссылке, как и другие объекты, которые дорого копировать.

C++
#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
}

В угловых скобках стоят тип элементов и их число. Размер и здесь входит в тип, поэтому total принимает только массив ровно из пяти int.

Частая ошибка

Число элементов считают внутри функции:

C++
int count(int a[5]) {
    return sizeof(a) / sizeof(a[0]);  // ✗
}
TEXT
warning: sizeof on array function parameter will return size of 'int *' instead of 'int[5]' [-Wsizeof-array-argument]

Это предупреждение, а не ошибка: функция компилируется, но a в ней — указатель. sizeof(a) даёт размер указателя, и результат не зависит от длины массива. Передайте длину вторым параметром или возьмите std::array.