Код
#статьи

Что такое массив и как он устроен

Заглядываем под капот одной из главных структур данных в программировании.

Иллюстрация: Оля Ежак для Skillbox Media

В языках программирования информация представлена разными типами данных: целые числа, числа с плавающей точкой, символы, строки, булевы значения и так далее. Благодаря этому компьютер понимает, как хранить информацию и что с ней делать.

Но есть и более сложные сущности, которые называются структурами данных. Они содержат данные, которые, как правило, связаны определённым образом. Одна из таких структур — массивы.

В этой статье мы расскажем, что такое массивы и зачем они нужны. Если же вы хотите научиться работать с ними в коде, почитайте материалы про массивы в C++ и в Java.

Что такое массив

Массив в программировании — это структура данных, которая хранит упорядоченный набор однотипных элементов. Его можно представить в виде шкафчика или камеры хранения на вокзале или в магазине: набор ячеек, в каждой из которых может что-то лежать.

Массив можно представить как шкафчик
Изображение: архив автора

Как и в шкафчике, каждая ячейка массива пронумерована, номер — это её индекс. Причём счёт идёт не от единицы, а от нуля.

Массивы есть в большинстве востребованных языков программирования, часто сразу в нескольких видах. Взгляните на семь самых популярных языков в рейтинге TIOBE — этот тип данных реализован в каждом из них.

Индекс TIOBE
Инфографика: TIOBE

При этом в разных языках программирования их могут называть по-разному и даже предлагать несколько реализаций. Например, в Python это lists (списки) и tuples (кортежи), в C++ — arrays (массивы) и vectors (векторы). Всё это массивы, но разных видов.

Для чего нужны массивы

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

Запись погоды без использования массивов
Иллюстрация: Оля Ежак для Skillbox Media

Эта информация хранится разрозненно, и переменные никак не связаны друг с другом. Если мы захотим посчитать среднюю температуру за декабрь, придётся писать длинную формулу:

Расчёт средней температуры без использования массивов
Иллюстрация: Оля Ежак для Skillbox Media

А если вдруг окажется, что термометр даёт ошибку в +3 градуса? Чтобы исправить ошибку, придётся вручную отнимать от каждой переменной 3 — и так для каждой из 31 строки кода.

Или, допустим, мы захотим учитывать температуру не только в нашем городе, но и в соседнем. Тогда в названии каждой переменной нужно будет дополнительно указывать не только дату, но и название города — так и запутаться можно.

Гораздо проще пойти другим путём: создать массив «Декабрь» и записывать температуру уже внутри него.

Запись погоды с использованием массивов
Иллюстрация: Оля Ежак для Skillbox Media

Так программа понимает, что эти элементы связаны между собой. Теперь мы за пару строчек кода можем найти среднемесячную температуру — достаточно сказать программе: сложи все элементы и раздели их на длину массива. Или прибавить три градуса (сказать: прибавь 3 к каждому элементу).

Если захотим измерять температуру в другом городе, можно просто создать другой массив — и их значения точно не перемешаются.

При этом обратиться к температуре любого — легче лёгкого, ведь каждый элемент имеет свой индекс, как номер ячейки в камере хранения. Нужно лишь запомнить, что нумерация обычно идёт от нуля.

Данные хранятся более упорядоченно, нет никакого нагромождения из десятков и сотен переменных, которые нужно держать в голове, чтобы не запутаться и не ошибиться.

В некоторых массивах можно хранить даже другие массивы. Например, мы можем объявить переменную Город_N_2022 и положить в неё массивы каждого из месяцев.

Использование массивов для записи погоды по городам
Иллюстрация: Оля Ежак для Skillbox Media

Массивы — очень полезный инструмент, о котором нередко спрашивают на собеседованиях. В разных языках программирования с ними можно совершать множество разных операций. Например, в PHP есть 13 способов для одной только сортировки массивов.

Как устроены массивы

Память в компьютере поделена на ячейки — фрагменты информации, которые имеют свой адрес. Можно сказать, это такой супермассив для всех данных внутри машины.

При создании массива компьютер выделяет непрерывный участок памяти и складывает в него элементы один за другим. Рассмотрим этот процесс подробнее.

Как резервируется память

Когда мы объявляем классический массив, мы также указываем его длину (сколько в нём будет элементов) и тип данных, которые будут в нём храниться. В случае массива «Декабрь» длина будет равна 31, а тип данных — float (число с плавающей запятой — мы всё-таки температуру записываем).

Так как все элементы принадлежат одному типу, они занимают одинаковый объём памяти. Допустим, в нашей архитектуре числа с плавающей запятой весят 4 байта. Компьютер умножает вес одного элемента на длину списка и получает количество памяти, которое ему нужно зарезервировать:

4 * 31 = 124 байта

И вот эти 124 соседних байта резервируются под массив «Декабрь». А до и после них в памяти могут быть какие угодно данные.

Ячейки памяти
Иллюстрация: Оля Ежак для Skillbox Media

Как работает обращение по индексу

Когда мы обращаемся к элементу массива по индексу, компьютеру нужно найти среди всей своей памяти ячейки, в которых лежит нужный элемент.

Для этого он определяет начальный адрес массива. Это адрес ячейки памяти, с которой начинается массив. Если он будет 54921, то память компьютера будет выглядеть следующим образом.

Начальный адрес массива
Иллюстрация: Оля Ежак для Skillbox Media

Извлечь из такой структуры элемент с нужным индексом несложно. Это делается по следующей формуле:

начальный адрес массива + индекс * число ячеек, которые занимает один элемент

Для наглядности подставим в эту формулу несколько индексов.

Индекс 0: 54921 + 0 * 4 = 54921 + 0 = 54921

Индекс 1: 54921 + 1 * 4 = 54921 + 4 = 54925

Индекс 2: 54921 + 2 * 4 = 54921 + 8 = 54929

За каждый индекс после нуля адрес ячейки смещается на 4, потому что именно столько весит каждый элемент массива. А если индекс равен нулю, смещения нет. Именно поэтому индексы считают с нуля, а не с единицы.

Теперь становится понятно, почему для классических массивов нужно заранее указывать тип данных и количество элементов:

  • Если компьютер не знает тип данных, то он не понимает, сколько памяти нужно выделять под каждый элемент и на сколько ячеек смещаться при поиске элемента по индексу.
  • Если компьютер не знает длину массива, то он не понимает, сколько памяти нужно под него выделить.

Виды массивов

Классический массив понятен, предсказуем, занимает мало места и быстро работает, но и возможности его применения ограничены. Чтобы массивы были более гибкими и подходили под разные задачи, в некоторых языках программирования придумали их более сложные реализации.

Статические и динамические

Длина статического массива определена заранее. При его создании программист сразу пишет, сколько в массиве будет элементов. Если положить в него меньше элементов, чем объявлено, то в остальных будут находиться пустые значения.

Это удобно, когда программист сразу знает, сколько элементов ему нужно. Если он записывает среднесуточную температуру за каждый день в декабре, то понадобится 31 элемент, если буквы русского алфавита — 33 элемента.

Длина динамических массивов, напротив, может изменяться во время выполнения программы. Например, программа должна хранить оценки школьника по информатике. Учитель ставит новую оценку — в массив добавляется новый элемент. Так это выглядит со стороны.

На самом деле при добавлении нового элемента компьютер создаёт новый массив, в который копирует старые элементы и добавляет новые. Старый массив при этом удаляется.

Так что по сути динамический массив — это тот же статический, но способный пересоздаваться с другой длиной.

Часто компьютер резервирует под динамические массивы немного больше места, чем нужно при создании. Он делает это для того, чтобы не пришлось пересоздавать массив, когда в него добавляют всего один или два новых элемента.

Однородные и гетерогенные

Однородные массивы состоят из элементов одинакового типа данных. Например, только целые числа или только строки. Хранить элементы разных типов в них нельзя.

В гетерогенных массивах одним элементом может быть целое число, другим — строка, третьим — вообще другой массив. Часто это может быть удобно, но среднее арифметическое всех его элементов, конечно, не посчитаешь. И ладно, если программа выдаст ошибку, — а если действительно решит посчитать и выведет результат?

На самом деле гетерогенные массивы хранят в себе не сами данные, а ссылку на них. Например, питоновский список может выглядеть так: [1, 'строка', False]. Но внутреннее его устройство сложнее: [ссылка на 1, ссылка на 'строка', ссылка на False]. А сами данные хранятся где-то ещё в разрозненном виде, никак не связанные друг с другом.

Получается, с технической точки зрения гетерогенный массив практически не отличается от гомогенного. Он тоже хранит в себе один тип данных — ссылочный.

Одномерные и многомерные

Одномерный массив — это ряд пронумерованных элементов. Они, как вагоны поезда, следуют друг за другом, и к ним можно обратиться по номеру: первый, второй, третий, десятый.

Двумерный массив — несколько рядов элементов. Его можно представить как таблицу, в которой есть строки и столбцы, а сами элементы находятся на их пересечении. Соответственно, индекс такого массива состоит из двух чисел: номера ряда (столбца) и номера элемента в этом ряду.

С точки зрения реализации он представляет собой массив, в котором лежат одномерные массивы.

Также бывают массивы трёхмерные, четырёхмерные, пятимерные и так далее. Чем больше измерений, тем сложнее структура и тем из большего количества чисел состоят индексы элементов.

Итоги

  • Массив — это структура данных фиксированной длины для хранения упорядоченного набора элементов. Элементы при этом должны относиться к одному типу данных.
  • Элементы массива физически хранятся в соседних ячейках памяти. К каждому из них можно обратиться по индексу.
  • У массива может быть более сложная реализация в зависимости от языка программирования. Длину динамического можно изменять, гетерогенные могут хранить ссылки на разные типы данных, а в многомерных каждый элемент имеет сразу несколько индексов.
Жизнь можно сделать лучше!
Освойте востребованную профессию, зарабатывайте больше и получайте от работы удовольствие.
Каталог возможностей
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована