Menu

Массивы в C#: объявление, Length, сортировка, двумерные и зубчатые массивы

Массив в C# это блок фиксированного размера из элементов одного типа. Как объявлять и инициализировать массивы, читать Length, сортировать и искать с помощью класса Array, безопасно копировать массивы и работать с двумерными и зубчатыми массивами.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

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

Объявление и инициализация массива

Тип массива это тип элемента, за которым следует []. Создать массив можно несколькими способами:

Вывод:

90, 0, 0, 72
Ben
2 prices, 3 days

new int[4] заполняет каждый элемент значением по умолчанию для типа: 0 для чисел, false для bool, null для строк и других ссылочных типов. Короткая форма { "Ana", "Ben" } работает только в объявлении; при присваивании существующей переменной нужно names = new[] { "Dev", "Eli" };.

Length, индексация и последний элемент

Индексы идут от 0 до Length - 1. Length это свойство, поэтому у него нет скобок (в отличие от метода LINQ Count()).

Вывод:

Count: 5
First: 18
Last: 16
Caught IndexOutOfRangeException

Чтение или запись за границами выбрасывает IndexOutOfRangeException во время выполнения; компилятор это не ловит. Обычная причина это условие цикла, записанное как i <= arr.Length вместо i < arr.Length.

C# 8 и новее добавляют синтаксис индекса с конца и диапазонов, который короче для последнего элемента и для срезов:

int last = temps[^1];        // 16
int[] middle = temps[1..4];  // { 21, 25, 19 }, a new array

Обход массива

Цикл for даёт индекс; foreach даёт каждый элемент и понятнее, когда вы только читаете.

Вывод:

4.95 | 13.20 | 3.58
Total: 21.73

Переменная foreach доступна только для чтения: p = 0; внутри цикла это ошибка компиляции. Чтобы менять элементы, используйте цикл с индексом.

Сортировка, переворот и поиск

Вспомогательные методы находятся в статическом классе Array. Array.Sort сортирует на месте и ничего не возвращает, поэтому исходный порядок теряется.

Вывод:

Ascending:  60, 72, 79, 88, 95
Descending: 95, 88, 79, 72, 60
Index of 60: 4
Index of 99: -1
Any above 90: True
First below 75: 72
Ana, ben, chloe
fig, kiwi, banana

Array.IndexOf возвращает -1, если значения нет. Array.Find возвращает значение по умолчанию для типа (здесь 0), когда ничего не найдено, что для чисел неоднозначно; когда это важно, используйте Array.FindIndex. Сортировка по убыванию одним вызовом: Array.Sort(scores, (a, b) => b.CompareTo(a)).

Если нужен отсортированный результат без изменения оригинала, LINQ возвращает новый массив: var sorted = scores.OrderBy(s => s).ToArray();. См. LINQ.

Изменение размера: массив не может расти

Длина фиксирована. Array.Resize создаёт новый массив нужного размера, копирует элементы и обновляет переменную, переданную через ref.

Вывод:

4
2
True
False

Каждое изменение размера копирует все элементы. Наращивание массива по одному элементу в цикле медленное, и именно это List<T> делает за вас эффективнее, удваивая свой внутренний массив.

Массивы это ссылочные типы: копирование

Присваивание массива другой переменной копирует ссылку, а не элементы. После этого оба имени указывают на один и тот же массив.

Вывод:

100
2
0, 100, 2, 3, 0

То же самое происходит, когда массив передаётся в метод: метод может изменить элементы вызывающего кода. Clone, Array.Copy, CopyTo и ToArray() из LINQ делают поверхностную копию. Для массива объектов новый массив хранит ссылки на те же объекты, поэтому изменение copy[0].Name всё равно меняет то, что видит original[0].

Сравнение массивов через == сравнивает ссылки. Чтобы сравнить содержимое, используйте a.SequenceEqual(b) из System.Linq.

Двумерные массивы (многомерные)

Прямоугольная сетка объявляется с запятой внутри квадратных скобок. Индексируйте её через [row, col].

Вывод:

Rows: 2
Cols: 3
Length: 6, Rank: 2
. X . 
. . X 

Length у двумерного массива это общее число элементов (6 для сетки 2 на 3), поэтому вложенные циклы используют GetLength(0) и GetLength(1). Rank это число измерений. Три измерения работают так же: new int[4, 4, 4] и cube[x, y, z]. foreach по двумерному массиву посещает каждый элемент строка за строкой.

Зубчатые массивы (массивы массивов)

Зубчатый массив int[][] это массив, элементы которого сами являются массивами, и у каждого внутреннего массива может быть своя длина. Он подходит для данных вроде «заказы каждого клиента», где строки разного размера.

Вывод:

Customer 0: 2 orders, 20, 35
Customer 1: 1 orders, 12
Customer 2: 4 orders, 8, 15, 40, 22
True

new int[3][] создаёт только внешний массив; каждая строка сначала равна null, и обращение к orders[0][0] до присваивания строки выбрасывает NullReferenceException. Синтаксис new int[3][4] недопустим; каждую строку вы создаёте сами.

Используйте [,] для настоящей сетки (доска, матрица, пиксели) и [][], когда строки разной длины или нужно менять местами целые строки.

Массив или List

Массив T[]List<T>
РазмерФиксирован при созданииРастёт и уменьшается
КоличествоСвойство LengthСвойство Count
Добавление или удалениеНевозможно (только Array.Resize)Add, Insert, Remove
Многомерность[,] и [][]Только списки списков
Типичное применениеИзвестный размер, таблицы поиска, буферыИзменяющиеся коллекции

Преобразование в любую сторону это один вызов: new List<int>(arr) или arr.ToList(), а также list.ToArray(). List<T> это растущая версия массива.

Частые ошибки

  • i <= arr.Length в цикле. Последний допустимый индекс Length - 1; такое условие выбрасывает IndexOutOfRangeException.
  • Вывод массива напрямую. Console.WriteLine(arr) печатает System.Int32[]; используйте string.Join.
  • Ожидание, что Array.Sort вернёт отсортированный массив. Он возвращает void и сортирует на месте.
  • Копирование через =. Так копируется ссылка; используйте Clone() или ToArray().
  • Использование строк зубчатого массива до их создания. Каждая строка new T[n][] равна null, пока ей не присвоят значение.
  • Length для числа строк двумерного массива. Он считает все элементы; используйте GetLength(0).

Часто задаваемые вопросы

Как получить длину массива в C#?

Используйте свойство Length: scores.Length. Это свойство, а не метод, поэтому скобки не нужны. Для двумерного массива Length это общее число элементов; используйте GetLength(0) для числа строк и GetLength(1) для числа столбцов.

Как отсортировать массив в C#?

Array.Sort(arr) сортирует массив на месте по возрастанию. Для сортировки по убыванию вызовите Array.Reverse(arr) после сортировки или передайте сравнение: Array.Sort(arr, (a, b) => b.CompareTo(a)). Чтобы получить отсортированную копию и сохранить оригинал, используйте LINQ: arr.OrderBy(x => x).ToArray().

Чем двумерный массив отличается от зубчатого в C#?

Двумерный массив int[,] это один прямоугольный блок: в каждой строке одинаковое число столбцов, а индексируется он как grid[row, col]. Зубчатый массив int[][] это массив массивов: каждая строка это отдельный массив со своей длиной, а индексируется он как rows[i][j]. Каждую строку зубчатого массива нужно создать перед использованием, иначе она равна null.

Можно ли изменить размер массива в C#?

Нет. Длина массива фиксируется при создании. Array.Resize(ref arr, newSize) выглядит как изменение размера, но на самом деле выделяет новый массив, копирует элементы и направляет вашу переменную на новый массив. Если размер часто меняется, используйте List<T>.

Почему при выводе массива печатается System.Int32[]?

Console.WriteLine(arr) вызывает arr.ToString(), а массивы его не переопределяют, поэтому вы получаете имя типа. Вместо этого соедините элементы в одну строку: Console.WriteLine(string.Join(", ", arr)).

Что использовать в C#, массив или List?

Используйте массив, когда число элементов известно и фиксировано, например 12 месяцев или игровое поле. Используйте List<T>, когда элементы со временем добавляются или удаляются. Оба индексируются за постоянное время, а List<T> внутри хранит элементы в массиве.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ