Course program← C#: Базовый курс
1Знакомство с C# и .NET
2Данные и типы
3Ветвления и циклы
4Методы и ошибки
5Коллекции и строки
6Классы и объекты

Массивы

This lesson is not translated yet – the Russian original is below.

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

Объявление

Три способа записать одно и то же:

int[] a = new int[5];                  // пять нулей
int[] b = new int[] { 1, 2, 3 };       // с указанием значений
int[] c = { 1, 2, 3 };                 // короткая форма

Квадратные скобки идут после типа, а не после имени: int[] numbers, а не int numbers[], как в C и Java.

Элементы заполняются автоматически: числа – нулями, bool – значением false, ссылочные типы – null. Это отличие от локальных переменных, которые компилятор требует присвоить вручную.

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

int[] numbers = { 10, 20, 30 };

Console.WriteLine(numbers[0]);    // 10 – первый
Console.WriteLine(numbers[2]);    // 30 – последний

numbers[1] = 99;                  // запись

Нумерация с нуля, поэтому у массива из трёх элементов индексы 0, 1 и 2. Длина хранится в свойстве Length:

Console.WriteLine(numbers.Length);          // 3
Console.WriteLine(numbers[numbers.Length - 1]);    // последний элемент

Выход за границы – это IndexOutOfRangeException во время работы, а не при компиляции. Компилятор не знает, каким будет индекс: он мог прийти от пользователя. Проверка происходит в рантайме, каждый раз – именно поэтому рантайм и гарантирует, что чужую память вы не прочитаете.

Индексы с конца

Писать numbers[numbers.Length - 1] неудобно, поэтому есть короткая запись:

Console.WriteLine(numbers[^1]);    // последний
Console.WriteLine(numbers[^2]);    // предпоследний

Знак ^ означает отсчёт с конца, причём ^1 – это именно последний элемент, а не выход за границу: с конца счёт идёт с единицы, а с начала – с нуля.

Диапазон элементов берётся оператором ..:

int[] all = { 1, 2, 3, 4, 5 };

int[] middle = all[1..4];     // 2, 3, 4 – правая граница не включается
int[] head = all[..2];        // 1, 2
int[] tail = all[3..];        // 4, 5

Размер не меняется

Главное ограничение массива: длина задаётся при создании и остаётся навсегда. Добавить шестой элемент в массив из пяти невозможно – можно только создать новый массив и скопировать туда старое содержимое.

int[] bigger = new int[numbers.Length + 1];
Array.Copy(numbers, bigger, numbers.Length);
bigger[^1] = 40;

Делать так вручную приходится редко: для меняющегося набора данных есть List<T>, о нём следующий урок. Массив берут, когда количество элементов известно заранее и не меняется.

Перебор

Оба способа вы уже знаете:

foreach (var number in numbers)
{
    Console.WriteLine(number);
}

foreach – когда нужны все элементы подряд. for – когда нужен индекс или обход не с начала:

for (int i = numbers.Length - 1; i >= 0; i--)
{
    Console.WriteLine(numbers[i]);    // в обратном порядке
}

Что умеет класс Array

Готовые операции лежат в статическом классе Array:

int[] numbers = { 5, 3, 8, 1 };

Array.Sort(numbers);              // 1, 3, 5, 8 – сортирует на месте
Array.Reverse(numbers);           // 8, 5, 3, 1
int index = Array.IndexOf(numbers, 3);    // 2, или -1 если не нашлось

Array.Sort меняет исходный массив, а не возвращает новый. Это частая ловушка: если исходный порядок ещё нужен, сначала сделайте копию через ToArray().

Полезные методы есть и у самого массива – они пришли из LINQ и работают со всеми коллекциями:

Console.WriteLine(numbers.Max());
Console.WriteLine(numbers.Min());
Console.WriteLine(numbers.Sum());
Console.WriteLine(numbers.Average());

Для них нужен using System.Linq; – в новых проектах он подключается автоматически.

Двумерные массивы

Таблица объявляется через запятую в скобках:

int[,] table = new int[3, 4];        // три строки, четыре столбца

table[0, 0] = 1;
table[2, 3] = 9;

Console.WriteLine(table.GetLength(0));    // 3 – строк
Console.WriteLine(table.GetLength(1));    // 4 – столбцов

У двумерного массива Length вернёт общее число ячеек (12), а не число строк – для размерностей есть GetLength.

Существует и второй вид – массив массивов, где строки могут быть разной длины:

int[][] jagged = new int[3][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };

Различать их просто: [,] – прямоугольная таблица, [][] – набор независимых массивов. Первый экономнее по памяти, второй гибче.