Содержание статьи
Массив — базовая структура данных, простая и полезная. По сути это набор элементов одного типа, упорядоченный по индексам. Представьте полку с пронумерованными секциями: взять, положить, заменить элемент можно по номеру секции, не перебирая всю полку.
Ключевые свойства
- Фиксированная или динамическая длина — в некоторых языках размер задают при создании, в других его можно менять.
- Быстрый доступ по индексу — операция чтения или записи по индексу обычно выполняется за константное время O(1).
- Последовательное размещение в памяти — в языках низкого уровня это важно для производительности и кэширования.
Статические и динамические массивы
Статический массив выделяется один раз и не меняет размера. Он экономичен по памяти и прогнозируем в поведении. Динамический массив может увеличиваться или уменьшаться: реализация обычно выделяет буфер большего размера и копирует данные при переполнении. Примеры динамических контейнеров — Python list, Java ArrayList, C++ vector.
Как устроен доступ
Индекс i переводится в адрес: адрес начала + i * sizeof(элемент). Поэтому индексация начинается с нуля в большинстве языков: адрес нулевого элемента — просто адрес начала. Ошибки с индексами приводят к выходу за границы и неожиданному поведению.
Примеры кода
С — статический массив и выделение динамики:
int a[5]; // массив из 5 int
int* b = malloc(5 * sizeof(int)); // динамический массив
b[2] = 10;
free(b);
Python — список как динамический массив:
arr = [1, 2, 3]
arr.append(4)
x = arr[1] # 2
JavaScript — массивы и методы:
const arr = [1, 2, 3];
arr.push(4);
arr.shift(); // удаляет первый элемент
Операции и сложность
- Чтение/запись по индексу: O(1).
- Добавление в конец: амортизированное O(1) для динамических массивов.
- Вставка или удаление в середине: O(n) из‑за сдвига элементов.
- Поиск без предварительной сортировки: O(n).
Многомерные массивы
Двумерный массив можно представить как массив массивов или как плоский массив с вычислением индекса: index = row * cols + col. Первый вариант удобнее и гибче, второй эффективнее по памяти и быстрее при последовательном обходе.
Копирование и мутабельность
Важно понимать: копирование массива может быть поверхностным или глубоким. Поверхностная копия дублирует ссылки на элементы, глубокая — копирует сами элементы. Для изменяемых объектов это критично.
Распространённые ошибки
- Off-by-one: неправильное использование границ при итерации.
- Чтение за границами: приводит к undefined behavior в C/C++ и исключениям в других языках.
- Неправильная оценка затрат при частых вставках в начало — лучше использовать deque или связный список.
- Ожидание, что массив всегда экономит память: динамические векторы могут держать резервный буфер.
Советы по использованию
- Если нужен быстрый случайный доступ — массив почти всегда лучший выбор.
- Для частых вставок или удалений в середине рассмотрите другие структуры: списки, деревья, дек.
- При работе с большими данными думайте о локальности доступа: последовательный проход быстрее за счёт кэша.
- Чтобы избежать лишних копий, используйте ссылки, итераторы или move-семантику (в языках, где это есть).
Короткий итог
Массив — прост и предсказуем. Он хорош там, где важен прямой доступ и компактность. Зная его особенности — ограничение по размеру, стоимость вставок и поведение при копировании — вы выберете правильный инструмент и избежите типичных ошибок.






