Выбрать главу

Есть некоторые особенности в объявлении и инициализации таких массивов. Если при объявлении типа многомерных массивов для указания размерности использовались запятые, то для изрезанных массивов применяется более ясная символика — совокупности пар квадратных скобок; например, int [] [] задает массив, элементы которого — одномерные массивы элементов типа int.

Сложнее с созданием самих массивов и их инициализацией. Здесь нельзя вызвать конструктор new int [3] [5], поскольку он не задает изрезанный массив. Фактически нужно вызывать конструктор для каждого массива на самом нижнем уровне. В этом и состоит сложность объявления таких массивов. Начну с формального примера:

//массив массивов — формальный пример

//объявление и инициализация

int[] [] jagger = new int[3] []

{

     new int [] {5,7,9,11},

     new int [] {2,8},

     new int [] {6,12,4}

};

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

int[] [] j agger1 = new int[3] []

{

     new int [4],

     new int [2],

     new int [3]

};

В этом случае элементы массива получат при инициализации нулевые значения. Реальную инициализацию нужно будет выполнять программным путем. Стоит заметить, что в конструкторе верхнего уровня константу 3 можно опустить и писать просто new int [] []. Самое забавное, что вызов этого конструктора можно вообще опустить — он будет подразумеваться:

int [] [] j agger2 =

{

      new int [4],

      new int [2],

      new int [3]

};

А вот конструкторы нижнего уровня необходимы. Еще одно важное замечание — динамические массивы возможны и здесь. В общем случае, границы на любом уровне могут быть выражениями, зависящими от переменных. Более того, допустимо, чтобы массивы на нижнем уровне были многомерными. Но это уже "от лукавого" — вряд ли стоит пользоваться такими сложными структурами данных, ведь с ними предстоит еще и работать.

Приведу теперь чуть более реальный пример, описывающий простое генеалогическое дерево, которое условно назову "отцы и дети":

//массив массивов — "Отцы и дети"

int Fcount =3;

string[] Fathers = new string[Fcount];

Fathers[0] ="Николай"; Fathers[1] = "Сергей";

      Fathers[2] = "Петр";

string[][] Children = new string[Fcount][];

Children[0] = new string[] {"Ольга", "Федор"};

Children[1] = new string[]

       {"Сергей","Валентина","Ира","Дмитрий"};

Children[2] = new string[]{"Мария","Ирина","Надежда"};

myar.PrintAr3(Fathers,Children);

Здесь отцов описывает обычный динамический одномерный массив Fathers. Для описания детей этих отцов необходим уже массив массивов, который также является динамическим на верхнем уровне, поскольку число его элементов совпадает с числом элементов массива Fathers. Здесь показан еще один способ создания таких массивов. Вначале конструируется массив верхнего уровня, содержащий ссылки со значением void. А затем на нижнем уровне конструктор создает настоящие массивы в динамической памяти, с которыми и связываются ссылки.

Я не буду демонстрировать работу с генеалогическим деревом, ограничусь лишь печатью этого массива. Здесь есть несколько поучительных моментов. В классе Arrs для печати массива создан специальный метод PrintAr3, которому в качестве аргументов передаются массивы Fathers и children. Вот текст данной процедуры:

public void PrintAr3(string [] Fathers, string[][] Children)

{

     for (int i = 0; i < Fathers.Length; i + +)

     {

         Console.WriteLine("Отец: {0}; Его дети: ", Fathers[i]);

         for (int j = 0; j < Children[i].Length; j++)

             Console.Write(Children[i][j] + " ");

         Console.WriteLine ();

     }

}//PrintAr3

Приведу некоторые комментарии к этой процедуре:

• Внешний цикл по i организован по числу элементов массива Fathers. Заметьте, здесь используется свойство Length, в отличие от ранее применяемого метода GetLength.