Указатели и динамические переменные

Вопросы для проверки знаний.

1. Какова минимальной адресуемой единицы памяти в современных языках программирования, а также вычислительных системах ?

2. Сколько ячеек памяти можно адресовать при помощи 8-битных адресов ?

3. Что называют стандартной памятью ПК ?

4. В чем заключается принцип сегментированной адресации ?

5. Что называют сегментами и смещением адреса ?

6. С какими сегментами одновременно может работать программа в МП 8086 и какие сегментных регистра используются для адресации в них ?

7. Какие исходные данные задают полный адрес в МП 8086 и как он вычисляется ?

8. Что такое динамическая память ?

9. Каким образом происходит обращение к динамическим данным ?

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 }