Массив (array) — последовательность элементов одного типа, расположенных непрерывно в памяти, с доступом по индексу через одно имя. Размер обычного массива — константа, известная на этапе компиляции.
Зачем нужно
Сто чисел не хранят в ста переменных: их долго придумывать, а главное — переменные нельзя перебирать в цикле. Элементы массива перебираются по номеру:
int array[100];
for (int i = 0; i < 100; ++i) {
std::cin >> array[i];
}Как работает
Объявление и доступ
int array[10]; // 10 int подряд
array[0]; // первый
array[9]; // последний: нумерация с нуляЭлементы идут подряд без разрывов: &a[i] - &a[j] == i - j.
Размер в скобках — положительная константа времени компиляции. int array[n]
с n из std::cin стандарт C++ запрещает; для такого случая есть
Динамический массив.
Размер
sizeof(array); // 40: суммарный размер в байтах
sizeof(array) / sizeof(int); // 10: число элементовСм. sizeof.
Инициализация
int a[10]; // не инициализирован
int z[10]{}; // нули
int b[5]{1, 2, 3}; // 1 2 3 0 0: недостающее — нули
int c[]{1, 2, 3}; // размер выводится: int[3]Ошибка в лонгриде L04
В лонгриде нули задаются как
int a[10]();, а выведение размера — какint b[1]{1, 2, 3}. Оба варианта не компилируются (GCC 16.2: «array of functions» и «too many initializers»). Здесь приведены рабочие формы, см. L04 - Массивы.
Массив и указатель
В большинстве ситуаций массив неявно превращается в указатель на нулевой элемент:
int array[10];
int* p = array;
std::cout << array + 5; // адрес array[5]
p[2]; // то же, что *(p + 2)
2[p]; // да, тоже *(2 + p)Индексирование — сдвиг указателя и разыменование, см. Арифметика указателей.
Но массив — не указатель:
sizeof(array); // 40
sizeof(p); // 8
&array; // int(*)[10]: указатель на массив из 10 int
&p; // int**Правила
- Нельзя создать массив ссылок или функций; массив указателей и массив
указателей на функции — можно:
int* c[30],int (*d[40])(int). - Нельзя определить массив неизвестного размера (
int a[];—storage size of 'a' isn't known), но можно объявить:extern int c[];. См. Объявление и определение. a == bсравнивает адреса нулевых элементов, не значения: для разных массивов всегдаfalse.- Массивы нельзя присваивать и копировать:
a = b;иint b[5] = a;— ошибки. Исключение — строка при инициализации массиваchar. - Если массив — поле структуры, присваивание структур копирует и массив.
Многомерные массивы
int b[5][20]; // двумерный
b[3][11];
int a[2][3]{1, 2, 3, 4}; // по строкам: 1 2 3 / 4 0 0
int c[3][2]{{1, 2}, {3, 4}, {5, 6}};
int d[][2]{1, 2, 3, 4}; // выводится только первая размерностьМногомерный массив — массив массивов. Его первый элемент — массив меньшей размерности, к указателю на который он и приводится:
int a[1][2][3];
a[0]; // int[2][3]
int b[2][3];
b[1][1] <=> *(b[1] + 1) <=> *(*(b + 1) + 1);b + 1 сдвигается на целую строку — sizeof(int[3]) байт.
Тонкости
Не из лекции
- Сравнение массивов через
==в C++20 устарело, в C++26 — ошибка компиляции (GCC 16.2).- Обращение за пределы массива, включая
array[10]при десяти элементах, — Неопределённое поведение. Компилятор границы не проверяет.- Когда массив передают в функцию, туда уходит указатель — и
sizeof(array) / sizeof(int)внутри функции даёт уже не число элементов.
Частые ошибки
- Задавать размер переменной:
int a[n]. - Обращаться к
a[N]в массиве изNэлементов. - Считать число элементов через
sizeofу указателя. - Сравнивать массивы через
==, ожидая сравнения содержимого. - Присваивать массив массиву.
Углубление — L05
Массив в функцию передаётся указателем на нулевой элемент — и функция не знает, сколько элементов можно смотреть. Два способа это сообщить:
void PrintArray(const int* data, int size); // начало + количество
void PrintRange(const int* begin, const int* end); // начало + конец
int values[] = {3, 1, 4};
PrintArray(values, 3);
PrintRange(values, values + 3);Во втором способе end указывает сразу за последний элемент: получается
полуинтервал [begin, end). Указатель values + 3 допустим как граница, но
разыменовывать его нельзя. При begin == end диапазон пустой. Так же устроены
стандартные алгоритмы: std::sort(values, values + 3) из <algorithm>.
const int* в параметрах — функции только читают элементы. Подробнее о
способах передачи — Передача параметров.