- •1.1. Как начать работу с турбо паскалем
- •1.2. Функциональные клавиши
- •1.3 Текстовый редактор
- •1.4. Основные приемы работы в среде турбо паскаля
- •Глава2. Знакомство с языком турбо паскаля
- •Глава 2 знакомство с языком турбо паскаля
- •2.1. Ваша первая программа
- •2.2. Типы данных
- •2.3. Преобразования типов и действия над ними
- •2.4. Операторы языка
- •2.5. Массивы
- •2.6. Процедуры и функции
- •2.7. Примеры программ
- •Глава3.Элементы языка
- •Глава 3
- •3.1. Алфавит
- •3.2. Идентификаторы
- •3.3. Константы
- •3.4. Выражения
- •3.5. Операции
- •3.6. Структура программы
- •Глава 4. Типы данных
- •4.1. Простые типы
- •4.2. Структурированные типы
- •4.3. Строки
- •4.4. Совместимость и преобразование типов
- •Глава 5. Файлы
- •Глава 5
- •5.1. Доступ к файлам
- •5.2. Процедуры и функции для работы с файлами
- •5.3. Текстовые файлы
- •5.4. Типизированные файлы
- •5.5. Нетипизированные файлы
- •Глава 6. Указатели и динамическая память
- •6.1. Динамическая память
- •6.2. Адреса и указатели
- •6.4. Выделение и освобождение динамической памяти
- •6.5. Использование указателей
- •6.6. Процедуры и функции для работы с динамической памятью
- •6.7. Администратор кучи
- •Глава 7. Типизированные константы
- •7.1. Константы простых типов и типа string
- •7.2. Константы-массивы
- •7.3. Константы-записи
- •7.4. Константы-множества
- •7.5. Константы-указатели
- •Глава 8. Процедуры и функции
- •Глава 8
- •8.1. Локализация имен
- •8.2. Описание подпрограммы
- •8.3. Параметры-массивы и параметры-строки
- •8.4. Процедурные типы. Параметры-функции и параметры-процедуры
- •8.5. Нетипизированные параметры-переменные
- •8.6. Рекурсия и опережающее описание
- •8.7. Расширенный синтаксис вызова функций
- •Глава 9. Модули
- •Глава 9
- •9.1. Структура модулей
- •9.2. Заголовок модуля и связь модулей друг с другом
- •9.3. Интерфейсная часть
- •9.4. Исполняемая часть
- •9.5. Инициирующая часть
- •9.6. Компиляция модулей
- •9.7. Доступ к объявленным в модуле объектам
- •9.8. Стандартные модули
- •Глава 10. Объекты
- •Глава 10
- •10.1. Основные принципы ооп
- •10.2. Постановка учебной задачи
- •10.3. Создание объектов
- •10.4. Использование объектов
- •Глава 11. Другие возможности турбо паскаля
- •Глава 11
- •11.1. Внешние процедуры (функции)
- •11.2. Использование встроенных машинных кодов
- •11.3. Обращение к функциям операционной системы
- •11.4. Поддержка процедур обработки прерываний
- •11.5. Запуск внешних программ
- •11.6. Оверлей
- •11.7. Прямое обращение к памяти и портам ввода-вывода
- •11.8. Длинные строки
- •Глава 12. Встроенный ассемблер
- •Глава 12
- •12.1. Общее описание мп 8086/8088
- •12.2. Специфика встроенного ассемблера
- •Глава 13. Использование библиотеки crt
- •Глава 13
- •13.1. Программирование клавиатуры
- •13.2. Текстовый вывод на экран
- •13.3. Программирование звукового генератора
- •Глава 14. Использование библиотеки graph
- •Глава 14
- •14.1. Переход в графический режим и возврат в текстовый
- •14.2. Координаты, окна, страницы
- •14.3. Линии и точки
- •14.4. Многоугольники
- •14.5. Дуги, окружности, эллипсы
- •14.6. Краски, палитры, заполнения
- •14.7. Сохранение и выдача изображений
- •14.8. Вывод текста
- •14.9. Включение драйвера и шрифтов в тело программы
6.7. Администратор кучи
Как уже отмечалось, администратор кучи - это служебная подпрограмма, которая обеспечивает взаимодействие пользовательской программы с кучей. Администратор кучи обрабатывает запросы процедур NEW, GETMEM, DISPOSE, FREEMEM и др. и изменяет значения указателей HEAPPTR и FREELIST. Указатель HEAPPTR содержит адрес нижней границы свободной части кучи, а указатель FREELIST - адрес описателя первого свободного блока. В модуле SYSTEM указатель FREELIST описан как POINTER, однако фактически он указывает на следующую структуру данных:
type
PFreeRec = ATFreeRec;
TFreeRec = record
Next : pointer;
Size : pointer
end;
Эта списочная структура предназначена для описания всех свободных блоков памяти, которые расположены ниже границы HEAPPTR. Происхождение блоков связано со случайной последовательностью использования процедур NEW-DISPOSE или GETMEM-FREEMEM («ячеистая» структура кучи). Поле NEXT, в записи TFREEREC содержит адрес описателя следующего по списку свободного блока кучи или адрес, совпадающий с HEAPEND, если этот участок последний в списке. Поле SIZE содержит ненормализованную длину свободного блока или 0, если ниже адреса, содержащегося в HEAPPTR, нет свободных блоков. Ненормализованная длина определяется так: в старшем слове этого поля содержится количество свободных параграфов, а в младшем - количество свободных байт в диапазоне 0... 15. Следующая функция преобразует значение поля SIZE в фактическую длину свободного блока:
Function BlbckSize(Size: pointer): Longint;
{Функция преобразует ненормализованную длину свободного блока в байты}
type
PtrRec = record
Lo, Hi : word
end;
var
LengthBlock: Longint;
begin
BlockSize := Longint(PtrRec(Size).Hi)*16 + PtrRec(Size).Lo
end;
Сразу после загрузки программы указатели HEAPPTR и FREELIST содержат один и тот же адрес, который совпадает с началом кучи (этот адрес содержится в указателе HEAPORG). При этом в первых 8 байтах кучи хранится запись, соответствующая типу TFREEREC (поле NEXT содержит адрес, совпадающий со значением HEAPEND, a поле SIZE - ноль, что служит дополнительным признаком отсутствия «ячеек» в динамической памяти). При работе с кучей указатели HEAPPTR и FREELIST будут иметь одинаковые значения до тех пор, пока в куче не образуется хотя бы один свободный блок ниже границы, содержащейся в указателе HEAPPTR. Как только это произойдет, указатель FREELIST станет ссылаться на начало этого блока, а в первых 8 байтах освобожденного участка памяти будет размещена запись TFREEREC. Используя FREELIST как начало списка, программа пользователя всегда сможет просмотреть весь список свободных блоков и при необходимости модифицировать его.
Описанный механизм вскрывает один не очень существенный недостаток, связанный с работой администратора кучи, а именно: в любой освободившийся блок администратор должен поместить описатель этого блока, а это означает, что длина блока не может быть меньше 8 байтов. Администратор кучи всегда выделяет память блоками, размер которых кратен размеру записи TFREEREC, т.е. кратен 8 байтам. Даже если программа запросит 1 байт, администратор выделит ей фактически 8 байт. Те же 8 байт будут выделены при запросе 2, 3 ,..., 8 байт; при запросе 9 байт будет выделен блок в 16 байт и т.д. Это обстоятельство следует учитывать, если Вы хотите минимизировать возможные потери динамической памяти. Если запрашиваемый размер не кратен 8 байтам, в куче образуется <дырка> размером от 1 до 7 байт, причем она не может использоваться ни при каком другом запросе динамической памяти вплоть до того момента, когда связанная с ней переменная не будет удалена из кучи.
Если при очередном обращении к функции NEW или GETMEM администратор не может найти в куче нужный свободный блок, он обращается к функции, адрес которой содержит переменная HEAPERROR. Эта функция соответствует следующему процедурному типу:
type
HeapErrorFun = function (Size:word): Integer;
Здесь SIZE - размер той переменной, для которой нет свободной динамической памяти. Стандартная функция, адрес которой при запуске программы содержит переменная HEAPERROR, возвращает 0, что приводит к останову программы по ошибке периода счета с кодом 203 (см. прил. 3). Вы можете переопределить эту функцию и таким образом блокировать останов программы. Для этого необходимо написать собственную функцию и поместить ее адрес в указатель HEAPERROR. Например:
Function HeapFunc(Size: Word): Integer; far;
begin
HeapFunc := 1 end;
begin {Основная программа}
HeapError := @HeapFunc;
.......
end.
Отметим, что функция типа HEAPERRORFUN вызывается только в том случае, когда обращение с требованием выделения динамической памяти было неуспешным. Она может возвращать одно из трех значений:
0 - прекратить работу программы;
1 - присвоить соответствующему указателю значение NIL и продолжить работу программы;
2 - повторить выделение памяти; разумеется, в этом случае внутри функции типа HEAPERRORFUN необходимо освободить память нужного размера.