К. Йенсен, Н. Вирт - Паскаль - Руководство для пользователя (1109480), страница 14
Текст из файла (страница 14)
При символах множества АБС11 для этого применяют два символа: сг (возврат каретки) и И (перевод строки). Однако в некоторых системах используется множество символов, где таких символов нет. В этом случае для маркировки конца строк нужно воспользоваться другими приемами. ССЫЛОЧНЫЕ ТИПЫ Ранее речь шла а типах, предназначенных для описания статически размещенных переменных. Статической' переломной называется переменная, описанная в программе и обозначаемая с помощью имени. Статической ее называют из-за того, что она существует, т. е. под иее выделена память на протяжении всего выполнения блока (программы, процсдурь1 или функции), где оиа локализована.
Однако переменные можно создавать и уничтожать динамически в процессе выполнения блока (без какой-либо связи со статической структурой программы). Такие переменные в дальнейшем будут называться динамическими, или иденгигрицировиинььии, переменными. ~О.Е ССЫЛОЧНЫЕ Г1Е РМЕННЫЕ и 'идентич ицировАнные (ДИНАМИЧЕСКИЕ) ПЕРЕМЕННЫЕ Идентифицированная (динамнческая) переменная не указывается в описаниях переменных и ее нельзя обозначать с помощью имени.
Вместо этого они порождаются н уничтожаютси с помощью предописанных процедур Йети и О)зрозс, а идентифицируются опн через ссылочиые значения (представляюшие собой нс что иное, как адрес места в памяти, где находится вновь созданная переменная). Ссылочиое значение должно быть присвоено уже сушествуюшей ссылочиой переменной, относящейся ксвответствуюьцему ссылочному типу. Р и с. 10Л.
Сиитаисичесиая диаграмма дая Сооыоеиого сила '! Описание ссылочного типа Р издает Т вЂ” тип области: 1уре Р = (Т; Множество ссылочиых значеннй типа Р представляет собой нс- !64 Руководство длл пользователя ограниченное число идентифицирующих значений, каждое из которых идентифицирует переменную типа Т, сюда же входит и специальное значение и!1, не идентифицирующее никакую переменную. Доступ к идентифицированной (динамической) переменной идет через идентифицирующее ее ссылочное значение. Если, например, переменная Р1г была описана так: чаг Р1г: Р; и сй было присвоено некоторое идентифицирующее значение, то конструкция Р1гТ обозначает идентифицированную переменную.
Пеоеменная Р и с. !Олк Сивтаксическая диаграмма для Идентификированной переменной Если Р1г равна и!! или не определена, то обращение Р111 — ошибочно. Для поро!кдения или размещения идентифицированной переменной типа Т и присваивания идентифицирующего ес значения переменной Р1г используйте )ч(евг(Р1г). А для уничтожения переменной, идентифицированной значением Р1г, применяйте Т)!зрозе(Р(г), после обращения к В!зрозе значение Р1г становится неопределенным.
Ссылки являются простым механизмом, позволяющим строить данные со сложной и меняющейся (и дажс рекурсивной) структурой. Если тип Т определяет записи с одним или несколькими полями типа Р, то с их помощью можно строить структуры, эквивалентные произвольному конечному графу, причем идентифицированные переменные будут представлять вершины, а ссылки— ребра. Программа !О.! иллюстрирует, как с помощью ссылок можно моделировать очередь клиентов. (Процедуры рассматриваются в следующей главе.) ргезгав Иа!1! пзг! ас!!прас,Опера!); Программа 10.1 — моделирование очереди кпиеитоюо бову!киваю!си первые 3. ! сапа! Иааегепйсв = 15; туре заве!прел = ) ..Иавегепзсп; 10.
Ссылочиые чипы !05 йавеЗЬг!пй= распеб аггау [Иаве1пбех] о! Спаг; Иаеога! = О..Иах1пь; С1!епсро!пьег = ТС1ьепс; С1!епс = гесогб Паве: йавеЗЬг!пй; йхЬ: С1!еп!Ро1псег епб; чаг Неаб, Та!1: С1!епСРо1псег; Паве: расаеб аггау [Паве1пбех] о! СЬаг ргосебчге Оеабйаве; чаг с: йаве1пбех; Ьей!и !ог с := 1 Ьо йаве[епй(Ь бо ТТ Ео!п(!про!) Ьоеп Паве[с) := ' е1ье Ьейьп йеаб(1проь,Паве[с]); Нг!Ье(Оп!рос,Паве[с]) епб; йеаб1п(!про!); Нг!Се1п(Оп!рос) епб [ йеабйаве ); ргосебоге АббС1!ее![о[!ьь; чаг ИеиС1!епс: С1!епсро1псег; ЬеО!и Пеи(йеиС11епс); !! Неаб = пь! Ьпеп Неаб := ПеиС1!епс е1ье Та!11.Их!:= ИеиС11епс; йеиС1ьепс!.Паве := Паве; ИеиС11еп$1.Их! := п11; Та!1:= йеиС11епь епб [ АООС1!епСТо[!ьс ); ргосебоге ЗегчеС1!епс(НоиИапу: йаьога1); чаг С(ьепс[оЗегче: С1!епьРо!псег; Ьей!и ип! !е (НоиМапу > О) апб (Неаб «г п(1) бо Ьей!и С11епьТоЗегне := Неаб; Неаб := Неаб 1.йхь; Нг!Се!п(С1!епьуоЗегче(.Паве); О1ьроье(С1ьепСТоЗегче); НоиИапу:= НоиМапу — 1 епб епб [ ЗегчеС(ьепсь ); Ьей1п [ На!с!ой(!ьс ) 106 Рркоеодстао для пользователя Неап:= п)1; иуи1е пос Во)1!прес) ео Ьей)п Веаейаве; А66011ООФТОФ!51 епе; Нг)ФО!п(ООФрЬФ) БегчеС1)ептз(3) епе [ На1ыпймас ) Дает в качестве результатов: Н)Н)ФО Ва1азоЬгавапуав Найе1 Фесагве Ве11о РОНготзау Ваггоп Уаеп За1е Рг)се Н1Н1са Ва1аавЬгававуав Варе! В качестве другого примера рассмотрим вбанк данных», включающий определенную группу лнц.
Предположим, каждый человек представляется такой записью, которая была уже определена в гл. 7. Если добавить в нее поле ссылочного типа, то нз таких записей можно формировать цепочки или связные списки и использовать их для поиска и включения информации: Фуре 11пх 1Регаоп; Регаоп = гесог6 ИехФ: 1)пК; еп6; Связный список из и лнц можно представить так, как показано на рис.
)О.З.. Каждый квадрат соответствует одному человеку: Г!гтт Р и с. 10.3. Связный список 10 Сои»о«ни« сипи 107 Переменная типа 1лпк с именем Г(гз( указывает на первого человека из этого списка. Поле же Иех1 у «последнего человека» имеет значение и!1. Заметим, что обозначение Е(гз11. Мех(1Лех1 указаавает иа третьего человека в списке.
Если допустить, например, что мы можем читать целые данные, относящиеся к росту человека, то с помощью приведенного ниже фрагмента программы можно построить упомянутую цепочку. хаг Е(г«1, Р: ((пх; Н, 1: 1пеейег; Е1г»Ь:= п11 1ог 1:= 1 Ьо й ао Ьей(п йеао(Н); йек(Р); Р).йехЬ : Е(г»Ь; Р(.Не1аЬЬ := Н; 1п(Ь(а1(геОЬЬегЕ(е)аа(РТ): Е1гаЬ := Р еоо Обратите внимание, что список растет в обратном направлении. Для обращения к элементам мы введем еще одну переменную, скажем Р1 типа Ыпй, которая будет свободно перемещаться по списку. Чтобы показать, как происходит поиск, представим себе, что есть информация о человеке с НещЫ, равным 175, и нам нужно получить доступ к ней.
В этом случае будем двигать Р1 «вдоль» Кех1 до тех пор, пока не обнаружим желаемое. РФ := Е1г»Ь; иЬ(1е РЬ 1.Не 1НЬЬ.<> 175 ао РЬ := РЬ 1.йехЬ Словами это можно выразить следуюгцим образом: «Сначала Р1 указывает на первого человека. До тех пор пока рост (Не(дй) человека, на которого указывает Р1, не будет равен 175, будем присваивать Р1 значение ссылки, находящееся в поле Иех1 (это опять же ссылка) записи, на которую в данный момент указываег Р1». Такая простая процедура поиска будет работать только в том случае, если есть уверенность, что найдется по крайней мере один человек с Не(дИ, равным 175. Но разве это реальное предположенией Поэтому для правильной работы нужно было бы еще и опознавать конец списка.
Сначала это можно попытаться сделать так: РЬ := Е(г»1; ио(1е (РЬ <> п(1) апд (Р$1.Н«(еЬЬ <> 115) до РЬ .= РЬ1.йехЬ 708 Рркоеодстео длл пользователя Вспомним, однако, о чем говорилось в равд. 4.1. Если Р1 = п(1, то переменная, на которую ссылаются во втором терме условия окончания, вообще не существует, это ошибка! Поэтому в данной ситуации можно выбрать любое из двух таких решений — и то и другое в этой ситуации работают правильно.
[1! РС:= Е)гзС; В:= ггщ, иЫ 1е (РС <> п!1) зпо' В бо !1 РС(.Не(ВЬС = 175 СЬеп В:= (а1зе е!зе РС .= РС1.йехС (2) РС:= Г(гзС; ыйт!е РС <> п)1 бо Ьеа1п 1( РС1.НехВЬС = 175 СЬеп ВоСо 13; РС := РСТ.НехС епб; 13: ° 103Ь ФУНКЦИИ !чЕ% и О!БРОВЕ Возьмем другую задачу: скажем, необходимо добавить в банк данных еще одно лицо. Для этого сначала с помощью предописанной процедуры Ыецг нужно выделить для переменной место и получить идентифицирующее ее значение: Ыетн (Р) процсдура равмещает попую идентифицироианную (динамическую! псрсмсннукг Р), отгнюнщуюся кобласти тина зля 1*, и порож,нн нппос илшппфнця. руюцгсс ссылочцсс зна щи не, оюнгсищссги к тому жс типу, что н Р, и ирнсаанааст его Р Если Р1— запись с нарна игами, то Ыем(Р) иыделяет место, достаточное для размещения любых нариантоа размещает новую ндентифицнроианную (динамическую) переменную Р1, относящуюся к вариантному записному тяпу для Р, со значениями полей нрпзнзкоп С1,..., Сп дли и пложспных парпантоя,п порождает понос ндентифицируюгпсс ссылочпос значение, относящееся к тому жс типу, что и Р, и присааиаает его Р Ыетт(Р, С1., Сп) Осторожно, если переменная-запись была порождена с помощью обращения к )х)ецг второго типа, то во время выполнения программы нельзя переходить от одного варианта к другим.
Присваивание всей целиком переменной считается ошибкой, хотя присваивания отдельным компонентам допускаются. Ы Ссылочные типы !0Э Начиная решать поставленную задачу, введем сначала ссылочную переменную; назовем ее ХстчР. В этом случае оператор !чеъ'()ч!етпР) разместит в памяти новую переменную типа Регзоп.
Затем новую переменную, на которую указывает ссылка )ч)етпР, нужно включить в список после элемента, на который ссылается Р1 (рис. 10.4). Р и с. 104. Связный список перед включением Включение проводится просто путем изменения ссылок. ИенР!.Иехй:= Р1! Иене; РЕ!.вехе:= ИеиР Результат показан на рис. 10.5. Включить вече Р и с. !0.5. Связный список после включения Исключение элемента, следуюшего за тем, на который указывает вспомогательная переменная Р1, проводится в одно действие: Р11.Мех1:= Р11.Иех11.14ех1 )!д Руководство дли пользователя При работе со списками часто бывает удобно пользоваться двумя ссылками, «смотряшими на соседние элементы».
При исключении, например, хорошо, когда одна ссылка, скажем Р1, указывает на элемент, предшествующий исключаемому, а вторая — Р2-— на сам исключаемый. В этом случае исключение проводится за одно действие: Р!!.)х)ех(:= Р2(.)х)ех! Однако существует опасность, что при таком исключении мы будем проигрывать в памяти (которую можно было бы еше использовать). Возможно в этом случае следует организовывать явный список «исключенных» элементов, на который указываст переменная Ггее.
Тогда новые элементы можно брать из этого списка (если он не пуст), а не обращаться к процедуре )х)еш. При такой системе исключение из списка превращается в передачу элемента из исходного списка в список свободных элементов. Р!1.Иехт:= Р21.Иехт; Р21.Иех! := Ггее; атее := Р2 убирает идентнфипированную переменную се) и уничтожает идентифипирующее значение (). Если () имело значение и)! или было нс определено, то — ошибка. Значение () должно было быть порождено с помощью обращения к )Чеи первого вида убирает ддентифипированную вариантную переменную-запись (2)с активаыми вариантами,селектированными значениями К), ..., Кп. Соогвет ствующее идентифицирующее значение (2 уничтожается. Если Я имело значение пи или было не определено, то ошибка.
Значение СЭ должно было быть порождено с помощью обращения к )Чем второго типа, а К), ..., Кп должны иметь те же значения (выбирать те же варианты), что и при порождении ))1зрозс(тс) (пароле Я К! ..., Кп) В гл. 11 приводятся две программы (программы 1!.6 и 11 7), демонстрирующие обход древовидных образований, построенных с помощью ссылочных типов. И последнее, если воспользоваться предописанной процедурой Э(зрозе, то работу с исключаемыми элементами можно возложить на реализацию Паскаля.