Шаг 57.
Язык программирования C#. Начала
Массивы. Двумерные массивы (окончание)

    На этом шаге мы рассмотрим пример инициализации двумерного массива.

    Как и одномерный массив, двумерный массив можно инициализировать при создании. В этом случае переменной массива присваивается список со значениями, которыми инициализируется двумерный массив. Список значений заключается в фигурные скобки. Его элементами являются вложенные списки. Каждый вложенный список выделяется парой фигурных скобок. Значения, указанные во вложенных списках, определяют строки двумерного массива. Например, командой

  int[,] nums = { {1, 2, 3}, {4, 5, 6} }; 
создается целочисленный двумерный массив из двух строк и трех столбцов. Элементы в первой строке принимают значения 1, 2 и 3, а элементы во второй строке принимают значения 4, 5 и 6. А если воспользоваться командой
  int[,] nums = { {1, 2}, {3, 4}, {5, 6} };              , 
то получим массив из трех строк и двух столбцов (в первой строке - элементы со значениями 1 и 2, во второй строке - элементы со значениями 3 и 4, в третьей строке - элементы со значениями 5 и 6).


Наряду с командой
  int[,] nums = { {1, 2, 3}, {4, 5, 6} }; 
для инициализации массива могут использоваться и команды
  int[,] nums = new int [2, 3]{ {1, 2, 3}, {4, 5, 6} } ;
или
  int[,] nums = new int [,]{ {1, 2, 3}, {4, 5, 6} } ;    .
Если размеры массива не указаны, они определяются автоматически по списку инициализации. Если размеры массива указаны явно, то они должны соответствовать структуре списка инициализации.

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr57_1
{
    class Program
    {
        static void Main()
        {
            // Создание и инициализация двумерного массива: 
            char[,] symbs = { {'A', 'B', 'C'}, {'D', 'E', 'F'} };
            Console.WriteLine("Исходный массив:");
            // Отображение массива: 
            for(int i = 0; i < symbs.GetLength(0); i++)
            { 
                for(int j = 0; j < symbs.GetLength(1); j++) {
                    // Отображение значения элемента:
                    Console.Write(symbs[i,j] + " ");
                }
                // Переход к новой строке:
                Console.WriteLine();
            }
            // Объект для генерирования случайных чисел:
            Random rnd = new Random();
            // Строка и столбец:
            int row = rnd.Next(symbs.GetLength(0)+1);
            int col = rnd.Next(symbs.GetLength(1)+1);
            Console.WriteLine("Добавляется {0}-я строка и {1}-й столбец", row, col); 
            // Создание нового массива:
            char[,] tmp = new char[symbs.GetLength(0)+1, symbs.GetLength(1)+1];
            // Целочисленные переменные: 
            int a, b;
            // Символьная переменная: 
            char s = 'a';
            // Заполнение массива. Копирование значений
            // из исходного массива:
            for (int i = 0; i < symbs.GetLength(0); i++)
            {
                // Первый индекс для элемента нового массива: 
                if (i < row) a = i;
                else a = i + 1;
                for (int j = 0; j < symbs.GetLength(1); j++)
                {
                    // Второй индекс для элемента нового массива: 
                    if (j < col) b = j;
                    else b = j + 1;
                    // Присваивание значения элементу массива: 
                    tmp[a, b] = symbs[i, j];
                }
            }
            // Заполнение добавленной строки в новом массиве: 
            for(int j = 0; j < tmp.GetLength(1); j++){
                // Значение элемента в строке: 
                tmp[row, j] = s;
                // Новое значение для следующего элемента:
                s++;
            }
            for(int i = 0; i < tmp.GetLength(0); i++){
                // Если элемент не в добавленной строке: 
                if ( i != row ) {
                    // Значение элемента в столбце: 
                    tmp[i, col] = s;
                    // Новое значение для следующего элемента:
                    s++;
                }
            }
            // Присваивание массивов: 
            symbs = tmp;
            Console.WriteLine("Новый массив:");
            // Отображение массива: 
            for (int i = 0; i < symbs.GetLength(0); i++)
            {
                for (int j = 0; j < symbs.GetLength(1); j++)
                {
                    // Отображение значения элемента: 
                    Console.Write(symbs[i, j] + " ");
                }
                // Переход к новой строке:
                Console.WriteLine();
            }
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


Рис.1. Результат работы приложения

    Проанализируем программный код.

    Исходный символьный массив symbs создается и инициализируется командой

  char[,] symbs = { {'A', 'B', 'C'}, {'D', 'E', 'F'} };     .

    Это массив из двух строк и трех столбцов, заполненный английскими буквами в алфавитном порядке (хотя в данном случае это не принципиально). С помощью вложенных конструкций цикла содержимое этого массива отображается в консольном окне. Поскольку нам понадобится генерировать случайные числа, командой

  Random rnd = new Random();
создается объект rnd класса Random. Объект используется для определения индекса добавляемой строки и индекса добавляемого столбца. Индекс строки записывается в переменную row, а значение вычисляется как rnd.Next(symbs.GetLength(0)+1). Это случайное число в диапазоне от 0 до symbs.GetLength(0) (верхняя допустимая граница определяется количеством строк в исходном массиве). Индекс добавляемого столбца записывается в переменную col и вычисляется командой rnd.Next(symbs.GetLength(1)+1). Это случайное число в диапазоне от 0 до symbs.GetLength(1) (верхняя допустимая граница определяется количеством столбцов в исходном массиве). После того как индексы добавляемой строки и столбца определены, командой
   Console.WriteLine("Добавляется {0}-я строка и {1}-й столбец", row, col); 
отображается сообщение об индексе добавляемой строки и индексе добавляемого столбца. Командой
char[,] tmp = new char[symbs.GetLength(0)+1, symbs.GetLength(1)+1];
создается новый символьный массив. В нем на одну строку и на один столбец больше, чем в исходном массиве symbs. После создания массив tmp заполняется. Делается это в несколько этапов. Сначала в массив tmp копируются значения из исходного массива symbs. Но специфика этого процесса состоит в том, что если первый индекс элемента в массиве symbs больше или равен индексу row добавляемой строки, то при копировании нужно выполнить сдвиг на одну позицию вниз. Аналогично, если второй индекс элемента в массиве symbs больше или равен индексу col добавляемого столбца, то при копировании необходимо выполнить сдвиг на одну позицию вправо. Другими словами, индекс копируемого элемента в массиве symbs и индекс элемента в массиве tmp, которому присваивается значение, могут отличаться. С помощью вложенных конструкций цикла перебираются элементы в массиве symbs. Индексы элемента из массива tmp, которому присваивается значение, записываются в переменные а и b. Во внешнем цикле (индексная переменная i перебирает строки в массиве symbs) использована условная конструкция, где переменной а присваивается значение i при условии i<row и i+1 в противном случае. Во внутреннем цикле (индексная переменная j перебирает столбцы в массиве symbs) с помощью условной конструкции переменной b присваивается значение j при условии j<col и значение j+1 в противном случае. Командой
  tmp[a, b] = symbs[i, j];
присваивается значение элементу в массиве tmp.

    После выполнения вложенных циклов в массиве tmp присвоены значения всем элементам, за исключением тех, что находятся в добавляемой строке и добавляемом столбце. Эти строка и столбец заполняются отдельно. Сначала заполняется добавляемая строка: запускается конструкция цикла, в котором индексная переменная j перебирает элементы в строке с индексом row. Значение элементу в строке присваивается командой

  tmp[row, j] = s;             .

    Начальное значение переменной s равно 'а' (маленькая буква русского алфавита). Такое значение будет у первого элемента в добавленной строке. Для следующего элемента значением будет следующая буква в алфавите, поскольку мы использовали команду s++, которой значение переменной s "увеличивается на единицу": значением переменной становится следующий символ в алфавите.

    После заполнения добавленной строки заполняется добавленный столбец. В соответствующем операторе цикла индексная переменная i перебирает элементы в столбце с индексом col. Значение элементам присваивается командой

  tmp[i, col] = s;            .

    Единственное, это происходит лишь в случае, если элемент не находится в добавленной строке (значение этого элемента уже определено при заполнении строки). Поэтому мы использовали условный оператор с условием i!=row (первый индекс i элемента не совпадает с индексом row добавленной строки).

    На этом заполнение массива tmp завершается. Но мы идем дальше и выполняем присваивание массивов командой

  symbs = tmp;                .

    В результате и переменная symbs, и переменная tmp ссылаются на один и тот же массив: это новый массив, созданный путем добавления к исходному массиву строки и столбца. Для проверки содержимого созданного массива использованы вложенные циклы.


Мы создали новый массив и ссылку в переменной массива symbs "перебросили" на этот новый массив. В итоге создается иллюзия, что изменен исходный массив. Так, вложенные конструкции цикла в самом начале программы и в самом конце программы фактически одинаковы. Эти управыляющие блоки используются для отображения содержимого массива, на который ссылается переменная symbs. Но массивы отображаются разные. Причина в том, что в начале выполнения программы и в конце выполнения программы переменная symbs ссылается на разные массивы. Причем у них не просто разные значения элементов, а разное количество строк и столбцов.

    Что касается исходного массива, на который ранее ссылалась переменная symbs, то, поскольку на этот массив больше не ссылается ни одна переменная, массив из памяти будет удален системой сборки мусора.


    На следующем шаге мы рассмотрим многомерные массивы.




Предыдущий шаг Содержание Следующий шаг