
- •1.2. Понятие алгоритма. Словесное задание алгоритмов
- •III. Тело алгоритма.
- •1.3. Типы алгоритмов. Операция присваивания
- •1.4. Графическое задание алгоритмов. Блок-схемы. Исполнение алгоритмов
- •2. Структурное программирование. Общие сведения по алгоритмическому языку паскаль и его среде разработки
- •2.1. Предпосылки появления и основные принципы структурного программирования
- •2.2. Язык программирования Турбо Паскаль. Единая интегрированная среда разработчика Turbo Pascal 7.0 (tp 7.0), структура ее диалогового окна и основные команды
- •2.3. Компилятор языка Паскаль Free Pascal ( fpc). Среда разработки Free Pascal ide
- •3. Основные элементы языка Паскаль. Алфавит. Идентификаторы. Типы данных. Выражения. Операции. Отношения. Математические функции в языке Паскаль
- •3.1. Синтаксис и семантика в описании алгоритмического языка. Алфавит языка Турбо-Паскаль
- •3.2. Элементарные конструкции языка Паскаль
- •3.3. Общая структура типов данных. Простые типы в языке Паскаль
- •3.4. Выражения, математические, логические операции, отношения, математические функции в языке Паскаль
- •3.5. Память пк, сегментная адресация, динамическая память
- •3.6. Указатели и динамические переменные
- •3.6.1. Виды указателей и их описание
- •3.6.2. Действия с указателями
- •3.6.3. Выделение и освобождение динамической памяти
3.6. Указатели и динамические переменные
3.6.1. Виды указателей и их описание
Указатели делятся на стандартные и определяемые программистом. Величины стандартного типа pointer предназначены для хранения адресов данных произвольного типа и при описании не привязаны к каким-либо конкретным типам.
Пример 1 указателя стандартного типа:
var p : pointer;
Таким образом, стандартный указатель представляет собой "заготовку", в которой может храниться адрес данных любого типа.
Также можно задать указатель на данные или подпрограмму конкретного типа. Как и для всех других нестандартных типов, это делается в разделе type с применением обозначения указателя ^.
Пример 2 описания переменной Buffer типа строка, включающая 255 символов, и указателя BufPtr на данную переменную, а также других переменных данных типов:
type Buffer = String[255]; BufPtr = ^Buffer; Var B : Buffer; BP : BufPtr; Указатели на данные определенного типа называются типизированными. Их можно описать на любой тип данных, кроме файловых. Если указателю присваивается стандартный тип данных, то его можно описать и непосредственно при описании переменной.
Пример 3. Задание указателя на данные типа word при описании переменной:
var pw : ^word;
Замечание. В Free Pascal, как и в других языках (например С) задание указателя на данные некоторого типа может рассматриваться как описание массива этого же типа (структурированной величины, состоящей из величин одного типа), причем сам указатель указывает на нулевой элемент этого массива.
Пример 4. Задание указателя на данные типа word в примере 3 можно считать эквивалентным следующему объявлению массива бесконечной длины с именем pw, у которого нумерация элементов начинается с 0, тип элементов - word (сам указатель задает адрес нулевого элемента):
var pw : array[0..Infinity] of word;
Таким образом, при описании типизированного указателя компилятор одновременно:
1) организует область памяти, в которой могут содержаться величины заданного типа,
2) создает специальную величину (указатель), в которой хранится начальный адрес этой области памяти.
Если указатель не типизирован, то по умолчанию считается, что он ссылается на данные, которые занимают в памяти по одному байту.
3.6.2. Действия с указателями
Для того, чтобы занести в указатель адрес существующей переменной (которая уже описана и получила свое место в памяти), применяют операцию получения адреса переменной. Она обозначается виде префикса @ или функции addr().
Пример 4 получения в указатель pw адреса переменной w типа word:
var w : word; { описание переменной w типа word }
pw : ^word; { описание указателя pw на величины типа word }
...
pw := @w; { или pw := addr(w); - засылка адреса переменной w в указатель pw }
Для обращения к значению переменной, адрес которой хранится в указателе, примеряется операция разадресации (разыменования), обозначаемая с помощью суффикса ^:
С величинами, адрес которых хранится в указателе, можно выполнять любые действия, допустимые для значений этого типа.
Пример 5 разыменования указателя pw из примера 4 и выполнения операций с получаемой переменной типа word:
pw^ := 2;
inc(pw^);
writeln(pw^);
Правила присваивания указателей:
1) любому указателю можно присвоить стандартную константу nil, которая означает, что указатель не ссылается на какую-либо конкретную ячейку памяти,
2) указатели стандартного типа pointer совместимы с указателями любого типа,
3) указателю на конкретный тип данных можно присвоить только значение указателя того же или стандартного типа.
Стандартные функции для работы с указателями:
addr(x) : pointer — возвращает адрес х (аналогично операции @), где х — имя переменной или подпрограммы;
seg (x) : word — возвращает адрес сегмента для х;
ofs (x) : word — возвращает смещение для х;
cseg : word — возвращает значение регистра сегмента кода CS;
dseg : word — возвращает значение регистра сегмента данных DS;
ptr (seg, ofs : word) : pointer — по заданному сегменту и смещению формирует адрес типа pointer.
Замечание. В Free Pascal, как и в С (но в отличие от Турбо Паскаля), поддерживаются арифметические действия с указателями сложение и вычитание. При этом каждая единица изменения величины типизированного указателя (например, при помощи функций Inc и Dec) означает сдвиг в памяти на такое число байт, которое занимает одна величина данного типа.
Пример 6 программы с описаниями и операциями с указателями:
var p1,p2 : ^longint; { описание указателей p1,p2 на величины типа longint }
L : longint; { описание величины L типа longint }
begin
Inc(p1); { увеличение p1 на 4, поскольку одна величины типа longint занимает в памяти 4 байта}
p1:= @p2; { засылка в p1 указателя на указатель p2}
p2:= @L; { засылка в p2 указателя на величину L}
L:= p1 - p2; { засылка в L разности значений указателей }
p1:= p1 - 2; { уменьшение p1 на 24=8 байт}
p2:= p2 + 4; { увеличение p2 на 44=16 байт }
end.
Присваивание L:= p1 - p2 в примере 6 возможно, поскольку все величины L,p1,p2 занимают в памяти одинаковый объем - по 4 байта.