Чтение онлайн

ЖАНРЫ

Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:

• Массив х объявлен с явной инициализацией. Число и значения его элементов определяется константным массивом.

• Массивы u и v объявлены с отложенной инициализацией. В последующих операторах массив и инициализируется в объектном стиле — элементы получают его в цикле значения.

• Обратите внимание на закомментированный оператор присваивания. В отличие от инициализации, использовать константный массив в правой части оператора присваивания недопустимо. Эта попытка приводит к ошибке, поскольку v — это ссылка, которой можно присвоить ссылку, но нельзя присвоить константный

массив. Ссылку присвоить можно. Что происходит в операторе присваивания v = u? Это корректное ссылочное присваивание: хотя u и v имеют разное число элементов, но они являются объектами одного класса. В результате присваивания память, отведенная массиву v, освободится, ею займется теперь сборщик мусора. Обе ссылки u и v будут теперь указывать на один и тот же массив, так что изменение элемента одного массива немедленно отразится на другом массиве.

• Далее определяется двумерный массив w и делается попытка выполнить оператор присваивания v=w. Это ссылочное присваивание некорректно, поскольку объекты w и v — разных классов и для них не выполняется требуемое для присваивания согласование по типу.

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

public static void CreateOneDimAr (int [] A)

{

for(int i = 0; i<A.GetLength(0);i++)

A[i] = rnd.Next(1,100);

}//CreateOneDimAr

Здесь rnd — это статическое поле класса Arrs, объявленное следующим образом:

private static Random rnd = new Random;

Процедура печати массива с именем name выглядит так:

public static void PrintArl(string name,int[] A)

{

Console.WriteLine(name);

for (int i = 0; i<A.GetLength(0);i + +)

Console.Write("\t" + name + "[{0}]={1}", i, A[i]);

Console.WriteLine;

}//PrintArl

На рис. 11.1 показан консольный вывод результатов работы процедуры TestDeciarations.

Рис. 11.1. Результаты объявления и создания массивов

Особое внимание обратите на вывод, связанный с массивами u и v.

Динамические массивы

Во всех вышеприведенных примерах объявлялись статические массивы, поскольку нижняя граница равна нулю по определению, а верхняя всегда задавалась в этих примерах константой. Напомню, что в C# все массивы, независимо оттого, каким выражением описывается граница, рассматриваются как динамические, и память для них распределяется в "куче". Полагаю, что это отражение разумной точки зрения: ведь статические массивы, скорее исключение, а правилом является использование динамических массивов. В действительности реальные потребности в размере массива, скорее всего, выясняются в процессе работы в диалоге с пользователем.

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

индексов, в динамическом случае содержит переменные. Единственное требование — значения переменных должны быть определены в момент объявления. Это ограничение в C# выполняется автоматически, поскольку хорошо известно, сколь требовательно C# контролирует инициализацию переменных.

Приведу пример, в котором описана работа с динамическим массивом.

public void TestDynAr

{

//объявление динамического массива А1

Console.WriteLine("Введите число элементов массива А1");

int size = int.Parse(Console.ReadLine);

int[] A1 = new int[size];

Arrs.CreateOneDimAr(A1);

Arrs.PrintAr1("A1",A1);

}//TestDynAr

В особых комментариях эта процедура не нуждается. Здесь верхняя граница массива определяется пользователем.

Многомерные массивы

Уже объяснялось, что разделение массивов на одномерные и многомерные носит исторический характер. Никакой принципиальной разницы между ними нет. Одномерные массивы — это частный случай многомерных. Можно говорить и по-другому: многомерные массивы являются естественным обобщением одномерных. Одномерные массивы позволяют задавать такие математические структуры как векторы, двумерные — матрицы, трехмерные — кубы данных, массивы большей размерности — многомерные кубы данных. Замечу, что при работе с базами данных многомерные кубы, так называемые кубы OLAP, встречаются сплошь и рядом.

В чем особенность объявления многомерного массива? Как в типе указать размерность массива? Это делается достаточно просто, за счет использования запятых. Вот как выглядит объявление многомерного массива в общем случае:

<тип>[, …,] <объявители>;

Число запятых, увеличенное на единицу, и задает размерность массива. Что касается объявителей, то все, что сказано для одномерных массивов, справедливо и для многомерных. Можно лишь отметить, что хотя явная инициализация с использованием многомерных константных массивов возможна, но применяется редко из-за громоздкости такой структуры. Проще инициализацию реализовать программно, но иногда она все же применяется. Вот пример:

public void TestMultiArr

{

int[,]matrix = {{1,2}, {3,4} };

Arrs.PrintAr2("matrix", matrix);

}//TestMultiArr

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

public void TestMultiMatr

{

int n1, m1, n2, m2,n3, m3;

Arrs.GetSizes("MatrA",out n1,out m1);

Arrs.GetSizes("MatrB",out n2,out m2);

Arrs.GetSizes("MatrC",out n3,out m3);

int[,]MatrA = new int[n1,m1], MatrB = new int[n2,m2];

int[,]MatrC = new int[n3,m3];

Arrs.CreateTwoDimAr(MatrA);Arrs.CreateTwoDimAr(MatrB);

Arrs.MultMatr(MatrA, MatrB, MatrC);

Arrs.PrintAr2("MatrA",MatrA); Arrs.PrintAr2("MatrB",MatrB);

Arrs.PrintAr2("MatrC", MatrC);

}//TestMultiMatr

Три матрицы — MatrA, MatrB и MatrC — имеют произвольные размеры, выясняемые в диалоге с пользователем, и использование для их описания динамических массивов представляется совершенно естественным. Метод CreateTwoDimAr заполняет случайными числами элементы матрицы, переданной ему в качестве аргумента, метод PrintAr2 выводит матрицу на печать. Я не буду приводить их код, похожий на код их одномерных аналогов.

Поделиться с друзьями: