11.2 Адреса
Память компьютера представляет собой совокупность элементарных ячеек для хранения информации — байтов, каждый из которых имеет собственный номер или адрес, что позволяет обращаться к любому байту памяти. Адреса задаются совокупностью двух шестнадцатиразрядных слов, которые называются сегментом и смещением. Сегмент — это участок памяти, имеющий длину 64К и начинающийся с физического адреса, кратного 16 (т.е. 0, 16, 32, 48 и т.д.). Смещение указывает, сколько байт от начала сегмента необходимо пропустить, чтобы обратиться к нужному адресу.
Адресное пространство компьютера составляет 1М. Для адресации в этих пределах нужно 20 двоичных разрядов, которые получаются из двух шестнадцатиразрядных слов (сегмента и смещения) следующим образом: содержимое сегмента смещается влево на 4 разряда, освободившиеся правые разряды заполняются нулями, результат складывается с содержимым смещения.
Физический адрес = Сегмент + Смещение
11.3 Указатели
Для управления динамической памятью, для организации и обработки динамических структур данных используются переменные-указатели.
Переменная-указатель — это переменная, которая в качестве своего значения содержит адрес определенного байта памяти, начиная с которого записывается значение (чаще всего, динамической) переменной (указатель можно установить и на статическую переменную). Любое значение переменной-указателя представляет собой либо совокупность двух слов (данных типа Word), трактуемых как сегмент и смещение, либо пустое значение (если переменная-указатель ни на что не указывает). С помощью переменных-указателей можно размещать в динамической памяти данные любых типов.
Указатели могут быть типизованными и нетипизованными.
Типизованный тип-указатель (ссылочный тип) определяет множество значений, которые могут указывать на динамические переменные определенного типа, называемого базовым типом. Диапазон значений типа-указатель — все адреса памяти, по которым возможна запись данных.
Форматописания типа:
Type
имя_типа_указателя = ^базовый_тип ;
Пример:
Type
PInt = ^Integer ;
PCh = ^Char ;
В качестве базового типа указателя может быть использован идентификатор, который еще не определен, но он должен быть определен в этом же разделе описаний, в той же секции Type:
Пример:
Type
PRec = ^Rec ;
Rec = Record
. . .
end ;
Переменная-указатель, как говорилось выше, содержит адрес динамической переменной в памяти. По этому адресу можно получить доступ к значению динамической переменной.
Форматописания переменной:
1-ый способ:
Type
имя_типа_указателя = ^базовый_тип ;
Var
имя_переменной_указателя : имя_типа_указат ;
2-ой способ:
Var
имя_переменной_указателя : ^базовый_тип ;
Пример:
Var
PI1, PI2 : PInt ; { идентификаторы типов определены в предыдущих примерах }
PC1, PC2 : PCh ;
PR1, PR2 : PRec ;
или без раздела Type:
Var
PI1, PI2 : ^Integer ;
PC1, PC2 : ^Char ;
PR1, PR2 : ^Rec ;
В Паскале можно указатель не связывать с каким-либо конкретным типом данных. Для этого служит стандартный тип Pointer :
Var
имя_переменной_указателя : Pointer ;
Такие указатели называются нетипизованными. С их помощью удобно динамически размещать данные, структура и тип которых меняются в ходе работы программы.
Пример:
Var
PP : Pointer ;
Копировать (использовать в операторах присваивания) можно только значения указателей одного и того же типа: присваивания
PI1 := PI2 ; PC1 := PC2 ; PR1 := PR2 ;
допустимы, а, например,
PI1 := PC2 ;
запрещено, поскольку PI1 и PC2 указывают на разные типы данных. Это ограничение не распространяется на нетипизованные указатели, поэтому можно записать
PP := PC2 ; PR1 := PP ;
Переменной-указателю можно присвоить значение (адрес) с помощью процедур New, GetMem, операции определения адреса @ или функции Ptr. Если указатель не указывает ни на какую переменную, то его значение равно Nil (пусто). Таким образом, значением переменной-указателя может быть либо Nil, либо адрес некоторой переменой (обычно, динамической).
Для обращения к переменным базового типа (т.е. к самим значениям динамических переменных) служит
имя_переменной_указателя^:
PI1^,PI2^,PC1^ и т.д.,
могут быть и такие случаи:
A^[i], A . B^, A[i] . B^ и т.п.,
PI1^ := 105 ;
PI2^ := PI1^ ;
PC1^ := ‘S’ ;
WriteLn ( PI2 ) ; { вывод шестнадцатеричного адреса переменной }
WriteLn ( PI2^ ) ; { вывод значения переменной по заданному указателю }