Programming Taskbook 0


Download 1.62 Mb.
Pdf ko'rish
bet58/71
Sana21.06.2023
Hajmi1.62 Mb.
#1644761
TuriУчебное пособие
1   ...   54   55   56   57   58   59   60   61   ...   71
Bog'liq
Abramyan-Pascal2016-1


Глава 5. Дополнительные средства обработки массивов 
95 
переменной. Поскольку в нашем примере a и b описаны в разных операто-
рах описания, для них были сгенерированы разные внутренние типы 
(условно говоря, arr1_10_integer1 и arr1_10_integer2), которые не считаются 
эквивалентными и, в частности, не являются совместимыми по присваи-
ванию. Поэтому компилятор фактически сообщает, что он не может преоб-
разовать тип arr1_10_integer1 к arr1_10_integer2, но поскольку эти имена яв-
ляются внутренними и отсутствуют в программе, он заменяет их на текст 
исходных описаний (чем, возможно, только сбивает с толку неопытного 
программиста). 
Указанная особенность, связанная с эквивалентностью типов, приво-
дит к аналогичным проблемам при использовании статических массивов в 
качестве параметров подпрограмм (или возвращаемых значений функций). 
Поскольку мы в дальнейшем не собираемся работать со статическими мас-
сивами, мы не будем обсуждать детали этих проблем (см. по этому поводу 
[2, п. 13.7.1]). Упомянутые особенности и связанные с ними проблемы яв-
ляются добавочным аргументом в пользу того, чтобы отказаться от ис-
пользования статических массивов в программах на языке PascalABC.NET. 
С динамическими массивами ситуация совершенно иная. Для эквива-
лентности динамических массивов (и, следовательно, их совместимости по 
присваиванию) достаточно, чтобы они имели одинаковый тип элементов
Где и как они описаны в программе, не имеет никакого значения. Подоб-
ная эквивалентность называется структурной (в отличие от именной экви-
валентности статических массивов). Заметим, что структурная эквивалент-
ность в PascalABC.NET реализована также для множеств set of T [1, гл. 3] 
и процедурных типов (см. п. 1.3). 
Поскольку размер динамического массива при описании не указыва-
ется, он не влияет на совместимость массивов. Но при таком подходе по-
элементное копирование при присваивании теряет смысл. И действитель-
но, присваивание динамических массивов означает совсем другое: оно 
лишь изменяет ссылку, хранящуюся в изменяемой переменной-массиве. 
Приведем пример: 
var a := Arr(1, 2, 3); 
var b := Arr(6, 7); 
b := a; 
Поскольку в генераторах Arr для переменных a и b использованы па-
раметры одинакового типа (integer), эти переменные имеют одинаковый 
тип array of integer и поэтому совместимы по присваиванию. Подчеркнем, 
что с ними связываются массивы разного размера. Фактически в a хранит-
ся ссылка на массив с элементами 1, 2, 3, а в b хранится ссылка на массив с 
элементами 6 и 7. Присваивание вида b := a изменяет лишь ссылку, храня-
щуюся в переменной b. Это приводит к важным последствиям. Во-первых, 


96 
программа теряет связь с массивом, содержащим элементы 6, 7, поскольку 
эта связь обеспечивалась только за счет ссылки, хранящейся в b. Массив 
становится недоступным программе и в дальнейшем автоматически удаля-
ется из памяти специальной подсистемой платформы .NET — сборщиком 
мусора (garbage collector) [3, п. 8.1.2]. Во-вторых, доступ к массиву с эле-
ментами 1, 2, 3 теперь оказывается возможным и с помощью переменной а, 
и с помощью переменной b.
Дополним предыдущий фрагмент следующими операторами 
b[0] := 5; 
Write(a); // [5, 2, 3] 
Мы видим, что изменение элемента b[0] привело к тому, что одновре-
менно изменился и массив a (так как фактически у нас имеется единствен-
ный массив с двумя именами). 
Указанное обстоятельство необходимо учитывать при передаче дина-
мических массивов в качестве параметров подпрограмм. В частности, сле-
дует понимать, что и передача динамического массива по значению, и пе-
редача его по ссылке (с указанием модификатора var) будет, во-первых, 
выполняться одинаково быстро (так как передача по значению не будет 
приводить к поэлементному копированию) и, во-вторых, позволит изме-
нять элементы переданного массива (даже при передаче массива по значе-
нию, поскольку созданная в подпрограмме при такой передаче копия ссыл-
ки будет обращаться к тому же самому массиву). 
Как при подобном способе присваивания создать настоящую копию 
массива, которую в дальнейшем можно было бы обрабатывать независи-
мо? Для этого в PascalABC.NET предусмотрено несколько способов.
Простейшим является использование функции Copy(a) с единствен-
ным параметром — копируемым массивом. Эта функция создает и воз-
вращает копию данного массива (точнее, возвращается ссылка на создан-
ную в памяти копию). Пример: 
var a := Arr(1, 2, 3); 
var b := Arr(6, 7); 
b := Copy(a); 
b[0] := 5; 
Writeln(a); // [1, 2, 3] 
Writeln(b); // [5, 2, 3] 
Мы видим, что теперь изменение значения элемента массива b никак 
не повлияло на содержимое массива a. 
Заметим, что для получения копий массива или его частей можно ис-
пользовать срезы (см. п. 3.7), поскольку любой срез фактически является 
копией некоторой части массива. Например, в предыдущем фрагменте мы 


Download 1.62 Mb.

Do'stlaringiz bilan baham:
1   ...   54   55   56   57   58   59   60   61   ...   71




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling