Шаг 59.
Язык программирования C#. Начала
Массивы. Массив со строками разной длины

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

    Напомним, как создается одномерный массив: объявляется переменная массива, и значением ей присваивается ссылка на массив. Впоследствии переменная массива отождествляется с массивом, на который она ссылается. Важно здесь то, что такую переменную можно индексировать - после имени переменной в квадратных скобках указывается индекс, в результате чего мы получаем доступ к элементу массива. А теперь представим, что мы создали одномерный массив, элементами которого являются переменные массива. Общая схема будет следующей: есть переменная массива, которая ссылается на массив, и этот массив состоит из переменных массива, ссылающихся на массивы. Именно такой подход реализован в примере, представленном ниже.

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

namespace pr59_1
{
    class Program
    {
        static void Main()
        {
            // Символьный массив из переменных массива: 
            char[][] symbs = new char[5][];
            // Целочисленный массив из переменных массива:
            int[][] nums = {new int[]{1,2,3}, new int[]{4,5}, new int[]{6,7,8,9}};
            // Символьная переменная:
            char s = 'А';
            // Заполнение символьного массива.
            // Перебор элементов во внешнем массиве: 
            for(int i = 0; i < symbs.Length; i++){
                // Создание внутреннего массива: 
                symbs[i] = new char[i+3];
                // Перебор элементов во внутреннем массиве: 
                for(int j = 0; j < symbs[i].Length; j++){
                    // Значение элемента внутреннего массива: 
                    symbs[i][j] = s;
                    // Значение для следующего элемента: 
                    s++;
                }
            }
            Console.WriteLine("Целочисленный массив:");
            // Отображение целочисленного массива: 
            for(int i = 0; i < nums.Length; i++){
                for(int j = 0; j < nums[i].Length; j++){
                    // Отображение элемента массива:
                    Console.Write("{0,3}", nums[i][j]);
                }
                Console.WriteLine();
            }
            Console.WriteLine("Символьный массив:");
            // Отображение символьного массива.
            // Перебор элементов внешнего массива: 
            foreach(char[] q in symbs){
                // Перебор элементов во внутреннем массиве: 
                foreach(char р in q){
                    // Отображение элемента массива:
                    Console.Write("{0,2}", р);
                }
                Console.WriteLine();
            }
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    Результат выполнения программы представлен ниже.


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

    В программе есть несколько моментов, достойных внимания. Итак, командой

  char[][] symbs = new char[5][];
создается массив symbs. Но это не очень обычный массив. Это массив одномерный, не двумерный. Массив из пяти элементов. Элементами массива являются переменные, которые могут ссылаться на символьные одномерные массивы. При объявлении переменной массива symbs после идентификатора типа char использованы двойные прямоугольные скобки [][]. Одна пара квадратных скобок означает, что создается массив. Вторая относится непосредственно к идентификатору типа. Фактически получается, что мы объявляем переменную для одномерного массива, который состоит из элементов типа char[]. А такое выражение используется при объявлении переменной для символьного массива. Далее, инструкция new char [5][] означает, что создается одномерный массив из пяти элементов (значение 5 в первых квадратных скобках). Вторые пустые квадратные скобки относятся к идентификатору типа char. Получается, что мы создаем массив из элементов типа char [] и размер массива равен 5. Итог такой: переменная symbs ссылается на массив из пяти элементов. Каждый элемент массива является переменной массива. Каждая такая переменная может ссылаться на одномерный символьный массив (но пока не ссылается, поскольку самих массивов еще нет - их нужно создать). Массивы создаются и заполняются с помощью конструкций цикла. С помощью цикла с индексной переменной i перебираются элементы в массиве symbs (будем называть его внешним массивом). Индексная переменная i принимает значения в диапазоне, ограниченном сверху величиной symbs.Length (условие "строго меньше"). Здесь еще раз имеет смысл подчеркнуть, что массив symbs - одномерный. В теле этой конструкции цикла командой
  symbs[i] = new char[i+3];
создается символьный массив, и ссылка на него записывается в элемент symbs[i]. Размер массива определяется значением выражения i+3. То есть массивы, создаваемые в рамках разных циклов, имеют разные размеры. И эти массивы нужно заполнять. Поэтому используется внутренняя конструкция цикла с индексной переменной j. Верхняя граница диапазона изменения индексной переменной j определяется выражением symbs[i].Length (условие "строго меньше"). Здесь мы должны учесть, что symbs[i] - это переменная, которая ссылается на одномерный массив, и фактически переменная обрабатывается как одномерный массив. Значением выражения symbs[i].Length является количество элементов в массиве, на который ссылается переменная symbs[i].

    В теле внутреннего цикла командой

  symbs[i][j] = s;
присваивается значение элементу во внутреннем массиве (массив, на который ссылается переменная symbs[i]). Начальное значение переменной s равно 'А' (большая буква русского алфавита). За каждый цикл значение переменной s "увеличивается на единицу", в результате чего элементы массива заполняются большими буквами русского алфавита.

    Для отображения элементов созданного "массива из массивов" использован цикл по коллекции. Точнее, мы используем вложенные конструкции цикла for each.

    Во внешней конструкции foreach перебираются элементы массива symbs, которые, как отмечалось выше, сами являются массивами (переменными, ссылающимися на массивы). Локальная переменная q во внешней конструкции цикла указана с идентификатором типа char[]. Значение переменной q - это ссылка на массив. Поэтому переменная q обрабатывается как массив. Как массив она использована во внутренней конструкции цикла foreach. Там объявлена локальная переменная р типа char, и эта переменная последовательно принимает значения элементов массива q. Таким образом, если q является элементом массива symbs, то р - это элемент в массиве, на который ссылается элемент массива symbs. Значение этого элемента отображается командой

  Console.Write("{0,2}", р);           .
Первый 0 в инструкции {0,2} означает, что вместо нее подставляется значение первого аргумента после текстовой строки "{0,2}" (то есть значение переменной р), а число 2 в инструкции {0,2} означает, что для отображения значения выделяется не меньше двух позиций.

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

  int[][] nums = {new int[]{1,2,3}, new int[]{4,5}, new int[]{6,7,8,9}};
Переменная массива nums объявлена с идентификатором типа int[][]. Это означает, что nums может ссылаться на одномерный массив, элементы которого имеют тип int[] - то есть являются ссылками на целочисленные массивы. Значением переменной nums присваивается список. Список определяет массив, на который будет ссылаться переменная nums. В списке всего три элемента: В итоге получается, что переменная nums ссылается на массив, состоящий из трех элементов. Первый элемент nums[0] ссылается на целочисленный массив, состоящий из элементов со значениями 1, 2 и 3. Второй элемент nums[1] ссылается на целочисленный массив, состоящий из элементов со значениями 4 и 5. Третий элемент nums[2] ссылается на целочисленный массив, состоящий из элементов со значениями 6, 7, 8 и 9. Как так получилось? Нужно вспомнить, что элементы массива nums - ссылки на одномерные массивы. Но кроме самих ссылок, нужны еще и сами одномерные массивы. Эта "двойная" задача решается с помощью инструкций new int[]{1,2,3}, new int[]{4,5} и new int[]{6,7,8,9}. Например, что такое инструкция new int [] {1,2,3}? Это команда создания целочисленного массива с элементами 1, 2 и 3. То есть одна задача решается - создается одномерный целочисленный массив. У инструкции new int[]{1,2,3} есть значение - это ссылка на созданный массив. Аналогично с двумя другими инструкциями. Следовательно, получается, что в списке, присваиваемом переменной nums, три элемента, которые являются ссылками на одномерные массивы. Эти три значения определяют содержимое массива, на который будет ссылаться переменная nums.


При формировании списка инициализации для переменной массива nums мы не можем использовать список из списков, поскольку такой способ используется при создании двумерного массива, когда каждый внутренний список определяет строку в двумерном массиве. Именно поэтому перед списками, определяющими одномерные целочисленные массивы, использована инструкция new int[].

    Для отображения содержимого массива nums мы используем обычный цикл for (вложенные конструкции цикла). Во внешнем цикле индексная переменная i (с начальным нулевым значением) перебирает индексы элементов в массиве nums. Значение индексной переменной каждый раз увеличивается на единицу, а цикл выполняется, пока значение переменной меньше значения nums.Length (количество элементов в одномерном массиве nums). Во внутреннем цикле индексная переменная j перебирает элементы в массиве, на который ссылается элемент nums[i] массива nums. Количество элементов в массиве nums[i] дается выражением nums[i].Length. За каждую итерацию цикла выполняется команда

  Console.Write("{0,3}", nums[i][j]);      ,
которой в консольном окне отображается значение элемента nums[i][j], причем под отображаемое число выделяется не менее трех позиций (число 3 после запятой в инструкции {0,3}).

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




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