Массив — это структура данных, в которой элементы одного типа лежат в памяти подряд, а к каждому обращаются по номеру, индексу. Нумерация в большинстве языков начинается с нуля: у массива из пяти чисел индексы от 0 до 4. Благодаря такому устройству программа достаёт любой элемент одинаково быстро, хоть первый, хоть миллионный.
Если вы только начинаете программировать, представьте массив как одну переменную, у которой не одно значение, а целый ряд пронумерованных ячеек. Ниже разберём, как массив устроен в памяти, какие бывают массивы и чем массив отличается от списка, потому что эти два слова путают чаще всего.
Что такое массив простыми словами

Возьмём камеру хранения на вокзале: ряд одинаковых ячеек, у каждой свой номер. Чтобы забрать сумку, вам не нужно открывать все дверцы по очереди, достаточно знать номер. Массив работает так же.
Три слова, без которых о массивах не поговорить:
- элемент: одно значение внутри массива, например температура за один день;
- индекс: номер элемента. Первый элемент имеет индекс 0, второй 1 и так далее;
- длина: сколько элементов в массиве. Индекс последнего элемента на единицу меньше длины.
Вот так это выглядит в Python. Строго говоря, здесь список, но в Python он и есть основной массив языка, подробнее об этом ниже.
temps = [12, 15, 9, 21]
print(temps[0], temps[3]) # 12 21
print(temps[-1]) # 21: последний элемент
temps[2] = 10
print(temps) # [12, 15, 10, 21]
print(len(temps)) # 4
Отрицательный индекс -1 работает в Python, но не в C и не в Java. Как ещё брать элементы с конца и целыми кусками, мы разбирали в статье про срезы в Python.
Как массив устроен в памяти
Классическое определение есть в справке Microsoft по C++: массив состоит из объектов одного типа, которые занимают непрерывную область памяти. Главное здесь слово «непрерывную». Проверим на коротком примере на C:
#include <stdio.h>
int main(void) {
int prices[5] = {120, 340, 90, 560, 210};
printf("sizeof(int) = %zu\n", sizeof(int));
for (int i = 0; i < 5; i++) {
printf("prices[%d] = %d, адрес %p\n", i, prices[i], (void *)&prices[i]);
}
return 0;
}
Вывод на нашем компьютере:
sizeof(int) = 4
prices[0] = 120, адрес 0x16dc56870
prices[1] = 340, адрес 0x16dc56874
prices[2] = 90, адрес 0x16dc56878
prices[3] = 560, адрес 0x16dc5687c
prices[4] = 210, адрес 0x16dc56880
Адреса у вас будут другими, но шаг останется тем же: каждый следующий элемент лежит ровно на 4 байта дальше, потому что одно число int занимает 4 байта. Поэтому компьютеру не нужно искать элемент. Он считает адрес по формуле:
адрес элемента = адрес начала массива + индекс × размер одного элемента
Отсюда и ответ на вопрос, почему индекс начинается с нуля. Индекс показывает, на сколько элементов нужно отступить от начала. Первый элемент лежит в самом начале, отступ ноль. Подробнее про объявление массивов, указатели и двумерные таблицы в C есть в отдельной статье о массивах в C.
Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединитьсяКакие бывают массивы
Массивы различают по нескольким признакам сразу, поэтому один и тот же массив может быть, например, двумерным и динамическим.
| Вид | Что это значит | Пример |
|---|---|---|
| Одномерный | Простой ряд элементов, один индекс | Оценки ученика за четверть |
| Многомерный | Массив массивов, два индекса и больше | Таблица, шахматная доска, пиксели картинки |
| Статический | Длина задаётся при создании и дальше не меняется | int a[10] в C, массивы в Java |
| Динамический | Растёт и уменьшается во время работы программы | list в Python, Array в JavaScript, ArrayList в Java |
| Ассоциативный | Доступ по ключу вместо номера | Словарь в Python, объект в JavaScript |
Ассоциативный массив массивом в строгом смысле не является: элементы в нём не пронумерованы подряд. Название историческое, а в Python и JavaScript для этого есть словари и объекты.
Статические и динамические
В Java длина массива фиксируется навсегда. В учебнике Oracle сказано прямо: массив хранит фиксированное число значений одного типа, длина задаётся при создании, и после создания она не меняется.
Динамический массив устроен хитрее. В документации Python объясняется, что внутри list в CPython лежит массив переменной длины, связным списком он не является: когда место кончается, массив пересоздаётся, причём с запасом, чтобы следующие несколько добавлений обошлись без пересоздания. Это видно, если следить за размером пустого списка:
import sys
a = []
prev = sys.getsizeof(a)
print(len(a), prev)
for i in range(20):
a.append(i)
s = sys.getsizeof(a)
if s != prev:
print(len(a), s)
prev = s
0 56
1 88
5 120
9 184
17 248
Размер растёт скачками: на первом, пятом, девятом и семнадцатом элементе. Между скачками Python кладёт новые элементы в уже выделенный запас. Цифры получены в Python 3.14 на 64-битном Mac, в других версиях шаги могут отличаться.
Однородные и разнородные
В C и Java все элементы массива одного типа. В JavaScript это не так: по справке MDN, ни размер массива, ни типы его элементов не фиксированы.
const mixed = [1, "два", true];
mixed[10] = 5;
console.log(mixed.length); // 11
console.log(mixed[5]); // undefined
Мы записали значение в ячейку 10, и длина сразу стала 11, а ячейки с 3 по 9 остались пустыми. Как правильно добавлять элементы и объекты в JS, разобрано в инструкции про push и spread.
Чем массив отличается от списка

Путаница возникает потому, что словом «список» называют две разные вещи.
- Связный список из учебников по алгоритмам. Элементы разбросаны по памяти, и каждый хранит ссылку на следующий (в двусвязном ещё и на предыдущий). Так устроен
LinkedListв Java. - Тип
listв Python. Несмотря на название, внутри это динамический массив, как мы видели выше.
Когда спрашивают, чем массив отличается от списка, обычно имеют в виду первое: массив против связного списка. Вот главные различия:
| Операция | Массив | Связный список |
|---|---|---|
| Взять элемент по индексу | Сразу, по формуле адреса | Нужно пройти по цепочке от начала или конца |
| Вставить в начало или середину | Медленно: все элементы правее сдвигаются | Быстро, если уже стоите на нужном месте |
| Добавить в конец | Быстро, пока есть запас | Быстро |
| Память | Только сами элементы | Элементы плюс ссылки на соседей |
Так эти два класса описывает документация Java. Про LinkedList: операции с индексом проходят список с начала или с конца, смотря что ближе. Про ArrayList: получение элемента по индексу выполняется за постоянное время, добавление в конец за амортизированное постоянное, а остальные операции, грубо говоря, за линейное.
Проверим скорость на Python
Мы взяли список из миллиона чисел и тысячу раз повторили каждую операцию. Python 3.14.7, три прогона на Mac, разброс между прогонами в скобках.
| 1000 повторов операции | Время |
|---|---|
data[999_999]: взять элемент по индексу |
0,015 мс (0,015–0,016) |
append и pop: добавить и убрать в конце |
0,1 мс (0,10–0,12) |
insert(0) и pop(0): добавить и убрать в начале |
0,38 с (0,38–0,40) |
999_999 in data: найти значение перебором |
5,4 с (5,33–5,39) |
Доступ по индексу к последнему из миллиона элементов почти ничего не стоит. Вставка в начало в три с лишним тысячи раз медленнее вставки в конец, потому что Python каждый раз сдвигает миллион ссылок. Тот же эффект для pop(0) мы разбирали в статье про удаление из списка. А поиск значения перебором оказался самым дорогим: массив знает, где лежит элемент с номером, но не знает, под каким номером лежит нужное значение.
Вывод: массив хорош, когда вы много читаете по индексу и добавляете в конец. Частые вставки в начало лучше делать другой структурой, например collections.deque в Python, а частый поиск по значению отдать словарю или множеству.
Массив и список в Python
В Python есть и «настоящий» однородный массив, модуль array. По документации он компактно хранит числа и символы одного типа, а тип задаётся при создании. Сравним с обычным списком:
import sys
from array import array
nums = list(range(1_000_000))
packed = array("i", range(1_000_000))
print("list:", sys.getsizeof(nums), "байт")
print("array:", sys.getsizeof(packed), "байт")
try:
packed.append(1.5)
except TypeError as e:
print("TypeError:", e)
list: 8000056 байт
array: 4091948 байт
TypeError: 'float' object cannot be interpreted as an integer
Список занимает вдвое больше, и это ещё без самих чисел: list хранит только ссылки на объекты, а числа лежат в памяти отдельно. Массив array хранит сами значения по 4 байта и не пускает в себя дробь. На практике в Python почти всегда берут обычный список, а для больших числовых расчётов NumPy, пример есть в инструкции как суммировать список. Методы списка собраны в статье о списках в Python, а чем от них отличается неизменяемый кортеж, мы писали отдельно.
Основные операции с массивом
Что умеют делать с массивом почти во всех языках, и насколько это дорого:
- чтение и запись по индексу: самая дешёвая операция, время не зависит от длины;
- перебор: проход по всем элементам циклом. В Python индекс и значение сразу даёт функция enumerate();
- добавление: в конец дёшево, в начало и середину дорого. Варианты для Python в инструкции как добавить элемент в список;
- удаление: та же история, с конца быстро, из начала медленно;
- поиск по значению: перебор всех элементов, если массив не отсортирован. По отсортированному массиву ищут бинарным поиском, а сортировать в Python удобно методом sort().
Многомерный массив читают двумя индексами подряд: сначала строка, потом столбец.
grid = [
[1, 2, 3],
[4, 5, 6],
]
print(grid[1][2]) # 6: вторая строка, третий столбец
Частые ошибки при работе с массивами

Ошибка на единицу
Самая частая ошибка новичков: цикл идёт до длины включительно. Элемента с индексом, равным длине, не существует.
temps = [12, 15, 9, 21]
for i in range(len(temps) + 1):
print(temps[i])
IndexError: list index out of range
Решение: range(len(temps)), а лучше перебирать сами элементы, for t in temps, без индексов вовсе.
Выход за границы массива
Python и Java на чужой индекс выбрасывают ошибку, JavaScript молча возвращает undefined. А C не делает ничего:
int a[3] = {1, 2, 3};
int i = 3;
printf("%d\n", a[i]);
Clang 17 с флагом -Wall собрал этот код без единого предупреждения, а программа напечатала 1, которой в массиве нет. Это значение из памяти за концом массива, на другой машине оно будет другим. Так рождаются самые неприятные ошибки в C: программа не падает, а тихо считает неправильно.
Присваивание вместо копии
В Python, JavaScript и Java присваивание даёт массиву второе имя, копии при этом не появляется.
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4]
c = a.copy()
c.append(5)
print(a, c) # [1, 2, 3, 4] [1, 2, 3, 4, 5]
Решение: нужна независимая копия, вызывайте copy() или срез a[:]. Для вложенных списков понадобится copy.deepcopy().
Удаление элементов прямо в цикле
Если удалять элементы из массива, по которому идёт цикл, элементы сдвигаются, и цикл перескакивает через следующий. Безопаснее собрать новый массив из нужных элементов. Почему так происходит, показано на примере в статье про удаление из списка, ссылка на неё есть выше.
Где освоить программирование системно
С массива начинает любой программист, а за ним идут словари, множества, стеки, деревья и алгоритмы поиска и сортировки. Разобраться в них по одной статье трудно, проще на курсе с задачами и проверкой кода. Ниже курсы по Python, языку, на котором структуры данных удобнее всего изучать с нуля.
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Профессия «Python-разработчик» Перейти на сайт курса | 157 335 ₽ | 5987 ₽/мес. | 10 месяцев | Обзор курса | |
| Fullstack-разработчик на Python Перейти на сайт курса | 137 000 ₽ | 7125 ₽/мес. | 21 месяц | Обзор курса | |
| ДО Профессия Python-разработчик Перейти на сайт курса | 149 001 ₽ | 3167 ₽/мес. | 10 месяцев | Обзор курса | |
| Автоматизированное тестирование на Python Перейти на сайт курса | 122 226 ₽ | 4108 ₽/мес. | 9 месяцев | Обзор курса | |
| Профессия Python-разработчик Перейти на сайт курса | 140 040 ₽ | 3890 ₽/мес. | 10 месяцев | Обзор курса |
Больше программ — в полном каталоге курсов по Python




