Скачиваний:
69
Добавлен:
24.03.2015
Размер:
262.66 Кб
Скачать

0 2

0 0 3

0 0 0 4

tre.Length = 4

tre.Rank = 1

В программе объявлена ссылка tre на массив массивов. Операцией new определён массив из size элементов - ссылок на массивы. Каждый элемент tre[j] – ссылка на ещё не существующий одномерный массив с элементами типа int. Эти массивы - реальные строки треугольной матрицы -формируются в цикле. Длина j-ro массива равна j+1.

В цикле печати массива для определения числа элементов используется свойство Length. Выражение tre.Length возвращает число строк матрицы. Обратите внимание, что в отличие от многомерного массива свойство Length равно числу элементов только "верхнего" уровня массива массивов. tri[j].Length позволяет определить длину j-й строки. Свойство Rank, относящееся к объекту типа int[][], равно 1, т.к. это одномерный массив ссылок на массивы. Остальное очевидно из результатов выполнения программы.

Вводя ссылку на массив и объявляя конкретный объект - экземпляр массива, программист каждый раз определяет некоторый тип именно таких массивов, которые ему нужны. Синтаксис объявления этих типов мы уже разобрали и объяснили с помощью примеров. Следует обратить внимание, что имена этих типов массивов и синтаксис определения типов массивов не похожи на те конструкции, которые применяются для определения пользовательских классов как таковых (вводимых с помощью служебного слова class). Однако каждый декларируемый в программе тип массивов является настоящим классом и создаётся как производный (как наследник) системного класса Array. Будучи наследником, каждый тип массивов получает или по-своему реализует методы и свойства класса Array. Следующая программа иллюстрирует возможности некоторых методов, о которых мы ещё не говорили.

// 07_07.cs массивы - методы и свойства класса Array

static void Main()

{

double[,] ar = {

{ 10, -7, 0, 7},

{ -3, 2.099, 6, 3.901},

{ 5, -1, 5, 6},

};

Console.WriteLine("ar.Rank = " + ar.Rank);

Console.WriteLine("ar.GetUpperBound(1) = " + ar.GetUpperBound(1));

Console.WriteLine("ar.GetLength(1) = " + ar.GetLength(1));

for (int i = 0; i < ar.GetLength(0); i++, Console.WriteLine())

for (int j = 0; j <= ar.GetUpperBound(1); j++)

Console.Write("\t"+ ar[i, j]);

}

Результат выполнения программы: ar.Rank = 2

ar.GetUpperBound(1) = 3 ar.GetLength(1) = 4 10 -7 0 7

3 2,099 6 3,901

5 -1 5 6

В программе определён и инициализирован двумерный массив с элементами типа double. Результаты выполнения программы поясняют особенности свойств и методов типа массивов, производного от класса Array. Обратите внимание, что GetUpperBound(1) - верхняя граница второго индекса, а не количество его значений.

7.5. Массивы массивов и поверхностное копирование

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

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

Метод Clone() позволяет создать новый экземпляр массива. В программе 07_04.cs показано, что изменяя один из одномерных массивов-копий мы не изменяем второй. Следующая программа иллюстрирует применение копирования к многомерному массиву:

// 07_08.cs - двумерный массив - полное клонирование

static void Main()

{

int size;

do

Console.Write("size = ");

while (!int.TryParse(Console.ReadLine(), out size) || size < 1);

int[,] one = new int[size, size];

Console.WriteLine("Maccив one:");

for (int i = 0; i < size; i++, Console.WriteLine())

for (int j = 0; j < size; j++)

{

if (i == j)

one[i, j] = 1;

Console.Write(one[i, j] + "\t");

}

Console.WriteLine("one. Length = " + one.Length);

int[,] two = (int[,])one.Clone(); // клонирование

two[0, 0] = -size;

Console.WriteLine("Maccив two:");

for (int i = 0; i < size; i++, Console.WriteLine())

for (int j = 0; j < size; j++)

Console.Write(two[i, j] + "\t");

Console.WriteLine("Maccив one:");

for (int i = 0; i < size; i++, Console.WriteLine())

for (int j = 0; j < size; j++)

Console.Write(one[i, j] + "\t");

}

Результат выполнения программы: size = 4<ENTER> Массив one:

1

0

0

0

0

1

0

0

0

0

1

0

0

0

0

1

one.

Length

= 16

Массив two

t

-4

0

0

0

0

1

0

0

0

0

1

0

0

0

0

1

Массив one

;

1

0

0

0

0

1

0

0

0

0

1

0

0

0

0

1

В программе определена ссылка two типа int[,] и ей присвоен результат копирования массива, связанного со ссылкой one, имеющей тот же тип int[,]. Выведена единичная матрица, адресованная ссылкой one, затем изменён обычным присваиванием один элемент массива-копии:

two[0,0]=-size;

Выведенные на консоль значения элементов массивов иллюстрируют независимость массива-оригинала от массива-копии.

Программы 07_04.cs и 07_08.cs работают с массивами, у которых по одному спецификатору размерности. В первом случае массив одномерный, во второй программе клонируется двумерный массив. Применяя метод Clone() к массиву массивов, мы сталкиваемся с очень важной особенностью. Строго говоря, действия метода остаются прежними - он создаёт массив-копию и присваивает его элементам значения элементов массива-оригинала. Однако в этом случае копирования тех подчинённых массивов, на которые "смотрят" ссылки-элементы массива-оригинала, не происходит. Выполняется так называемое поверхностное или поразрядное копирование. Иначе и быть не должно - "не знает" метод Clone(), что код, который является значением элемента массива, представляет собой ссылку и по этой ссылке нужно ещё что-то "доставать".

Таким образом, копируя с помощью метода Clone() массив массивов, мы получаем два экземпляра массива верхнего уровня, элементы которых адресуют одни и те же участки памяти, выделенные для подчинённых массивов объекта-оригинала.

В качестве иллюстрации указанной ситуации приведём следующую программу, построенную на основе 07_06.cs:

// 07_09.cs - непрямоугольный массив - клонирование поверхностное!

static void Main09()

{

int size;

do

Console.Write("size = ");

while (!int.TryParse(Console.ReadLine(), out size) || size<1);

int[][] tre = new int[size][];

for (int j = 0; j < size; j++)

{

tre[j] = new int[j + 1];

tre[j][j]=j + 1;

}

Console.WriteLine("Массив tre:");

for (int i = 0; i < tre.Length; i++, Console.WriteLine())

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

Console. Write(tre[i][j] + "\t");

Console.WriteLine("tre.Length = " + tre.Length);

int[][] two = (int[][])tre.Clone();

two[0][0] = - size;

Console.WriteLine("Массив two:");

for (int i = 0; i < two.Length; i++, Console.WriteLine())

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

Console.Write(two[i][j] + "\t");

Console.WriteLine("Массив tre:");

for (int i = 0; i < tre.Length; i++, Console.WriteLine())

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

Console.Write(tre[i][j] + "\t");

}

Результат выполнения программы:

size = 4<ENTER>

Массив tre:

1

0 2

0 0 3

0 0 0 4

tre.Length = 4

Массив two:

-4

0 2

0 0 3

0 0 0 4

Массив tre:

-4

0 2

0 0 3

0 0 0 4

В программе определена ссылка two типа int[][] и ей присвоен результат копирования (клонирования) "треугольного" массива, адресованного ссылкой tre, имеющей тип int[][]. С помощью оператора two[0][0] = - size; изменён один целочисленный элемент "нижнего уровня" массива массивов. После присваивания изменилось значение, соответствующее выражению tre[0][0].

14

Соседние файлы в папке Lekc_C#