|
Горбачев Л.И. Основы программирования в среде Turbo Pascal.
[НАЗАД]
[ДАЛЕЕ]
УКАЗАТЕЛИ И ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ.
3. Тип данных "указатель".
Переменная задается тремя параметрами: именем, типом, значением и
адресом. Благодаря типу "указатель" появляется возможность использовать в
качестве значения переменной адрес другой переменной, так чтобы такая переменная
как бы "указывала" на другую.
Например: Переменная типа "указатель"
Имя |
Задание типа |
Значение |
Адрес | |
Z |
"указывает на переменную типа real" |
$24A2:$1000 |
$1000:$2A34 | |
Значением переменной Z с адресом $1000:$2A34 является адрес
переменной типа real (значение которой записывается начиная с адреса
$23A2:$1000).
Тип данных "указатель" вводится следующим образом: type real_index = ^real; var
head, tail: real_index; или var head, tail :
^real;
даже если наименование real_index не используется.
Переменная типа "указатель" указывает на переменную типа, заданного в
описании типа. Переменная связывается с этим типом. В качестве значения такая
переменная имеет адрес той переменной, на которую она указывает.
Переменной, на которую указывает указатель, не обязательно
присваивать какое-либо имя. К ней можно обращаться через имя указателя, а потому
она называется ссылочной переменной.
Например: Элементарные операции
присваивания для переменных типа "указатель".
Переменная head типа "указатель" имела в качестве значения адрес
вещественного числа 3.25, и имя head^, под которым можно было обратиться к этому
числу. Точно так же tail указывала на число 2.45.
Соответственно нужно различать два типа операций присваивания
значения: head^ := tail^;
Ссылочная переменная head^ получает значение tail^, т.е. head и tail
указывают теперь на одинаковые объекты 2.45.
Согласно head := tail переменные-указатели имеют одно и то же
значение, то есть указывают на один и тот же объект 2.45 (обратите внимание на
различие формулировок "одинаковые объекты" и "один и тот же объект").
В последней операции присваивания следует иметь в виду, что head и
tail должны указывать на объект одного и того же типа.
Пример: Выдать
адрес в форме сегмент: смещение, соответственно, в десятичном и
шестнадцатеричном виде. [program PointerTest]
Оператор присваивания var rptr :
^real; wptr : ^word; rptr := wptr; приводит при компиляции к ошибке,
поскольку rptr и wptr - объекты различного типа.
Между тем в качестве значения интерес представляет только один адрес,
а потому существует стандартный тип pointer, совместимый со всеми типами
указателей.
Ответим на следующие три вопроса:
- Как присваивается значение переменной типа "указатель"?
- Какие операторы и константы существуют для переменной типа "указатель"?
- Как можно выдать значение переменной типа "указатель"?
- Начнем с первого вопроса: Как присвоить переменной Р типа "указатель"
некоторое значение? Для этого существует две принципиально различных
возможности:
- с помощью стандартной процедуры new(P) переменная Р получает адрес
динамической памяти и там резервируется место для переменной P^;
- через оператор присваивания Р := допустимый адрес.
Рассмотрим сначала второй случай. Существует оператор @ для задания
адреса, применимый ко всем переменным: var i :
integer; r : real; zi : ^integer; zr : ^real; i := 135; zi := @i;
(* Итак, zi^ = 135 *) r := 1.3; zr := @r; (* Итак, zr^ = 1.3 *)
Кроме того, для работы с адресами существуют функции: addr(x),
ptr(seg, ofs), seg(x), ofs(x), dseg, cseg, sseg.
- Перейдем ко второму вопросу: Какие константы и операторы существуют для
переменных типа "указатель"? Для такого типа переменных имеется единственная
константа nil, т.е. после
var P : pointer; P := nil; переменная Р не указывает ни
на что (внутреннее представление $0000:$0000). На вопрос об операторах ответить
просто: их нет, т.е. ничего подобного Р + 2 или Р - sizeof(real) не существует!
- Остановимся на третьем вопросе: Как можно выдать значение переменной типа
"указатель"?Запись
var P : pointer; P :=
какой-либо адрес; write(P); приведет к ошибке "Cannot write variable of
this type" ("Нельзя записать переменную такого типа"). Итак, для того, чтобы
вывести значение Р в нужной Вам форме в виде абсолютного адреса (отдельно
СЕГМЕНТ:СМЕЩЕНИЕ) в десятичном или шестнадцатеричном представлении, нужно
написать собственную процедуру.
Может сложиться представление, что после var
P:^integer переменная Р^ является совершенно обычной целой переменной. Это так
лишь тогда, когда Р имеет некоторое определенное значение, а именно адрес Р^.
Наиболее распространенная ошибка, когда программу начинают строкой: Р^ := 17; не
присвоив Р значения, например, с помощью new(P). Тогда не ясно, где же находится
константа 17.
Пример: С помощью данной программы осуществляется ввод ряда
целых чисел, а затем осуществить вывод в обратном порядке. Head - голова;
Pair - пара; Tail - хвост; Ref - (reference) - ссылка, упоминание. [program DemoStack]
[НАЗАД]
[ДАЛЕЕ]
|
|