В процессе компиляции исходной программы все имена переменных преобразуются в адреса ячеек памяти, в которых размещаются соответствующие значения данных. В командах машинной программы при этом стоят машинные адреса размещения переменных. Это прямая адресация: вызов значения по адресу в команде. Например, по оператору присваивания k:=j; на машинном уровне происходит копирование значения из области ОП, отведённой переменной j, в область ОП, отведённую переменной k. Таким образом, при выполнении машинной программы реализуются операции над операндами – значениями переменных, расположенными по определенным адресам ОП. Имена переменных на машинном уровне не применяются, а только адреса, сформированные транслятором с использованием имен переменных. Но программист не имеет доступа к этим адресам, не используя указатели.
Определение Указатель (reference, ссылка) – это переменная или константа стандартного типа для хранения адреса оперативной памяти. Адресуемый тип может быть любым стандартным или пользовательским, простым или сложным.
Переменная типа указатель занимает в ОП двойное слово (4 байта). Старшее слово содержит адрес размещения сегмента, а младшее - адрес смещения в сегменте. Указатель может быть типовым или бестиповым. Если указатель адресует определённый тип данных, он называется типовым. Бестиповой указатель может адресовать различные типы данных.
Форма объявления типа указатель:
имя_типа_указатель = ^имя_типа;
где имя_типа_указатель - идентификатор;
имя_типа – идентификатор любого типа данных.
Ключевое слово Pointer является именем типа бестипового указателя.
Пример Объявление типа указателя.
Type
p1 = ^integer; {указатель на тип integer}
p2 = ^real; {указатель на тип real }
p3 = ^char; {указатель на тип char}
p4 = array [1..10] of ^integer; {массив указателей на integer}
p5 = array [1..20] of ^ real; {массив указателей на real}
p6 = array [1..30] of ^ char; {массив указателей на char}
pp1 = ^p1; {указатель на указатель на тип integer}
pp2 = ^p2; {указатель на указатель на тип real }
pp3 = ^p3; {указатель на указатель на тип char }
pp4 = ^p4; {указатель на массив указателей на integer}
pp5 = ^p5; {указатель на массив указателей на real}
pp6 = ^p6; {указатель на массив указателей на char}
a1 = array [1..5] of integer; {массив типа integer}
a2 = array [1..20] of real; {массив типа real}
a3 = array [1..6, 1..50] of real; {массив типа real}
a4 = array [1..5] of char; {массив типа char}
strc = record x, y: real end; {запись}
pa1 = ^a1; {указатель на массив типа integer}
pa2 = ^a2; {указатель на массив типа real}
pa3 = ^a3; {указатель на массив типа real}
pa4 = ^a4; {указатель на массив типа char}
pstrc =^ strc; {указатель на запись типа strc}
ptf = ^ text; {указатель на текстовый файл}
fn = function (x, y: integer): real; { процедурный тип}
pfn = ^ fn; {указатель на процедурный тип fn}
Переменные типа указатель можно объявить одним из двух способов:
1. в виде указателя на стандартный или ранее определенный тип данных;
2. с использованием ранее объявленного типа указатель.
Пример Объявление переменных типа указатель.
var
{ объявление с использованием стандартных типов}
vpi: ^ integer; {указатель на данные типа integer}
vpr: ^ real; { указатель на данные типа real}
vpc: ^ char; { указатель на данные типа char}
{ объявление с использованием ранее определенных типов}
vpa1: ^a1; {указатель на массив типа a1}
vpa2: ^a2; {указатель на массив типа a2}
vpa3: ^a3; {указатель на массив типа a3}
vpa4: ^a4; {указатель на массив типа a4}
vpstc: ^strc; {указатель на запись типа strc}
{ объявление с использованием ранее определенных типов указателей}
vp1: p1; {переменная - указатель на тип integer}
vp2: p2; {переменная - указатель на тип real}
vp3: p3; {переменная - указатель на тип char}
vp4: p4; {переменная - массив указателей на тип integer}
vp5: p5; {переменная - массив указателей на тип real}
vp6: p6; {переменная - массив указателей на тип char}
vpp4: ^p4; {переменная – указатель на массив указателей типа integer}
vpp5: ^p5; {переменная – указатель на массив указателей типа real}
vpp6: ^p6; {переменная – указатель на массив указателей типа char}
vpa1: pa1; {указатель на массив типа integer}
vpa2: pa2; {указатель на массив типа real}
vpa3: pa3; {указатель на массив типа real}
vpa4: pa4; {указатель на массив типа char}
vpstrc : pstrc; {указатель на запись типа strc}
pf : ptf; {указатель на текстовый файл}
ntp: pointer; {бестиповой указатель}
vf :fn; {процедурная переменная типа fn}
vpf : pfn; {указатель на функцию типа fn}
Замечание Недопустимо при объявлении типа или переменной типа указатель справа от символа ^ использовать что-либо, кроме имени типа.
Недопустимо:
type
p7 = ^string[5];
p8 = ^ array[1..10] of real;
p9 = ^ record x,y: real end;
var
vp10: ^ string[5];
vp11: ^ array[1..10] of real;
Замечание Правила объявления в Паскале требуют, чтобы все используемые в объявлениях константы и идентификаторы были объявлены до их использования. Но при описании указателей допускается ссылка на имя типа записи, определенной после её использования для определения указателя.
{function Sizeof (x):Word; - возвращает размер аргумента в байтах. x- переменная любого типа или любой тип.}
Обращение к переменной с помощью указателя
Указатель – это переменная или константа, которые хранят значение адреса ОП. Паскаль дает возможность использования адресов с помощью операций @ и ^.
Для объявления указателя и для извлечения значений переменной, которую адресует указатель, используют символ ^ .
Для получения адреса переменной можно использовать операцию @ или функцию Addr.
Операция @ - определение (получение) адреса переменной - возвращает адрес ОП своего операнда. Операндом операции @ должно быть имя переменной того же типа, для которого определен и указатель левой части оператора присваивания, получающий значение этого адреса.
Пример
pi := @ i;
Переменная - указатель pi получает значение адреса переменной I в результате выполнения оператора @. Выполнение этого оператора эквивалентно pi:= Addr( i );
Рассмотрим обращение к значению динамической переменной с помощью указателя. При этом используется косвенная адресация.
Косвенная адресация значения с помощью операции ^ осуществляет доступ к значению по указателю, то есть извлечение значения, расположенного по адресу - содержимому указателя. Операнд операции ^ должен быть типа указатель. Результат операции ^ представляет собой значение, на которое указывает (ссылается, адресует) операнд. Тип результата – это тип, определенный при объявлении указателя.
В общем виде оператор присваивания, использующий имя указателя и ^ - операцию косвенной адресации, можно представить как:
имя_переменной := имя_ указателя^ ;
где имя_ указателя – это переменная или константа, которые содержат адрес размещения значения, требуемого для переменной левой части оператора присваивания.
Пример
j :=pi ^;
Переменная j получает значение, расположенное по адресу, который содержится в указателе pi, с помощью оператора ^.
pi:= @i; j :=pi ^;
Последовательность операций выполняет то же самое, что j :=i ;
Схематично взаимосвязь между указателем и адресуемым значением можно представить в виде цепочки, где
ppi:=@pi - адрес указателя;
pi:=@i- значение указателя, адрес i;
i:=pi^; - значение переменной i.
Имена типов указателей можно использовать в списках формальных параметров.
Имена указателей и элементов массивов указателей с операцией ^ справа от имени переменной-указателя можно использовать:
1. в выражениях везде, где допускается использование значения, которое извлекается с помощью этой операции, например: j:=pi^;
2. в левой части операторов присваивания, например: pi^:=33, при этом переменная, расположенная по адресу pi, получит значение 33;
Над указателями допускаются операции сравнения: = и <>.
Ввод и вывод значений указателей в Паскале недопустимы.