| До сих пор мы имели дело с переменными, которые размещаются в памяти согласно определенным правилам, а именно, для локальных переменных, описанных в подпрограмме, память отводиться при вызове подпрограммы; при выходе из нее эта память освобождается, а сами переменные прекращают существование. |
| Глобальным переменным
программы память отводиться в начале ее выполнения; эти переменные существуют в течение всего периода работы программы. Распределение памяти во всех этих случаях производиться полностью автоматически. Переменные, память под которые распределяется описанным способом, называются статическими
. Под эту категорию попадают все переменные, описанные в Pascal - программе и обозначенные идентификаторами. |
| Помимо такой привычной схемы, Pascal дает возможность образовывать новые переменные в любой момент работы программы без учета ее статической структуры, сообразуясь с потребностями решаемой задачи. Точно так же допускается уничтожение созданных переменных в произвольный момент выполнения программы. (Имеется в виду отведение памяти для хранения переменной и, соответственно, освобождение отведенной ранее памяти). Переменные, созданием и уничтожением которых может явно управлять программист, называются динамическими
переменными. |
| Необходимость в динамических структурах данных обычно возникает в следующих случаях
: |
| 1. Используются переменные, имеющие довольно большой размер (например, массивы большой размерности), необходимые в одних частях программы и совершенно не нужные в других. |
| 2. В процессе работы программы нежен массив или список или иная структура, размер которой изменяется в пределах и трудно предсказуем. |
| 3. Когда размер данных, обрабатываемых в программе, превышает 64К (сегмент данных). |
| Динамические переменные размещаются в динамической памяти, размер которой можно варьировать в широких пределах. По умолчанию этот размер определяется всей доступной памятью (оперативной) ПК. |
| Естественным средством доступа к статическим переменным являются идентификаторы этих переменных (так как статическая переменная всегда описана в некотором блоке). |
| Динамические переменные, количество которых и место расположения в памяти заранее не чувственно, невозможно обозначить идентификаторами. Поэтому единственным способом доступа к динамическим переменным является указатель на место их текущего расположения в памяти. |
| На принципе обращения к динамическим переменным посредством указателей (ссылок) на них и основаны все соответствующие средства языка Pascal. |
 |
 |
| В ТР можно объявить указатель и не связывать его при этом с каким-либо конкретным типом данных. Для этого служит стандартный тип POINTER: |
| Var |
| PP:pointer; |
| Указатели такого вида называются не типизированными. Они совместимы со всеми прочими ссылочными типами. |
| Так как нетипизированные указатели не связаны с конкретным типом, с их помощью удобно размещать данные, структура и тип которых меняются в ходе работы программы. |
| Адреса задаются сегментом и смещением. |
| Сегмент - участок памяти, имеющий длину 64К и начинающийся с физического адреса кратного 16 (0, 16, 32, 64…) |
| Смещение - указывает, сколько байт от начала сегмента необходимо пропустить, чтобы обратиться к нужному адресу. |
| Фрагмент памяти в 16 байт называется параграфом. |
| Все ссылочные переменные имеют одинаковый размер, равный 4 байтам, и содержат адрес расположения в памяти конкретных значений переменных базового типа. |
| Для того, чтобы присвоить переменной ссылочного типа некоторое значение, необходимо воспользоваться унарной операцией взятия адреса объекта, которая обозначается знаком '@' (амперсант). |
| Например: |
 |
| В ТР можно передавать значения только между указателями, связанными с одним и тем же типом данных. Это ограничение не распространяется на безтиповые указатели. |
| Операция взятия адреса допустима для любых переменных, в том числе для элементов массивов, полей записей и так далее. |
| Например: |
 |
| Для того, чтобы указатель "никуда не указывал", ему присваивается значение NIL: |
| P1:=NIL; |
| NIL - предопределенная константа типа Pointer, соответствующая адресу 0000:0000. Это значение можно присваивать любому указателю. |
| Над значениями ссылочных типов допускаются две операции сравнения на равенство '=' и неравенство '<>'. |
| Эти операции проверяют, ссылаются ли два указателя на одно и то же место в памяти. |
| If P3<>NIL then … |
| If P1=P2 then … |
| Для доступа к переменной (статической) имеются две возможности: |
| Одна - обращение к переменной по имени, то есть через идентификатор; |
| Вторая - воспользоваться адресом переменной, который содержится в указателе. |
| Например: |
| I:=I+2; |
| P1:=@I; |
| Для реализации второго, косвенного доступа к переменной через указатель на нее используется конструкция, называемая разыменованием. |
| Для того, чтобы по указателю не переменную получить доступ к самой этой переменной, необходимо после переменной - указателя поставить знак '^'. |
| Запись P1^ означает, "переменная, на которую ссылается P1". |
| Еще раз: |
| - Значением любого указателя является адрес, по которому размещены данные; |
| - А чтобы указать, что речь идет не об адресе, а о самих данных, за указателем ставится значок '^'. |
| Такая конструкция может находиться в любом контексте, в котором допустимо, вхождение самой указуемой переменной. То есть в нашем случае операторы: |
| I:=I+2; и P1^:=P1^+2; полностью эквивалентны. |
| Разыменование имеет тип, совпадающий с базовым типом переменной - указателя; то есть конструкция P1^ считается переменной целого типа. |
 |
| Разыменование допускается для любых ссылочных типов. |
| В случае "указателя на указатель" возможно многократное разыменование. |
| Например: |
 |
| Считается разыменование некорректным, если значение указателя равно NIL. |
| В этом случае нет переменной, на которую ссылается указатель. |
| Недопустимо: |
| P1:=NIL; |
| P1^:=2; |