Массив хранит фиксированное число элементов одного типа, расположенных в памяти подряд. Вы выбираете длину при создании, читаете и записываете элементы по индексу, начиная с нуля, и после этого длина никогда не меняется.
Объявление и инициализация массива
Тип массива это тип элемента, за которым следует []. Создать массив можно несколькими способами:
Вывод:
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> внутри хранит элементы в массиве.