Перейти к содержимому
Теория · Массивы · урок 1 из 9

Массивы

Чему вы научитесь

Чему вы научитесь:

  • создавать массив, читать и менять его элементы по индексу;
  • обходить массив циклами for и foreach;
  • объяснять, почему после int[] b = a; у одного массива два имени;
  • сортировать массив, искать в нём и брать его части через ^1 и 1..3.
Ряд из трёх шкафчиков scores с номерами 0 1 2: шкафчик 1 открыт, на дверце бирка scores[1], а четвёртого места нет

Представьте ряд одинаковых шкафчиков в раздевалке бассейна. На каждой дверце номер, и нумерация начинается с нуля: шкафчик 0, шкафчик 1, шкафчик 2. Чтобы положить вещь или забрать её, достаточно назвать номер. Сколько шкафчиков в ряду, решают, когда ряд ставят, и пристроить к нему ещё один потом нельзя.

Зачем такой ряд программе? Если нужно хранить баллы 3 учеников, можно завести 3 переменные: score1, score2 и score3. Но для 30 учеников понадобится 30 имён, и цикл не сможет пройти по ним: номер в имени переменной нельзя подставить из счётчика.

Такой ряд в C# называется массивом: это набор переменных одного типа под одним именем. Каждая переменная ряда — элемент массива, а её номер — индекс.

C#
int[] scores = [90, 75, 88];
Console.WriteLine(scores[0]);     // 90
Console.WriteLine(scores[2]);     // 88
scores[1] = 80;
Console.WriteLine(scores[1]);     // 80
Console.WriteLine(scores.Length); // 3

Давайте разберём программу по строкам:

  1. int[] scores объявляет переменную для массива. Тип int[] читается как «массив чисел int»: квадратные скобки после типа означают массив.
  2. [90, 75, 88] создаёт массив из трёх элементов и кладёт в них эти числа по порядку.
  3. scores[0] — элемент с индексом 0, то есть первый. Программа печатает 90.
  4. scores[2] — третий и последний элемент, 88.
  5. scores[1] = 80; кладёт новое значение во второй элемент, а остальные не трогает.
  6. scores.Length — длина массива, число его элементов: 3.

Индексы начинаются с нуля

В массиве из трёх элементов индексы 0, 1 и 2. Индекс последнего элемента на единицу меньше длины: scores.Length - 1.

Почему с нуля? Индекс показывает, на сколько элементов нужно отступить от начала массива. Первый элемент стоит в самом начале, отступать не нужно, поэтому его индекс 0.

Как создать массив

Перечень значений

В перечне [90, 75, 88] значения стоят в квадратных скобках через запятую, а длину компилятор считает сам. Такая форма появилась в C# 12. В коде постарше тот же массив пишут как new int[] { 90, 75, 88 }.

У перечня в квадратных скобках нет собственного типа: его задаёт объявление слева. Поэтому var scores = [90, 75, 88]; не скомпилируется, и компилятор сообщит об ошибке CS9176.

Массив заданной длины

Если значения станут известны позже, массив создают по длине: new int[3]. Каждый элемент такого массива уже получил значение:

C#
int[] counts = new int[3];
Console.WriteLine(counts[0]); // 0
counts[2] = 7;
Console.WriteLine(counts[2]); // 7
bool[] flags = new bool[2];
Console.WriteLine(flags[1]);  // False

Новый массив чисел заполнен нулями, а массив bool — значениями false. Длина может быть и переменной: new int[n] создаёт массив из n элементов. Но после создания она не меняется.

Здесь аналогия со шкафчиками неточна. Настоящий шкафчик бывает пустым, а элемент массива — нет: в нём всегда лежит значение, хотя бы ноль.

Обход в цикле for

Индекс может быть переменной. Поэтому цикл for проходит по всему массиву: его счётчик i по очереди принимает значения всех индексов.

C#
int[] scores = [90, 75, 88];
for (int i = 0; i < scores.Length; i++)
{
    Console.WriteLine(i + ": " + scores[i]);
}
// 0: 90
// 1: 75
// 2: 88

Разберём заголовок цикла:

  • int i = 0 — счётчик начинает с индекса первого элемента;
  • i < scores.Length — цикл продолжается, пока индекс меньше длины: последний индекс 2, а при i, равном 3, цикл заканчивается;
  • i++ — после каждой итерации счётчик переходит к следующему индексу.

Условие пишут именно через <, а не через <=. С <= счётчик дойдёт до индекса 3, которого в массиве нет.

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

Последний элемент попытались прочитать по индексу, равному длине:

C#
int[] scores = [90, 75, 88];
Console.WriteLine(scores[scores.Length]); // ✗
TEXT
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.

Программа компилируется, но при запуске останавливается на этой строке с исключением IndexOutOfRangeException. Строки до неё успевают выполниться, а строки после — нет. Последний элемент — scores[scores.Length - 1].

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

Главное

  • Массив — ряд элементов одного типа под одним именем; int[] — массив чисел int.
  • Индексы начинаются с нуля: у первого элемента индекс 0, у последнего — Length - 1.
  • [90, 75, 88] создаёт массив из перечисленных значений, new int[3] — из трёх нулей; длина массива после создания не меняется.
  • Индекс за границей массива останавливает программу с исключением IndexOutOfRangeException.