Операции с указателями
3 Процедуры и функции, работающие с указателями
4 Преобразование типов данных с использованием типизированных указателей.
5 Управление динамической памятью
До настоящего момента мы имели дело с переменными, которые размещаются в памяти согласно вполне определенным правилам. Так, память под глобальные переменные программы выделяется в процессе компиляции, и эти переменные существуют в течение всего времени работы программы. Для локальных переменных, описанных в подпрограмме, память отводится при вызове подпрограммы, при выходе из нее эта память освобождается, а сами переменные прекращают свое существование. Иными словами, распределение памяти во всех случаях осуществляется полностью автоматически. Переменные, память под которые выделяется описанным образом, называют статическими. Под эту категорию подпадают все переменные, объявленные в области описаний программных блоков. Однако Borland Pascal предоставляет возможность создавать новые переменные во время работы программы, сообразуясь с потребностями решаемой задачи, и уничтожать их, когда надобность в них отпадает.
Переменные, созданием и уничтожением которых может явно управлять программист, называют динамическими. Для более полного понимания механизма работы с динамическими переменными следует сначала разобраться в механизме адресации оперативной памяти MS DOS.
Указатели.
Наименьшей адресуемой единицей памяти персонального компьютера, построенного на базе микропроцессоров фирмы Intel и их аналогов, является байт. Таким образом, память представляет собой последовательность нумерованных байтов. Для обращения к конкретному байту необходимо знать его номер, который называют его физическим адресом.
Память принято делить на слова, двойные слова и параграфы. Слово имеет длину 2 байта, двойное слово - 4 байта, а параграф - 16 байт.
При работе с памятью используется адресация по схеме «база + смещение» (рис. 7.1). При этом адрес конкретного байта М определяется как адрес некоторого заданного байта Аб (адрес базы) + расстояние до требуемого байта Асм (смещение).
В микропроцессорах фирмы Intel (начиная с i8086) в качестве адреса базы используют адреса, кратные 16. Четыре последних бита такого адреса равны 0, и их не хранят, а аппаратно добавляют при вычислении физического адреса.
Непрерывный участок памяти, имеющий длину не более 64 КБ и начинающийся с адреса, кратного 16 (0,16,32, ), называют сегментом. Адрес начала сегмента принимают за базу для всего сегмента. Адрес базы сегмента без последних четырех бит называют сегментным.
Сегментный адрес и смещение имеют размер по 16 бит (слово). Физический адрес, получаемый при их сложении с учетом отброшенных четырех бит (рис. 7.2), имеет размер 20 бит и может адресовать память объемом 2^20 байт или 1 МБ.
Максимальное смещение равно 2^16-1, что соответствует 64 КБ памяти. Таким образом, относительно одной базы можно адресовать не более 64 КБ памяти, что ограничивает размер сегмента.
Примечание. Современные модели микропроцессоров используют адреса большей длины с отличающейся схемой получения физического адреса, что учитывается версиями Pascal, предназначенным для работы «под Windows», но принцип адресации по схеме «база+смещение» используется и там.
Программа и данные хранятся в памяти фрагментами, каждый из которых расположен в своем сегменте. Различают три вида сегментов: кодов, данных и стека. В сегментах кодов хранится собственно программа. В сегментах данных размещаются глобальные переменные и константы. Сегмент стека интенсивно используется в процессе выполнения программы: при вызове подпрограмм в стек записывается адрес возврата, в нем размещаются локальные переменные, копии параметров-значений, адреса параметров-переменных и параметров-констант и т.п.
В процессе работы сегментные адреса хранятся в специальных сегментных регистрах:
Доступ к конкретным участкам сегмента осуществляется через соответствующие смещения. При записи адреса в память отдельно сохраняются сегментный адрес и смещение (рис. 7.3).
В Borland Pascal для работы с адресами используется специальный тип данных - указатель. Данные этого типа включают два поля типа word и хранят соответственно сегментный адрес и смещение.
Различают указатели двух типов: типизированные и нетипизированные.
Типизированные указатели содержат адреса, по которым в памяти размещаются данные определенных типов. Используя эти указатели с данными указанных типов, можно выполнять операции, предусмотренные базовым типом. Синтаксическая диаграмма объявления типизированного указателя приведена на рис. 7.4.
Например:
или без предварительного объявления типа:
Нетипизированные указатели хранят просто адреса, которые не связаны с данными конкретных типов. Для их объявления используют зарезервированное слово pointer.
Например:
Указатели –– единственное исключение из общего правила, согласно которому все ресурсы перед использованием должны быть описаны. Для них допускаются описания вида:
Для указателей, которые не хранят никаких адресов, введена константа «нулевой адрес» с именем nil. Константу nil можно присваивать указателю любого типа.