Шаг 68.
Язык программирования C#. Начала
Статические методы. Массив как результат метода

    На этом шаге мы рассмотрим механизмы возврата массива из метода.

    Метод может возвращать результатом массив. Точнее, метод может возвращать ссылку на массив. Обычно схема такая: при вызове метода создается массив, а результатом метод возвращает ссылку на него. Как уже отмечалось, переменные, которые создаются при вызове метода, существуют, пока метод выполняется, а после завершения метода они удаляются из памяти. В принципе, массив, который создан при вызове метода, также является "кандидатом на удаление". Но если ссылка на массив возвращается методом как результат и присваивается в качестве значения, например, какой-то переменной, то эта переменная (объявленная до вызова метода) будет ссылаться на массив. Такой массив не будет удален из памяти даже после завершения выполнения метода.


В языке C# существует система автоматического сбора мусора. Если в памяти есть объект или массив, на который не ссылается ни одна переменная в программе, такой объект/массив будет из памяти удален системой сборки мусора. Так, если при вызове метода создается массив и ссылка на него записывается в локальную переменную, но как результат этот массив (ссылка на него) не возвращается, то после выполнения метода локальная переменная из памяти удаляется. Следовательно, на созданный массив не будет ссылок, и он удаляется системой сборки мусора. Но если ссылка на массив возвращается результатом метода и записывается во внешнюю (для метода) переменную, то после завершения работы метода на созданный массив в программе будет ссылка. Поэтому массив не удаляется из памяти.

    Если метод возвращает результатом ссылку на массив, то тип результата метода указывается точно так же, как он указывается для переменной массива того же типа. Например, если метод возвращает результатом ссылку на одномерный целочисленный массив, то идентификатор типа для такого метода выглядит как int[]. Если метод возвращает результатом ссылку на двумерный символьный массив, то идентификатор типа результата метода имеет вид char[,].

    Ниже представлена программа, где описано несколько статических методов, возвращающих в качестве результата массив.

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

namespace pr68_1
{
    class Program
    {
        // Метод для создания массива с числами Фибоначчи: 
        static int[] fibs(int n){
            // Создается массив: 
            int[] nums = new int [n];
            // Первый элемент массива: 
            nums[0] = 1;
            // Если массив из одного элемента: 
            if ( nums.Length == 1 ) return nums;
            // Второй элемент массива: 
            nums[1] = 1;
            // Заполнение элементов массива: 
            for (int k=2; k < nums.Length; k++){
                // Значение элемента массива равно сумме значений 
                // двух предыдущих элементов: 
                nums[k] = nums[k-1] + nums[k-2];
            }
            // Результат метода - ссылка на массив: 
            return nums;
        }

        // Метод для создания массива со случайными символами: 
        static char[] rands(int n){
            // Объект для генерирования случайных чисел:
            Random rnd = new Random();
            // Создание массива: 
            char[] symbs = new char [n];
            // Заполнение массива: 
            for(int k=0; k < symbs.Length; k++){
                // Значение элемента - случайный символ: 
                symbs[k] = (char)('A' + rnd.Next(26));
            }
            // Результат метода - ссылка на массив: 
            return symbs;
        }

        // Метод для создания двумерного массива с нечетными 
        // числами:
        static int[,] odds(int m, int n) {
            // Создание двумерного массива: 
            int[,] nums = new int[m, n];
            // Локальная переменная: 
            int val = 1;
            // Перебор строк массива:
            for (int i=0; i < nums.GetLength(0); i++){
                // Перебор элементов в строке:
                for(int j=0; j < nums.GetLength(1); j++){
                    // Значение элемента: 
                    nums[i, j] = val;
                    // Значение для следующего элемента: 
                    val += 2;
                }
            }
            // Результат метода - ссылка на массив: 
            return nums;
        }

        // Главный метод программы: 
        static void Main()
        {
            // Переменная для целочисленного массива: 
            int[] A;
            // Переменная для символьного массива:
            char[] B;
            // Переменная для двумерного массива: 
            int[,] C;
            // Создается массив с числами Фибоначчи:
            A = fibs(10);
            Console.WriteLine("Числа Фибоначчи:");
            // Отображение содержимого массива: 
            foreach (int s in A){
                Console.Write("| {0} ", s);
            }
            Console.WriteLine("|");
            // Создается массив со случайными символами: 
            B = rands(8);
            Console.WriteLine("Случайные символы:");
            // Отображение содержимого массива: 
            foreach (char s in B){
                Console.Write("| {0} ", s);
            }
            Console.WriteLine("|");
            // Создается двумерный массив с нечетными числами: 
            C = odds(4, 6);
            Console.WriteLine("Двумерный массив:");
            // Отображение содержимого двумерного массива: 
            for(int i=0; i < C.GetLength(0); i++) {
                for(int j=0; j < C.GetLength(1); j++) {
                    Console.Write("{0, 4}", C[i, j]);
                }
                Console.WriteLine();
            }
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


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

    В программе описывается три статических метода. Каждый из них возвращает результатом ссылку на массив. Метод fibs() создает одномерный целочисленный массив, заполняет его числами Фибоначчи, а результатом возвращает ссылку на этот массив.


Последовательность Фибоначчи формируется так: первые два числа в последовательности равны 1, а каждое следующее число - это сумма двух предыдущих. То есть речь идет о последовательности чисел 1, 1, 2, 3, 5, 8, 13, 21 и так далее.

    Аргументом методу передается целое число, определяющее размер массива. Идентификатором типа результата указана инструкция int[]. В теле метода командой

  int[] nums = new int[n]; 
создается одномерный целочисленный массив. Размер массива определяется аргументом n, переданным методу. Командой
  nums[0] = 1; 
первому (начальному) элементу массива присваивается единичное значение. Затем выполняется условная конструкция. В ней проверяется условие nums.Length == l, истинное в случае, если массив состоит всего из одного элемента. Если так, то получается, что массив уже заполнен (на предыдущем этапе единственному элементу массива было присвоено единичное значение). Поэтому командой
  return nums; 
завершается выполнение метода, а результатом возвращается ссылка на созданный массив (напомним, что выполнение инструкции return в теле метода приводит к завершению выполнения метода). Если же условие в условном операторе ложно, то командой
  nums[1] = 1;
единичное значение присваивается и второму (но порядку) элементу массива.


Получается так, что нам нужно явно присвоить первым двум элементам массива единичные значения. Но у нас нет гарантии, что второй элемент в массиве существует. Поэтому после присваивания значения первому элементу выполняется проверка на предмет того, равен ли размер массива единице. Если это так, то с помощью return-инструкции выполнение метода завершается. Если выполнение метода не завершилось (размер массива не равен единице), то присваивается значение второму элементу.

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

  nums[k] = nums[k - 1] + nums[k - 2]; 
значение элемента массива вычисляется как сумма значений двух предыдущих элементов. По завершении цикла, когда массив заполнен, командой
  return nums;
ссылка на массив возвращается результатом метода.


Если окажется, что массив состоит всего из двух элементов, то при первой проверке условия k < nums.Length в конструкции цикла с учетом того, что начальное значение переменной k равно 2, условие окажется ложным. Поэтому команды в теле цикла выполняться не будут.

    Метод rands() предназначен для создания одномерного массива, заполненного случайными символами. Результат массива имеет тип char[] (ссылка на символьный массив), а аргументом методу передается целое число, определяющее размер массива. В теле метода создается объект rnd класса Random для генерации случайных чисел: команда

  Random rnd = new Random();     . 

    Командой

  char[] symbs = new char[n]; 
создается символьный массив. После этого запускается цикл, в котором индексная переменная k перебирает значения индексов элементов созданного массива. За каждый цикл командой
  symbs[k] = (char)('A' + rnd.Next(26));
элементу массива присваивается случайное символьное значение. После заполнения массива командой
  return symbs; 
ссылка на пего возвращается результатом метода.


Значением выражения rnd.Next(26) является случайное целое число в диапазоне от 0 до 25 включительно. Выражение 'A'+rnd.Next(26) вычисляется так: к коду 65 символа 'А' прибавляется значение выражения rnd.Next(26). Получается какое-то (случайное) целое число в диапазоне значений от 65 до 90. После явного приведения к символьному типу (инструкция (char) перед выражением 'A'+rnd.Next(26)) получаем символ с соответствующим кодом.

    Метод odds() создает двумерный целочисленный массив, заполняет его нечетными числами и возвращает ссылку на этот массив. У метода два целочисленных аргумента, которые определяют количество строк и столбцов в двумерном массиве. Идентификатор типа результата имеет вид int[,] (ссылка на двумерный целочисленный массив).

    В теле метода двумерный массив создается командой

  int[,] nums = new int [m, n];   . 
Для заполнения массива использованы вложенные конструкции цикла. При заданных индексах i и j значение элемента массива вычисляется командой
  nums[i, j] = val;  . 
После этого командой
  val += 2; 
текущее значение переменной val увеличивается на 2. Поэтому значение следующего элемента будет на 2 больше. Начальное значение переменной val равно 1. В итоге элементы массива заполняются числами, начиная со значения 1, и каждое следующее значение больше предыдущего на 2. А это последовательность нечетных чисел. После заполнения массива ссылка на него возвращается результатом метода.


Желающие могут подумать, как следует изменить программный код, чтобы массив заполнялся четными числами или, например, числами, которые кратны 5 (то есть 5,10,15, 20 и так далее).

    В главном методе программы объявляется несколько переменных массива:

Сами массивы не создаются. Точнее, они создаются при вызове статических методов, описанных в программе. При выполнении команды
  A = fibs(10);
создается массив из 10 (аргумент метода fibs()) чисел Фибоначчи, и ссылка на массив записывается в переменную А. Командой
  B = rands(8);
создается массив из 8 (аргумент метода rands()) случайных символов, и ссылка на этот массив записывается в переменную В. Наконец, командой
  C = odds(4, 6); 
создается двумерный массив из 4 строк и 6 столбцов (аргументы метода odds()), и ссылка на массив записывается в переменную С. Массив заполнен нечетными числами. Также в главном методе есть команды (конструкции цикла), предназначенные для отображения содержимого созданных массивов. Они уже должны быть понятны, поэтому особых комментариев не требуют.


Допустим, имеется два метода. Один метод, аргументом которому передается ссылка на целочисленный массив, при вызове заполняет этот массив случайными числами. Другой метод, аргументом которому передается целое число (размер создаваемого массива), возвращает ссылку на целочисленный массив, заполненный случайными числами. В чем между ними принципиальная разница? В первом случае мы сами создаем массив и ссылку на него передаем методу. Во втором случае массив создается при вызове метода.

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




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