JavaRush /Курсы /C# SELF /Зубчатые массивы (Jagged Arrays) в C#

Зубчатые массивы (Jagged Arrays) в C#

C# SELF
7 уровень , 5 лекция
Открыта

1. Чем зубчатые массивы отличаются от двумерных

Вот мы дошли до темы, которую многие называют «массивами массивов» или «зубчатыми массивами» — по-английски jagged arrays. В отличие от двумерных массивов, зубчатые массивы позволяют хранить колонки разной длины. Это как если бы у вас был комплекс зданий, где у каждого здания свое количество квартир — в одном здании 5 квартир, в другом 20, а в третьем — всего одна.

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

Главное отличие:

  • В двумерном массиве у каждой «строки» (и у каждого «столбца») одинаковое количество элементов. Пример: int[,] grid = new int[3, 5]; — у нас всегда 3 строки по 5 элементов.
  • В зубчатом массиве каждая строка может быть разной длины! Пример: int[][] jagged = new int[3][]; — и только потом мы каждую строку (подмассив) инициализируем по-своему.

Вот как это выглядит визуально:

Двумерный массив Зубчатый массив
Количество элементов Строго фиксированное (например, 3х5) Может отличаться между разными строками
Индексация
[i, j]
[i][j]
Гибкость Низкая Высокая
Применение Таблицы, математика Неравномерные данные:
списки студентов с разным числом оценок, треугольники

Визуализация: сравним двумерный и зубчатый массив

Двумерный массив (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘

Зубчатый массив (разные длины):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘

2. Синтаксис объявления и инициализации зубчатого массива

Объявление зубчатого массива не страшнее, чем объявления предыдущих типов! Пугаться двойных квадратных скобок не стоит:

int[][] jaggedArray = new int[3][];
Объявление зубчатого массива

Это значит, что у нас есть массив из 3 элементов, и каждый из них — это тоже массив int-ов. Но пока что внутренние массивы не созданы! Для лучшего понимания давайте разберём это подробнее.

Пошаговая инициализация зубчатого массива

Шаг 1 — создание основного (внешнего) массива:

int[][] jaggedArray = new int[3][];

Теперь у нас есть 3 «строки», но все они пока равны null.

Шаг 2 — создание и заполнение внутренних массивов (подмассивов):

Например, пусть первая строка будет длиной 2, вторая — 4, третья — 3:

jaggedArray[0] = new int[2]; // 2 элемента в первой строке
jaggedArray[1] = new int[4]; // 4 элемента во второй строке
jaggedArray[2] = new int[3]; // 3 элемента в третьей строке

Шаг 3 — заполнение значениями:

Внутренние массивы — это обычные массивы! Например:

jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;

jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
jaggedArray[1][3] = 6;

jaggedArray[2][0] = 7;
jaggedArray[2][1] = 8;
jaggedArray[2][2] = 9;

Краткая инициализация зубчатого массива

Можно создать и заполнить зубчатый массив сразу, если вы знаете значения заранее:

int[][] jaggedArray = new int[][]
{
    new int[] { 1, 2 },
    new int[] { 3, 4, 5, 6 },
    new int[] { 7, 8, 9 }
};

Или чуть короче, опуская тип внутренних массивов:

int[][] jaggedArray = {
    new[] { 1, 2 },
    new[] { 3, 4, 5, 6 },
    new[] { 7, 8, 9 }
};

3. Перебор и работа с зубчатыми массивами

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

for (int i = 0; i < jaggedArray.Length; i++)
{
    Console.WriteLine($"Строка {i}:");
    for (int j = 0; j < jaggedArray[i].Length; j++)
    {
        Console.Write($"{jaggedArray[i][j]} ");
    }
    Console.WriteLine();
}

Итог на экране:

Строка 0:
1 2 
Строка 1:
3 4 5 6 
Строка 2:
7 8 9 

Можно использовать foreach, чтобы не думать об индексах:

foreach (int[] row in jaggedArray)
{
    foreach (int value in row)
    {
        Console.Write($"{value} ");
    }
    Console.WriteLine();
}

4. Устройство массива массивов

А сейчас вы узнаете, как на самом деле устроены массивы массивы. Готовы?

Если в случае с обычным массивом «переменная-массив хранит ссылку на контейнер, который хранит элементы массива». То в случае с зубчатыми массивами у нас ситуация немного взрывоопаснее: переменная-массив-массивов хранит ссылку на контейнер, который хранит ссылки на одномерные массивы. Это лучше один раз увидеть, чем сто раз попробовать объяснить:

Устройство двумерных массивов

Слева у нас «переменная-массив-массивов», которая хранит ссылку на «объект-контейнер массивов». В середине у нас «объект-контейнер массивов», в ячейках которого хранятся ссылки на одномерные массивы — строки зубчатого массива. Ну и справа вы видите четыре одномерных массива — строки нашего зубчатого массива.

Это то, как на самом деле устроены зубчатые массивы. И такой подход дает C#-программисту несколько преимуществ:

Во-первых, т.к. «контейнер контейнеров» хранит ссылки на «массивы-строки», мы можем очень быстро и просто менять строки местами. Чтобы получить доступ к «контейнеру контейнеров», нужно просто указать один индекс вместо двух. Пример:
int[][] data = new int[2][];
data[0] = new int[5]; // первая строка — массив из 5 элементов
data[1] = new int[5]; // вторая строка — массив из 5 элементов

int[] row1 = data[0];
int[] row2 = data[1];

Вот с помощью такого кода можно поменять строки местами:

// Важная матрица с данными
int[][] matrix = {
  new int[] {1, 2, 3, 4, 5},
  new int[] {5, 4, 3, 2, 1}
};

int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;

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

5. Типичные сценарии применения зубчатых массивов

Когда зубчатый массив может быть полезнее двумерного?

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

Пример из жизни: менеджер оценок студентов

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

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

Студент Оценки
0 5, 4
1 3, 4, 4
2 5

Объявим такой массив:

int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 };         // Первый студент - 2 оценки
studentMarks[1] = new int[] { 3, 4, 4 };      // Второй студент - 3 оценки
studentMarks[2] = new int[] { 5 };            // Третий студент - 1 оценка

Выведем оценки каждого студента:

for (int i = 0; i < studentMarks.Length; i++)
{
    Console.Write($"Студент {i}: ");
    for (int j = 0; j < studentMarks[i].Length; j++)
    {
        Console.Write(studentMarks[i][j] + " ");
    }
    Console.WriteLine();
}

Использование зубчатых массивов с другими типами

Зубчатым может быть массив чего угодно: строк, массивов других массивов (глубже!), даже ваших собственных объектов.

Пример: массив строк

string[][] groups = new string[][]
{
    new string[] { "Иван", "Пётр" },
    new string[] { "Мария", "Алексей", "Сергей" },
    new string[] { "Василиса" }
};

6. Особенности и возможные ошибки

Зубчатые массивы — штука гибкая, но и ловушки расставлены на каждом шагу.

  • Если вы не инициализировали какой-то из внутренних массивов (jaggedArray[1] = ...), попытка обратиться к нему приведёт к NullReferenceException. Не забывайте инициализировать каждый внутренний массив!
  • Не все строки (подмассивы) одинаковой длины. Если использовать фиксированный индекс во втором измерении, можно выйти за его пределы.
  • Не путайте с двумерным массивом! Индексация выглядит так: array[i][j], а не array[i, j].
2
Задача
C# SELF, 7 уровень, 5 лекция
Недоступна
Объявление и инициализация простого зубчатого массива
Объявление и инициализация простого зубчатого массива
2
Задача
C# SELF, 7 уровень, 5 лекция
Недоступна
Наибольшее значение в зубчатом массиве
Наибольшее значение в зубчатом массиве
1
Опрос
Массивы, 7 уровень, 5 лекция
Недоступен
Массивы
Знакомство с массивами
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Александр Уровень 24
7 октября 2025
в опроснике некоторые правильные ответы подсвечены серым, поправьте плз)