Text
                    TURB PAS
О.А. МЕЖЕННЫЙ

Учитесь программировать
j"Z.
initgraph( i . j
Err: = GraphRe :>>	"
If Err
Ur i t eLn (i/ *• <•> ' z «Ise /// s///s/C
J/Шбы
diu 2 Get Ma 71
do' a:zReadKey
) Of
.Moue(0
HUV'A-V1 M°oe( .Moue(-<<5> \\	Moue(0>ie
' V \\V-1 ~.Moue(0 4
 -v- ’C1 . Move (5,0 r
1.	Koue( - 5.0
ervr end-
1 аЦДЛсКШиКА http: // www. di al ektijca. co 1» >
Учитесь программировать
Учитесь программировать
О. А. МЕЖЕННЫЙ
дцдлаялика
Москва • Санкт-Петербург • Киев Компьютерное издательство «Диалектика» 2001 год
ББК 32.973.26-018.2.75
М44
УДК 681.3.07
Компьютерное издательство “Диалектика”
По общим вопросам обращайтесь в издательство “Диалектика” по адресу: info@dialektika.com. http://www.dialektika.com
Меженный, Олег. Анисимович.
M44Turbo Pascal: учитесь программироват. — М. : Издательский дом “Вильямс”, 2001. — 448 с. : ил.
ISBN 5-8459-0176-6 (рус.)
Данная книга, посвященная программированию на Turbo Pascal, начинается с подробного описания примера достаточно простой программы. В последующих главах рассматриваются различные темы языка программирования Turbo Pascal, такие как операторы, подпрограммы, типы данных, файлы, указатели, модули, объектно-ориентированное программирование. Несколько глав книги посвящены использованию подпрограмм модулей поставляемых в составе Turbo Pascal 7.0. Помимо глав, в книге имеется несколько приложений, в которых содержатся вспомогательные материалы справочного характера.
Книга рассчитана на широкий круг читателей, изучающих программирование.
ББК 32.973.26-018.2.75
Все названия программных продуктов являются зарегистрированными торговыми марками соответствующих фирм.
Никакая часть настоящего издания ни в каких целях не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами, будь то электронные или механические, включая фотокопирование и запись на магнитный носитель, если на это нет письменного разрешения издательства ком-пыотеного издателктва “Диалектика”.
Copyright © 2001 by Dialektika Computer Publishing.
All rights reserved including the right of reproduction in whole or in part in any form.
ISBN 5-8459-0176-6
© Компьютерное изд-во “Диалектика”, 2001
Оглавление
Глава 1.	Введение в Turbo Pascal	17
Глава 2.	Операторы	37
Глава 3.	Процедуры и функции	61
Глава 4.	Типы данных	77
Глава 5.	Файлы	121
Глава 6.	Динамическая память и указатели	155
Глава 7.	Типизированные константы	181
Глава 8.	Модули	189
Глава 9.	Использование ресурсов модуля DOS	207
Глава 10.	Использование ресурсов модуля CRT	237
Глава 11.	Использование ресурсов модуля GRAPH	253
Глава 12.	Объектно-ориентированное программирование 317
Приложение А.	Интегрированная среда	335
Приложение Б.	Модуль SYSTEM	405
Приложение В.	Список всех процедур и функций	423
Приложение Г.	Структурная схема программы	431
Приложение Д.	Ресурсы Internet, посвященные Turbo Pascal	435
Приложение Е.	Таблица ASCII	439
Содержание
Глава 1. Введение в Turbo Pascal	17
Пример простой программы	18
О типах данных	26
Тип Real	27
Тип Integer	27
Тип Char	28
Тип Boolean	29
Алфавит и зарезервированные слова	29
Алфавит языка Turbo Pascal	30
Зарезервированные слова	31
Комментарии	32
Переменные	33
Константы	34
Глава 2. Операторы	37
Оператор присваивания	38
Составной оператор	38
Условные операторы	39
Оператор IF	39
Оператор CASE	42
Операторы цикла	45
Оператор WHILE	45
Оператор REPEAT	48
Оператор FOR	51
Вложенные циклы	53
Оператор перехода и пустой оператор	57
Оператор WITH	60
Глава 3. Процедуры и функции	61
Что такое подпрограмма	62
Описание процедур	63
Описание функций	65
Сферы действия имен	67
Параметры
Рекурсия	72
Опережающее описание	75
Стандартные процедуры и функции	76
Глава 4. Типы данных	77
6
Содержание
Понятие типа данных	78
Простые типы	79
Порядковые типы	82
Строки	89
Структурированные типы данных	93
Массивы	93
Записи	102
Множества	110
Совместимость типов	117
Приведение типов	119
Глава 5. Файлы	121
Что такое файл	122
Файловые типы и файловые переменные	123
Операции над файлами	126
Организация доступа к файлам	126
Ввод-вывод	132
Ориентирование в файле	133
Специальные операции	139
Завершающие операции	141
Виды файлов	142
Типизированные файлы	142
Текстовые файлы	143
Нетипизированные файлы	150
Еще процедуры и функции для работы с файлами	154
Глава 6. Динамическая память и указатели	155
Типичная проблема	156
Статические и динамические переменные	158
Указатели	159
Состояния указателя	161
Выделение и освобождение динамической памяти 161
Действия над указателями и динамическими переменными	163
Два вида динамических данных	165
Динамические данные без внутренних ссылок	165
Динамические данные с внутренними ссылками	167
Процедуры и функции для работы с динамической памятью	170
Работа с обширным массивом	176
Глава 7. Типизированные константы	181
Содержание
7
Знакомство с типизированными константами	182
Константы простых типов	183
Константы-строки	184
Константы-массивы	184
Константы-записи	185
Константы-множества	186
Константы-указатели	186
Глава 8. Модули	189
Кое-что о модулях	190
Стандартные модули	191
Структура модуля	193
Заголовок модуля	194
Интерфейсный раздел	195
Раздел реализации	196
Инициирующий раздел	197
Компиляция модулей	197
Использование модулей	199
Порядок действия имен	199
Косвенное использование модулей	201
Взаимное использование модулей	201
Порядок выполнения инициирующих разделов 202
Библиотеки модулей. Файл TURBO.TPL	203
Утилита TPUMOVER	204
Другие утилиты	206
Глава 9. Использование ресурсов модуля DOS	207
Обслуживание прерываний	208
Вызов прерывания	208
Как задать иную процедуру обработки прерывания 214
Дата и время	216
Системные дата и время	217
Дата и время изменения файла	219
Статус диска	221
Обработка файлов	222
Обработка процессов	228
Работа с переменными среды	230
Дополнительные средства	232
Обработка <Ctrl+Break>	232
Состояние верификации в MS DOS	233
Версия MS DOS	234
Глава 10. Использование ресурсов модуля CRT	237
8
Содержание
Управление клавиатурой	238
Клавиши и коды	238
Выявление нажатия любой клавиши	240
Выявление нажатия определенной клавиши	241
Программа определения кодов	241
Управление выводом на экран	243
Быстрый вывод на экран	243
Выбор текстового режима	244
Цвета символов и фона	245
Яркость	246
Перемещение курсора	247
Текстовые окна	248
Очистка окна	249
Работа со строками	250
Управление звуком	251
Глава 11. Использование ресурсов модуля GRAPH	253
Режимы: графический и текстовый	254
Цвета, палитры, заполнения	265
Координаты и окна	272
Точки и линии	279
Незаполненные фигуры	287
Заполненные фигуры	293
Текст в графическом режиме	302
Прочие процедуры и функции	310
Страницы	311
Изображения: сохранение в памяти и отображение на экране	313
Встраивание в исполняемый файл драйверов 314
Встраивание в исполняемый файл шрифтов	315
Глава 12. Объектно-ориентированное программирование 317
Что такое ООП	318
Инкапсуляция	319
Наследование	323
Виртуальные методы и полиморфизм	325
Конструкторы, динамические объекты и деструкторы 329
Поля и методы: скрытые и общедоступные	333
Приложение А. Интегрированная среда	335
Основные понятия и определения	336
Система меню	345
Содержание
9
Меню File	345
Меню Edit	351
Меню Search	353
Меню Run	358
Меню Compile	360
Меню Debug	363
Меню Tools	371
Меню Options	373
Меню Window	391
Меню Help	395
Локальное меню	399
Команды редактора	399
Команды перемещения курсора	400
Команды вставки и удаления	401
Команды для работы с выделенными фрагментами 401
Прочие команды	402
Приложение Б. Модуль SYSTEM	405
Управление выполнением программы	406
Преобразование типов	407
Работа с переменными порядковых типов	409
Математические функции	411
Работа со строками	413
Управление динамической памятью	415
Работа с адресами	415
Ввод-вывод и работа с файлами и каталогами	417
Прочее	417
Приложение В. Список всех процедур и функций	423
Приложение Г. Структурная схема программы	431
Приложение Д. Ресурсы Internet, посвященные Turbo Pascal	435
Приложение Е Таблица ASCII	439
Предметный указатель	442
10
Содержание
От автора
Данная книга предназначена для всех тех, кто хочет (или кому необходимо) научиться создавать программы на языке программирования Turbo Pasc al. Она может использоваться как учебник студентами и учащимися и как самоучитель теми, кто предпочитает учиться самостоятельно. Для успешного усвоения предлагаемого материала предварительной подготовки в области программирования не требуется. Для изложения, охватывающего основные аспекты указанного языка программирования, использована версия Turbo Pascal 7.0.
Автор благодарен коллективу редакции фирмы "Диалектика”, — всем, кто принимал участие в создании этой книги, — прежде всего зав. редакцией С. Н. Тригубу (за конструктивную критику и ценные советы), литературному редактору Л. И. Лесько (способствовавшей тому, чтобы текст книги соответствовал нормам литературного языка), художественному редактору С. А. Чернокозинскому (за обложку, а также за рисунки, иллюстрирующие и оживляющие текст), техническому редактору А. В. Говде (сумевшему превратить полученный от автора скучный текст в привлекательные страницы) и корректорам Л. А. Гордиенко, Л. В. Коровкиной, О. В. Мишутиной (за своевременное и качественное внесение правок).
Автор заранее благодарен читателям, которые пришлют отзывы, замечания, предложения, а также сообщения о выявленных ошибках по адресу oleg@dialektika. com.
Введение
В первом разделе введения читателю предлагается информация о структуре книги и о том, как с ней работать. Во втором разделе кратко излагается история появления языка программирования Pascal, его развития и, наконец, создания Turbo Pascal 7.0 — версии, к изучению которой мы сейчас приступаем.
Как построена эта книга
Решая, как излагать материал, автор столкнулся с определенными трудностями. В самом деле, если начать с изложения основ языка программирования, читателю долго не будет ясно, как это работает и для чего все это нужно. В итоге такая книга получится скучной и неинтересной. Если же сразу начать с создания программы, читатель многого может не понять. Поразмыслив, автор все же решил первую главу начать с примера достаточно простой программы, сопровождая его подробными объяснениями. Подобный подход позволит сразу же “окунуть” читателя в процесс программирования, тем самым вызвав интерес к изучаемому материалу. При этом, если что-то окажется непонятно, к главе 1 можно вернуться впоследствии, вооружившись сведениями, содержащимися в последующих главах.
Последующие главы (2-12) посвящены различным темам, описывающим язык программирования Turbo Pascal, таким как операторы, подпрограммы, типы данных, файлы, указатели, модули, объектно-ориентированное программирование. Предполагается, что эти главы будут читаться последовательно — одна за другой. Объяснения, по возможности, дополняются примерами. Примеры представляют собой либо фрагменты программ, либо целые программы. При этом тексты целых программ, если они небольшие, представлены в виде копии экрана в окйе редактора Turbo Pascal вместе с окном вывода (Output). Это позволяет читателю видеть в одном месте как исходный текст программы, так и результаты ее работы (т.е. вывод на экран). Как это выглядит, демонстрирует рис. В. 1.
12
Turbo Pascal: учитесь программировать
Окно редактора Turbo Pascal с текстом программы Окно Output с выводом на экран
Btle '"Edit "Search :
a
read (b);
if b>=0 then writein (b);
read (c);
if c>=0 then writein £c)
program example;
var a,b,c:real;
begin
read (a);
if a>=0 then write In fa);
Output
OOOC
		
1. SuwOCwwE • Uj.
end.
b:=b*b;
ОСЮОООООООЕ^ОО
6.4OOOOOOOOOE+01
00000!


Рис. B. 1. Подобное представление программ, когда в одном месте содержатся исходный текст и вывод программы на экран, должно облегчить понимание материала
Имея дело с подобными копиями экрана, необходимо помнить, что окно Output свободно перемещается по экрану. Иными словами, взаимное расположение окна редактора Turbo Pascal и окна Output может несколько отличаться оттого, что показано выше.
Тексты обширных программ (которые не поместились в окне редактора Turbo Pascal) представлены в тексте книги. При этом тексты программ (обширных и не очень), если они отмечены пиктограммой Internet (см. далее), содержатся на Web-узле издательства “Диалектика” (http/www.dialektika.com), откуда их можно загрузить на свой компьютер. (Для того чтобы получить доступ к упомянутым примерам, после загрузки главной страницы следует щелкнуть на ссылке Материалы, а затем в появившемся на экране перечне выбрать название данной книги.)
С примерами программ, которые приведены в этой книге (и доступны в Internet для загрузки), можно (и желательно) экспериментировать. Как? Например, изменить выводимый на экран текст, чтобы увериться, что вывод на экран изменится соответственно. Можно увеличить или уменьшить число циклов в программе, в которой используются операторы цикла, чтобы посмотреть, что из этого выйдет. Не запрещается также поэкспериментировать с условиями в условном операторе, чтобы лучше понять, его принцип работы. Несомненно, что в процессе работы над книгой и знакомства с приведенными примерами программ у читателя появятся новые идеи.
Введение
Несколько глав книги посвящены использованию подпрограмм модулей SYSTEM, DOS, CRT и GRAPH. Поскольку на сегодняшний день Turbo Pascal как средство разработки крупных программ в значительной мере утратил свое значение и используется в основном в учебных целях, в этой книге средства модуля OVERLAY не рассматриваются. Что касается модулей PRINTER, TURBO3 и GRAPH3, то их использование ограничено, и нескольких слов, сказанных о них в главе 8, вполне достаточно. В данной книге не рассматривается также библиотека Turbo Vision.
Помимо глав, в книге имеется несколько приложений, в которых содержатся вспомогательные материалы справочного характера. Особое место среди них занимает обширное Приложение А с руководством по использованию интегрированной среды разработчика Turbo Pascal 7.0. Автор исходил из предположения, что приступающие к изучению языка программирования Turbo Pascal в массе своей не знакомы со средой разработчика и поэтому подробные сведения (которых, кстати, нет во многих других книгах, посвященных Turbo Pascal) им не помешают. Почему руководство о среде помещено в приложение в конце книги? Дело в том, что цель данной книги — научить читателя основам программирования на Turbo Pascal, а не использованию среды разработчика. Поэтому к указанному Приложению можно обращаться только по мере необходимости.
Прочие приложения содержат такие полезные вещи, как таблицу ASCII, структурную схему программы со всеми возможными разделами, перечень всех рассмотренных подпрограмм (с указанием модуля, в котором содержится данная подпрограмма, и главы, где можно найти описание этой подпрограммы). Кроме того, в приложениях вы найдете описания тех подпрограмм модуля SYSTEM, которые не рассматривались в главах книги, и список Internet-ресурсов, посвященных Turbo Pascal, где можно найти тексты программ и файлы модулей, документацию и разного рода руководства, файлы драйверов и шрифтов.
В книге вам встретятся следующие пиктограммы (всего две).
Данной пиктограммой помечены примеры программ, которые можно найти на Web-узле издательства “Диалектика" (http/www.dialektika.com),
Примечание
  —‘—7-~~—..,.^7...,;..i
V 11одобной пиктограммой помечены абзацы, содержимое • J которых уточняет приведенный выше материал. J
Указанные пиктограммы призваны помочь читателю лучше и быстрее ориентироваться в книге.
14
Turbo Pascal: учитесь программировать
Историческая справка
Язык программирования, одной из поздних версий которого посвящена данная книга, создан швейцарским физиком Никлаусом Виртом (Niklaus Wirth — портрет на рис. В.2) в 1970 году и назван в честь французского математика XVII века Блеза Паскаля, потрет которого можно видеть на обложке.
Почему язык программирования назван именем французского математика? Дело в том, что Паскаль (в 1640 г.) создал арифметическую (или счетную) машину, которая считается первым подобным устройством. Он даже смог изготовить и продать 10—15 ее экземпляров, причем некоторые из них дошли до наших дней! Машину Блеза Паскаля (схему и изображение дошедшего до нас экземпляра) можно видеть на рис. В.З.
Рис. В.2. Никлаус Вирт
Рис. В.З. Схема и сохранившийся экземпляр счетной машины Блеза Паскаля
Итак, оригинальная версия языка программирования Pascal была предложена в 1970 году. Впоследствии появилось множество версий и
Введение
И5
расширений этого языка. Наиболее популярным из них стал пакет Turbo Pascal фирмы Borland, выпущенный в 1983 году. Первая версия этого пакета предназначалась для операционной системы СР/М, но уже через год (в 1984 г.) появилась версия для MS DOS. С тех пор было выпущено несколько версий этого пакета, последнюю из которых — Turbo Pascal 7.0 — мы как раз собираемся изучать.
16
Turbo Pascal: учитесь программировать
В этой главе...________________
	Пример простой программы
	Кое-что о типах данных
	Символы и зарезервированные слова
	Комментарии
	Переменные
	Константы
Многие книги, посвященные Turbo Pascal, начинают знакомить читателя с этим языком программирования с таких элементарных понятий, как алфавит, зарезервированные слова, типы, переменные, операторы и т.п. В принципе, подход “от простого к сложному” себя оправдывает, однако в данном случае представляется, что читатель лучше поймет смысл перечисленных выше элементарных понятий, если начать с примера простой программы, включающей эти элементы Так и поступим. Попробуем создать простую программу, а затем запустим ее на выполнение, чтобы убедиться, что она работает должным образом.
Пример простой программы
Предположим, необходимо создать программу для вычисления корней квадратного уравнения ахг+Ьх+с= О. Конечно, для полного решения этого уравнения было бы необходимо предусмотреть различные случаи, когда его коэффициенты А, Ви С равны или не равны нулю. (Например, если А = О, В - О и С= О, то уравнение имеет бесконечное множество решений. Если А = О, В — О, а СУ О, то уравнение не имеет решений. Для этих и прочих частных случаев в будущей программе можно было бы предусмотреть вывод соответствующих текстовых сообщений.) Однако для упрощения задачи (и будущей программы) будем считать, что коэффициент А здесь не равен нулю, а дискриминант уравнения (Ь2-4ас) неотрицателен. Программу с учетом всех изменений содержит пример 1.1.
Internet
Пример 1.1
program rootsl;
var a, b, c, xl, x2: real;
begin
read (a, b, c)
xl:=(-b+sqrt(sqr(b)-4*a*c))/(2*a);
x2:=(-b-sqrt(sqr(b)-4*a*c))/(2*a);
Vrite (xl, x2);
end.
Первая строка приведенной выше программы, начинающаяся с зарезервированного слова PROGRAM, представляет собой заголовок. (Здесь, вероятно, уместно сказать, что длина заголовка, а также любой другой строки программы на Turbo Pascal не должна превышать 126 символов.) Вообше-то. присутствие в программе заголовка — это требование стандартного Pascal. В Turbo Pascal заголовок не является обяза-
18
Turbo Pascal учитесь программировать
тельным элементом текста программы. Тем не менее, чтобы каждая рассматриваемая программа имела собственное имя, все примеры программ, с которыми нам придется иметь дело в этой книге, будем дополнять заголовками. (Подробнее о структуре программы и о месте в этой структуре заголовка речь пойдет в Приложении Г.)
Слово PROGRAM (а также VAR, BEGIN и END, которые вы также найдете в приведенной программе) относится к так называемым зарезервированным (в Turbo Pascal) словам, имеющим специальное назначение, о которых будет идти речь дальше в этой главе. После слова PROGILAM, через пробел, следует имя программы, присваиваемое автором при ее создании. Наша программа имеет имя Roots 1
Со второй строки в нашей программе начинается раздел описания переменных. Все используемые переменные должны быть описаны в этом разделе. В нашем случае после слова VAR следует перечень из пяти переменных. Слово Real после этого перечня (через двоеточие) указывает, что данные переменные могут принимать только вещественные значения. Если какая-либо переменная из тех, что используются в программе, не фигурирует в разделе описания переменных, компилятор выведет соответствующее сообщение об ошибке. С наиболее используемыми типами данных мы познакомимся позже в этой главе.
В оставшейся части программы — между служебными словами BEGIN и END — содержится ее тело (или раздел операторов). Здесь описанные средствами Turbo Pascal представлены все действия, позволяющие получить нужные результаты. (О структуре программы и о том, какое место в этой структуре занимает тело программы, речь пойдет в Приложении Г)
Первая строка тела программы в приведенном выше примере представляет собой оператор чтения Read, который служит для ввода значений переменных А, В и С. На практике это выглядит так. Дойдя до оператора Read, программа приостанавливает работу и от пользователя программы (который заинтересован в получении результатов вычислений) требуется ввести значения соответствующих переменных. Пользователь вводит значение переменной А и нажимает клавишу <Enter>, а затем аналогично вводит значения переменных В и С. Если бы оператор чтения выглядел как read (с, а, Ь), то сначала пришлось бы ввести значение для переменной С, затем для А и наконец для В.
После операторов, позволяющих ввести значения переменных, следует оператор присваивания xl:=(-b+sqrt(sqr(b)-4*a*c))/(2*а);. Знак присваивания (:=) делит его на две части. В правой части представлено выражение, которое необходимо вычислить. Затем полученное значение присваивается переменной, содержащейся в левой части оператора. Данный оператор вычисляет значение одного из корней (xl) квадратно-
1 Roots — корни (англ).
Глава 1. Введение в Turbo Pascal	Н9
го уравнения и присваивает его переменной XI. Если в традиционной форме записи, принятой в математике, это выражение выглядит как
-b+^Jb? -4 ас
2а
то представленное на языке программирования Turbo Pascal оно имеет несколько иной вид (см. выше). Во-первых, для возведения в квадрат предусмотрена специальная функция Sqr. Выражение Sqr(b) из Turbo Pascal соответствует b2. Кроме того, выражение 4ас (представленное в традиционной форме) в Turbo Pascal следует записывать как 4*а*с, где символ * (звездочка) — знак умножения. Иными словами, в тексте программы на Turbo Pascal знак умножения нельзя опускать или заменять точкой.
Также если в традиционном математическом представлении выражение, вычисляющее один из корней квадратного уравнения, записано в две строки и операция деления представлена горизонтальной линией, разделяющей делимое и делитель, то в Turbo Pascal соответствующее выражение записывается в одну строку, а в качестве знака деления используется наклонная черта (/). При этом вместо знака радикала в Turbo Pascal используется специальная функция Sqrt, предназначенная для вычисления квадратного корня.
Оператор присваивания x2:=(-b-sqrt(sqr(b -4*а*с))/(2*а);, вычисляющий второй корень нашего квадратного уравнения, отличается от предыдущего оператора единственным знаком математической операции. Вместо знака плюс (+) перед функцией вычисления квадратного корня здесь используется минус (—).
К сказанному можно добавить, что операторы в тексте программы следует располагать определенным образом и при этом в меру использовать отступы и пустые строки. Отступы предназначены для того, чтобы показать, где одна структура включается в другую, а пустые строки — для отделения основных разделов программы. В принципе, текст программы можно записать и в одну строку — для компилятора это безразлично. Наша программа Roots 1, представленная подобным образом, выглядит так:
program rootsl; var a, b, с, xl, х2: real; begin read (a, b, c) xl:=(-b+sqrt(sqr(b)-4*a*c))/{2*a); x2:=(-b-sqrt(sqr(b)-*a*c))/(2*a); write (xl, x2); end.
И эта программа будет работать! Однако, если данную программу потребуется когда-нибудь изменить или усовершенствовать, разобраться в таком исходном тексте будет непросто. Чтобы повысить их читабельность, при написании текстов программ следует придерживаться определенного стиля.
20
Turbo Pascal: учитесь программировать
Кроме того, отладка (т.е. удаление ошибок) программы проводится построчно. Если в программе, записанной в одну строку, компилятор обнаружит ошибку, будет зафиксирован сам факт, но не выявлен оператор, содержащий ошибку. А если в строках программы содержатся по два-три оператора, при обнаружении ошибки программисту придется предпринимать дополнительные действия, чтобы выявить ее местонахождение. Иными словами, целесообразно исходный текст программы максимально вытягивать по вертикали — стремиться в каждой строке иметь не более одного оператора.
Теперь, когда мы себе представляем, как должна выглядеть программа, вычисляющая корни квадратного уравнения, остается только ввести ее текст и попробовать выполнить. Исходный тёкст программы Rootsl в окне интегрированной среды разработчика Turbo Pascal 7.0 можно видеть на рис. 1.1.
Тело программы
Заголовок Раздел описания переменных
Рис. 1.1. Программа Rootsl в окне интегрированной среды разработчика
Теперь попробуем выполнить нашу программу. Для этого в меню Run интегрированной среды разработчика выберем одноименный пункт. В результате программа запускается на выполнение.
Собственно при этом программа выполняется, только если в ней нет ошибок. Если же без ошибок не обошлось, курсор позиционируется в месте предполагаемой ошибки, а в первой строке в окне редактора отображается информация об обнаруженной ошибке (рис. 1.2).
Глава 1. Введение в Turbo Pascal
2Л
Рис. 1.2. Такое может случиться с каждым
Мы здесь просто забыли ввести точку с запятой после оператора Read. Более подробную информацию по той или иной ошибке вы найдете в системе справки (пункт меню Help интегрированной среды разработчика).
Какой вид принимает экран после запуска на выполнение нашей (свободной от ошибок) программы, позволяет судить рис. 1.3. Здесь в первой строке можно видеть введенные исходные данные, а во второй — вычисленные программой корни уравнения.
3 66 8
-1.2188741862Е-01-2.1878112581Е+С1
Рис. 1.3. Все правильно, хотя и не слишком вразумительно
22
Turbo Pascal: учитесь программировать
Конечно, это никуда не годится! Во-первых, не помешало бы сделать так, чтобы программа отображала текстовое сообщение, приглашающее ввести значение каждой из переменных. Для этого вместо единого оператора Read, позволяющего задать по очереди все три переменные, добавим в программу три оператора Read, — для ввода значения каждой переменной в отдельности, — предварив каждый из них оператором Write, обеспечивающим вывод на экран соответствующего сообщения. В результате фрагмент текста программы, позволяющий ввести значение одной из переменных, примет следующий вид:
write ('Введите значение А'); read (а);
Во-вторых, значения корней уравнения здесь представлены в одну строку и не разделены даже пробелом. Было бы лучше вывести их в отдельных строках и как-нибудь обозначить. Для этого вместо одного оператора Write, обеспечивающего вывод на экран значений обоих корней уравнения, введем в программу два оператора WriteLn, чтобы значения корней отображались в разных строках. (Процедура Write осуществляет вывод заданного значения и переводит курсор2 на следующую позицию в той же строке; процедура WriteLn осуществляет вывод заданного значения и переводит курсор в начало следующей строки.) Кроме того, сделаем так, чтобы значения корней, выводимые на экран, предварялись соответствующими обозначениями. В результате операторы WriteLn будут выглядеть так:
writein ('xl=',xl); writein ('х2=',х2);
(Вероятно, читатель уже догадался, что если аргумент функции WriteLn заключен в апострофы, символы между апострофами будут выведены на экран в том виде, в каком они представлены в тексте программы.)
Наконец, неплохо бы весь вывод на экран как-нибудь озаглавить. Д ля этого можно ввести в начало программы оператор
writein ('Вычисление корней квадратного уравнения')
Программу со всеми этими преобразованиями (пусть теперь она называется Roots2) содержит пример 1.2.
Internet
program roots2;
var a, b, c, xl, x2: real;
begin
writein ('Вычисление корней квадратного уравнения');
2 Курсор — это горизонтальная мигающая черточка на экране, указывающая, где будет отображен следующий символ, когда вы введете его с клавиатуры.
Глава 1. Введение в Turbo Pascal	23
write ('Введите значение А	
read (а); write ('Введите значение В	
read (b); write ('Введите значение С	
read (с);
xl:=(-b+sqrt(sqr(b)-4*a*c))/(2*a);
x2:=(-b-sqrt(sqr(b)-4*a*c))/(2*a);
writein ('xl'fXl);
writein ('x2',x2);
end.
Как теперь выглядит экран с результатами работы программы, смотрите на рис. 1.4.
Вычисление корней квадратного уравнения
Введите значение А: 3
Введите значение В: 66
Введите значение С: 8 xl=-l.2188741S62E-01 х2--2.1878112581Е+01
Рис. 1.4. Так гораздо лучше
Ну вот, здесь уже что-то можно понять. Видны значения коэффициентов А, Ви С, а также вычисленные значения корней уравнения. Пусть вас не смущают, возможно,, непонятные величины XI и Х2. Здесь мы имеем дело с так называемым представлением чисел с плавающей точкой (известное также как экспоненциальный формат чисел). Число, расположенное перед символом Е, в этом представлении заменяет основание степени 10, а непосредственно за ним следует порядок. В нашем случае 1.2188741862Е-01 соответствует 1.2188741862*101 или 0.12188741862, а 2.1878112581Е+01— 2.1878112581*10' или 21.878112581. Для чего это нужно? Для краткого представления чисел с большим количеством разрядов (например, двадцатью и больше). Дело в том, что компьютеры имеют ограниченную разрядность, и чтобы на них можно было обрабатывать огромные (или бесконечно малые) числа, эти числа приходится представлять в форме, подходящей для компьютера.
24
Turbo Pascal: учитесь программировать
Как еще можно усовершенствовать программу вычисления корней квадратного уравнения? Например, вовсе необязательно вводить в программу переменные х1 и х2 и использовать отдельные операторы для вычисления и для вывода результатов. Эти действия можно совместить. В результате корни квадратного уравнения будут вычисляться и выводиться на экран следующим образом:
writein (('xl='),(-b+sqrt(sqr(b)-4*a*c))/(2*а));
writein (('х2='),(-b-sqrt(sqr(b)-4*a*c))/(2*а));
Нетрудно заметить, что выражения sqrt(sqr(b)-4*a*c) и 2*а вычисляются здесь по два раза, и это увеличивает время работД! программы. Конечно, в случае такой простой программы, как наша, это не ощутимо, однако в обширных программах, если допустить, чтобы одно и то же выражение вычислялось повторно несколько десятков (или сотен) раз, мелкие задержки неизбежно сложатся в нечто существенное. Кроме того, хороший стиль программирования диктует исключать случаи повторного вычисления выражений. В силу этого введем в нашу программу две новые переменные — D и Е, присвоим им вычисленные значения указанных выражений, а затем используем эти переменные для дальнейших вычислений. Программа с указанными изменениями (которая теперь называется Roots3) содержится в примере 1.3.
Internet
program roots3;
var a, b, c, d, e: real;
begin
writein ('Вычисление квадратного уравнения');
write ('Введите значение А ');
read (а);
write ('Введите значение В ');
read (b);
write ('Введите значение С ');
read (с);
d:=sqrt(sqr(b)-4*a*c);
е:=2*а;
writein (('xl='), (~b+d)/e);
writein (('х2='), (-b-d)/e);
end.
Теперь испытаем нашу программу. При этом необходимо помнить, что изменения в последнем варианте нашей программы Root.s3 по сравнению с Roots2 связаны исключительно с внутренним порядком вычислений и никак не влияют на вид экрана с результатами работы программы.
Кстати, можно сделать так. чтобы на экране одновременно были видны исходный текст программы и результаты ее работы. Для этого в
Глава 1. Введение в Turbo Pascal
25
меню Debug (Отладка) среды разработчика выберем пункт Output (Вывод). Результат виден на рис. 1.5.
Рис. 1.5. Текст программы и результаты ее работы
На экране появилось окно Output с отображением результатов работы программы Roots3. Если здесь видна не вся информация, можно воспользоваться полосами прокрутки окна Output. На этом, пожалуй, можно завершить совершенствование программы вычисления корней квадратного уравнения.
Как будто все очевидно, и читателю, вероятно, уже не терпится написать собственную программу. К сожалению, не все так просто. Для того чтобы программы на Turbo Pascal писать правильно, необходимо прежде познакомиться с некоторыми элементарными вещами. Этому и посвящаются оставшиеся разделы данной главы.
О типах данных
Типам данных специально посвящена глава 4 этой книги, однако до того нам часто придется иметь дело с различными типами данных при изучении тех-или иных тем. Поэтому полезно усвоить о типах данных некоторые начальные сведения, отложив более подробный разговор до указанной главы.
Тип позволяет точно определить, как следует интерпретировать те или иные данные. В результате исключаются попытки производить над этими данными неприемлемые операции. Например, если в программе фигурирует переменная, имеющая смысл “количество штук”, понятно, что ее значение не должно представлять собой дробное число. Чтобы
26
Turbo Pascal: учитесь программировать
этого избежать, такой переменной при объявлении должен быть присвоен один из целочисленных типов. Также недопустимы арифметические операции над символами, чтобы этого не случилось, соответствующие переменные должны принадлежать символьному типу (Char). А если в программе имеется переменная, способная принимать только значения Да или Нет (либо Правда или Пожь), чтобы обеспечить правильную трактовку ее значения, данная переменная должна принадлежать логическому типу (тип Boolean). Иными словами, принятая в Turbo Pascal типизация переменных позволяет исключить ошибочную интерпретацию данных и повышает надежность программ.
Тип Real
Мы уже встречались с типом данных Real в программах Rootsl — Roots3 и знаем, что это вещественный тип данных. Переменные типа Real Moiyr принимать дробные значения и изменяться в пределах от 2.9*10Е-39 до 1.7*10Е38 (или 2.9*10'39— 1.7*1038). Объявить переменные типа Real в разделе описания переменных можно следующим образом:
var
a,b,c:real;
К вещественным значениям применимы четыре арифметических действия; полученный при этом результат — также вещественное число. К вещественным значениям применимы также операции сравнения =, о, >, >=, <, <=, дающие логический результат.
С особенностями использования значений типа Real мы уже познакомились при создании программы вычисления корней квадратного уравнения.
Тип Integer
Это целочисленный тип данных. Переменные типа Integer могут принимать значения, представляющие собой целые числа в диапазоне от —32768 до 32767. Объявить переменные типа Integer в разделе описания переменных можно следующим образом;
var
а,b,с:integer;
После объявления переменных в разделе описаний программы эти переменные могут участвовать в выражениях в теле программы. Например:
а:=Ь+с;
Ь:=с-2;
с:=а*Ь;
К целочисленным значениям применимы четыре арифметических действия. Причем если операции сложения (+), вычитания (—) и умно
Глава 1. Введение в Turbo Pascal	27
жения (*) с двумя целыми значениями дадут целочисленный результат, то операция деления (/), примененная к двум целым значениям, даст вещественный результат. Например, значение, полученное в результате вычисления а/b (где А и В — целые числа), можно присвоить переменной только вещественного типа.
Кроме обычных арифметических операций, к целочисленным значениям в Turbo Pascal применимы две специальные операции деления, обозначаемые зарезервированными словами DIV и MOD. Так, результатом действия a div Ь будет целая часть частного от деления А на В. Например:
25 div 2=12;
5 div 7=0;
Результатом выполнения действия a mod b будет остаток от деления А на В (не путать остаток с дробной частью). Например:
25 mod 2=1;
5 mod 7=5;
К целочисленным значениям применимы также операции сравнения =, <>, >, >=, <, <=, дающие логический результат (TRUE или FALSE). Вот пример использования операции сравнения:
if a>b then а:=а+с else а:=а-с;
Тип Char
Char представляет собой символьный тип данных. Область допустимых значений— все символы таблицы ASCII, принятой для персональных компьютеров (см. приложение Е).
Объявить переменные типа Integer в разделе описания переменных можно следующим образом:
var
a,b,c:char;
После объявления переменных в разделе описаний программы эти переменные могут участвовать в выражениях в теле программы. Например:
а:='а';
b:=chr(97);
if c>a,4then ...
В первой строке переменной А присваивается значение типа Char, соответствующее букве “а”. (Когда значения типа Char задаются в программе явно, они “окаймляются” апострофами.)
Во второй строке переменной В присваивается значение типа Char, соответствующее коду 97 из таблицы ASCII (иными словами, той же букве “а”). (Функция Chr преобразует код из таблицы ASCII в соответствующий символ, т.е. в значение типа Char.)
28
Turbo Pascal: учитесь программировать
Условный оператор в третьей строке, если значение переменной С больше значения переменной А, инициирует выполнение какого-то действия. Одно значение типа Char считается больше другого, если код первого значения больше кода второго. Например, выражение 'а'<’Ь' соответствует истине, точно так же, как и 97<98.
Над значениями типа Char возможны все операции сравнения (=, о, >. >=, <, <=). Причем они дают тот же результат, что и при применении к кодам соответствующих символов.
Тип Boolean
Это логический тип данных. Переменные типа Boolean принимают значения TRUE и FALSE (правда и ложь), которые также могут быть представлены в виде двоичных цифр 1 и О соответственно.
Вот как можно объявить переменные типа Boolean в разделе описания переменных:
var
a,b,c:boolean;
После объявления переменных в разделе описаний эти переменные могут участвовать в выражениях в теле программы. Например:
a:=true;
b:=c;
c:=false;
К значениям типа Boolean применимы шесть операторов сравнения и три логических операции.
С операторами сравнения =, о, >, >=, <, <= мы уже знакомы. Особенность их применения к логическим значениям состоит только в том, что значение TRUE (поскольку его также можно представить в виде двоичной цифры 1) считается больше значения FALSE (которое соответствует двоичной цифре О).
Логические операции AND (И — логическое умножение), OR (ИЛИ — логическое сложение), XOR (исключающее ИЛИ), NOT (НЕ— логическое отрицание) подробнее рассматриваются в главе 4. Это же касается и принятых в Turbo Pascal типов данных.
Алфавит и зарезервированные слова
Основными элементами “человеческого” языка (если он обладает письменностью) являются буква, слово, словосочетание, предложение. Что касается языка программирования, аналогичные элементы имеются и в нем, только здесь словосочетание называют выражением, а предложение — оператором. Слова в языке программирования образуются
Глава 1. Введение в Turbo Pascal	29
из определенного набора символов (букв, цифр и специальных знаков). Выражение здесь — группа слов, а оператор — некоторое сочетание выражений и слов. Иначе говоря, символы, слова, выражения и операторы составляют некоторую иерархическую структуру. Основе этой структуры— перечню символов, используемых в языке программирования Turbo Pascal, и посвящен следующий раздел.
Алфавит языка Turbo Pascal
Для записи программы на языке Turbo Pascal, как простейшей, какую мы создали в предыдущем разделе, так и самой сложной, используется набор знаков, включающий буквы, цифры и специальные символы. Речь идет о следующих знаках.
1.	Прописные и строчные буквы латинского алфавита: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
Сюда относится и символ подчеркивания ( _ ). (В языке Turbo Pascal символ подчеркивания считается буквой.)
2.	Десятичные цифры:
О 123456789
3.	Специальные символы:
+ ()-.*,/: = ;>'<#[]$()Л@
К числу специальных символов относится также пробел.
Из специальных символов образуются составные символы, такие как:
:=	присвоить
о	не равно
диапазон значений
(* *)	можно использовать вместо фигурных скобок ({})
<=	меньше или равно
>=	больше или равно
(. .)	можно использовать вместо квадратных скобок ([ ])
римечание
Сказанное* ыше касается тэл* ло зарезервированных слов и идентификаторов (т.е имен переменных, меток, констант, 1роцедур и функций) и не относится к сообщениям предназначенным дня вывода на экран. Примером могут £ нужить программы Rootsl-Roors3 (см. выше), где г указанных элементах широко используются буквы русского алсраьита. Это же Kacaei ся и текста ко^ гментаоиев (см. раздел “Коммента рии" дальше з этой главе;.
30
Turbo Pascal: учитесь программировать
Зарезервированные слова
Речь идет об ограниченном наборе слов, состоящих из букв. Смысл каждого из зарезервированных слов в Turbo Pascal строго фиксирован. Эти слова нельзя использовать для обозначений переменных, констант и т.п. Вот слова, о которых идет речь, представленные в алфавитном порядке:
AND	GOTO	PROGRAM
ASM	IF	RECORD
ARRAY	IMPLEMENTATION	REPEAT
BEGIN	IN	SET
CASE	INHERITED	SHL
CONST	INLINE	SHR
CONSTRUCTOR	INTERFACE	STRING
DESTRUCTOR	LABEL	THEN
DIV	LIBRARY	TO
DO	MOD	TYPE
DOWNTO	NIL	UNIT
ELSE	NOT	UNTIL
END	OBJECT	USES
EXPORTS	OF	VAR
FILE	OR	WHILE
FOR	PACKED	WITH
FUNCTION	PROCEDURE	XOR
Если присмотреться, нетрудно заметить, что некоторые из зарезервированных слов мы уже использовали в программах Roots 1, Roots2 и Roots3 выше. Это следующие слова:
PROGRAM
VAR
BEGIN
END
Первое слово заголовка программы
Слово, открывающее раздел описания переменных
Слово, обозначающее начало раздела операторов (тела программы)3
Слово, завершающее тело программы
Смысл и назначение прочих зарезервированных слов мы будем выяснять по мере использования их в программах. В
В более широком смысле данное слово обозначает начало составного оператора. Раздел операторов программы представляет собой частный случай составного оператора. О составных операторах речь пойдет дальше.
Глава 1. Введение в Turbo Pascal
31
Комментарии
Комментарии— это текстовые строки, вставляемые в текст программы для пояснения функций отдельных ее частей. Подобные комментарии можно вставить и в текст созданной нами выше программы вычисления корней квадратного уравнения. Исходный текст указанной программы (которая теперь называется Roots4) с комментариями содержится в примере 1.4.
Internet
Пример 1.4
program roots4;
var a, b, с, d, е: real;
begin
writein ('Вычисление корней квадратного уравнения');
write ('Введите значение А');
read (а);
write ('Введите значение В');
read (b);
write ('Введите значение С');
read (с);
d:=sgr(b)-4*a*c;
е:=2*а;
{Вычисление и вывод первого корня} write ('xl='), (-b+d)/е;
{Вычисление и вывод второго корня} write ('х2='), (-b-d)/e;
end.
римечание
Ни в коем случае не следует путать комментарии и сооб-1 тения выводимые на экран Первые предназначены д,1Я пояснений в исходном тексте программы (на случа! ели кому-нибудь когда нибудь потребуется в них разби-’ ратьсЯ), а втсрые—. для информирования пользователя
Разумеется, назначение операторов данной программы очевидно и без. комментариев, однако, если исходный текст программы состоит из сотен строк, без комментариев не обойтись. Следует подчеркнуть, что подобные комментарии предназначены исключительно для людей (чтобы им было легче разобраться в исходном тексте программы) и полностью игнорируются компилятором.
В заключение следует сказать, что помимо фигурных скобок для выделения комментариев в тексте программы можно использовать пары символов “круглая скобка — звездочка”. Иными словами, два коммента-
32
Turbo Pascal: учитесь программировать
рия, которые мы только что вставили в текст программы Roots4, могут такж>: выглядеть следующим образом:
(♦Вычисление первого корня*)
(♦Вычисление второго корня*)
Примечание
Если nooie откр1 .шающей фигурной скобки следует знак доллара ($), данное выражение является не комме» гарй-ем, а директивой кок пчлятора. В эт< >м случае после символа $ ечгдуе'*' мнемоника дапективь'.
Кстати, фигурными скобками можно воспользоваться, чтобы сделать для компилятора невидимым какой-либо фрагмент программы. Если некоторый оператор (или группу операторов) требуется “изъять из обращения”, не удаляя их полностью (а вдруг еще понадобятся), указанные операторы можно просто заключить в фигурные скобки, превратив их как бы в комментарий. Мы уже знаем, что комментарии полностью игнорируются компилятором.
Переменные
В каждой программе для вычисления нужных результатов широко используются переменные. Что такое переменная? Это, по сути, некоторая область в памяти компьютера, для которой в данной программе предусмотрено уникальное имя и содержимое которой в ходе работы программы может изменяться (именно поэтому указанное понятие получило такое название). Когда переменной присваивается новое значение, ее старое значение теряется. Все используемые в программе переменные в языке программирования Turbo Pascal должны быть объявл е-ны в разделе описания переменных. (Подробнее о структуре программы и о месте в этой структуре раздела описания переменных речь пойдет в Приложении Г.) При этом устанавливается не только сам факт существования переменной, но и задается ее тип, определяющий, какие значения может принимать данная переменная. В последней версии программы вычисления корней квадратного уравнения (Roots4) раздел описания переменных выглядел следующим образом:
var а, Ь, с, d, е: real;
Здесь объявляются пять переменных типа Real. Что собой представляет этот тип и какие еще существуют типы, мы уже выяснили в разделе “О типах данных” в этой главе выше. Вот еще пример раздела описания переменных:
var
SqMeters, {исходная величина - размер ткани в кв. метрах)
SqYards :real;{вычисляемая величина - размер ткани в кв. ярдах}
2-2016
Глава 1. Введение в Turbo Pascal
33
Здесь задаются две переменные, обе типа Real. Мы уже знаем, что текст в фигурных скобках— это комментарии, которые игнорируются компилятором и предназначены исключительно для легкости понимания исходного текста программы. Судя по идентификаторам переменных, это фрагмент программы, переводящей квадратные метры в квадратные ярды, что подтверждают и комментарии.
Вероятно, читатель уже понял, что раздел описания переменных может содержать несколько строк, каждая из которых разделена двое-точием (:). В правой части такой строки содержится идентификатор переменной (или перечень идентификаторов, разделенных запятыми), а в правой части указан тип данных, которому принадлежит данная переменная (переменные). Каждая строка в разделе описания переменных завершается символом “точка с запятой” (;). Зарезервированное слово VAR присутствует в тексте программы в единственном экземпляре; число строк описания переменных, следующих за словом VAR, не ограничивается.
Константы
Предположим, значение переменной С в программе Roots4 имеет некоторое постоянное значение, например 5.5. Разумеется, вместо переменной С в программе можно использовать указанное фиксированное значение (число). Но что если наше квадратное уравнение когда-нибудь потребуется решить с другим значением коэффициента С? В этом случае данное значение пришлось бы изменять по всему тексту программы (в программе Roots4 — всего дважды, но в других программах, возможно, десятки и сотни раз).
Можно оставить все как было и фиксированное значение для С (5.5) вводить каждый раз с клавиатуры вместе со значениями двух других переменных А и В. Можно также в раздел операторов (в тело программы) добавить оператор присваивания с: =5.5. Однако С в данном случае, по существу, переменной не является и ее значение должно быть постоянным . -при каждом выполнении программы, независимо от входных данных.
Предлагая наилучшее решение, Turbo Pascal позволяет вводить в программы объекты, внешне похожие на переменные, но значения которых, в отличие от переменных, не изменяются в ходе работы программы. Подобные объекты называются константами. Наша программа (которую теперь назовем Roots5) с коэффициентом С квадратного уравнения, заданным в качестве константы, содержится в примере 1.5.
34
Turbo Pascal: учитесь программировать
Пример 1.5
program roots5;
const c=5.5
var a, b, d, e: real;
begin
writein ('Вычисление корней квадратного уравнения');
write ('Введите значение А');
read (а);
write ('Введите значение В');
read (b);
d:=sqrt(sqr(b)-4*a*c);
е:=2*а;
{Вычисление и вывод первого корня} write ('xl='), (-b+d)/e;
{Вычисление и вывод второго корня} write ('х2='), (-b-d)/е;
end.
В программе появился новый структурный элемент — раздел описания констант, в котором задается значение константы С. Этот раздел начинается со слова CONST, входящего в число зарезервированных слов, имеющих специальное значение (перечень зарезервированных в Turbo Pascal слов см. выше). Подробнее о структуре программы и о месте в этой структуре раздела описания констант речь пойдет в Приложении Г.
Преимущество задания какого-либо постоянного значения в виде константы, а не переменной, в том, что при этом блокируется возможность его случайного изменения (например, в результате ошибки программиста). В Turbo Pascal исключаются операторы присваивания, в правой части которых содержится идентификатор константы. Так если С— константа, то появление в теле программы строки наподобие С: = хххх (где хххх— некоторое значение) побудит компилятор выдать соответствующее сообщение об ошибке.
Приведем пример раздела описания констант:
const
number = 93;
max = 10;
min = -max;
message = 'Ошибка';
quantity = 2.33E11;
Первым двум константам в этом разделе присваиваются значения, представляющие собой целые числа, третьей (min)— значение второй константы со знаком “минус”, четвертой— значение, представляющее собой текстовое сообщение. Наконец, пятая константа здесь будет содержать вещественное число, представленное с плавающей точкой.
Г лава 1. Введение в Т urbo Pascal	35
2*
Бросается в глаза, что при объявлении констант не указывается тип данных. Как же в этом случае компилятор трактует значение той или иной переменной? Дело в том, что каждой константе с самого начала (в разделе объявления констант в начале программы) присваивается фиксированное значение, которое в программе (при использовании) изменяться не может. Так вот, тип каждой константы однозначно определяется по ее значению.
36
Turbo Pascal: учитесь программировать
В этой главе...________________
	Оператор присваивания
	Составной оператор
	Условные операторы
	Операторы цикла
	Оператор перехода и пустой оператор
Операторы языка программирования Turbo Pascal, представленные в нужной последовательности, позволяют реализовать алгоритм решения задачи. При этом каждый из операторов выполняет некоторое действие над данными.
Операторы Turbo Pascal подразделяются на две группы: простые и структурированные. Простые операторы не содержат в себе других операторов: структурированные, включают в себя другие операторы — как простые, так и структурированные. (В последнем случае в состав операторов могут входить и другие операторы, иными словами, возможно множество уровней вложенности операторов.)
К простым операторам относятся оператор присваивания, оператор перехода и пустой оператор, а к структурированным — составной оператор, условные операторы (IF и CASE) и операторы цикла (WHILE, REPEAT и FOR).
Оператор присваивания
С оператором присваивания (самым простым, но наиболее используемым) мы познакомились в предыдущей главе, когда создавали нашу первую программу. Нам уже известно, что знак присваивания (:=) делит этот оператор на две части. В правой части представлено выражение, состоящее из идентификаторов констант, переменных, функций и знаков операций, которое необходимо вычислить. После вычисления полученное значение присваивается переменной, указанной в левой части оператора. При этом тип переменной должен быть совместим с типом вычисленного выражения.
Вот примеры операторов присваивания:
а:=Ь+с;
а: =' b' ;
new:=234;
x:=true;
Составной оператор
Составной оператор представляет собой последовательность некоторых операторов, выполняющихся в том порядке, в каком они представлены в тексте программы. Зарезервированные слова BEGIN и END являются так называемыми операторными скобками, в которые заключены операторы, входящие в составной оператор. Когда, в зависимости от определенного условия, требуется обеспечить последовательное выполнение некоторого набора операторов, без составного оператора не обойтись.
38
Turbo Pascal: учитесь программировать
Составной оператор имеет вид
begin SI; S2; .. Sn end;
Здесь Sl-Sn— операторы, образующие составной оператор; зарезервированные слова BEGIN и END — операторные скобки. Частный случай составного оператора— раздел операторов (или тело) любой программы на Turbo Pascal. Составной оператор может включать другие составные операторы (т.е. составным может быть любой из операторов Sl-Sn), причем допускается любой уровень вложенности.
Условные операторы
Если в программе, в зависимости от некоторого условия, требуется выбрать тот или иной вариант действий, можно воспользоваться одним из условных операторов. В Turbo Pascal предусмотрены два условных оператора — IF и CASE.
Оператор IF
Оператор IF имеет вид:
if р then al else а2
При выполнении этого оператора сначала вычисляется некоторое логическое выражение Р (условие), в случае истинности которого выполняется оператор А1, а в случае ложности— оператор А2. Использованные здесь ключевые слова IF, THEN и ELSE имеют смысл если, то и иначе соответственно.
Возможен сокращенный вариант оператора IF:
if р then al
Здесь, если условие Р истинно, выполняется оператор А1. Если же условие Р ложно, управление просто передается следующему (за оператором IF) оператору в программе. Можно сказать, что первый вариант оператора IF осуществляет выбор между двумя действиями, а второй — между действием и отсутствием действия.
Что представляет собой условие? В принципе, в этом качестве может быть просто использовано логическое значение TRUE или FALSE, либо константа логического типа, имеющая одно из этих значений. Ошибка здесь зафиксирована не будет. Однако в этом случае теряется смысл применения оператора IF, поскольку заранее известно, какое действие будет выполнено. Например, если D — константа типа Boolean (описанная в разделе объявления констант), имеющая значение TRUE, то использовать оператор IF
if d then c:=a+b else c:=a-b;
бессмысленно, поскольку заведомо известно, какое действие будет выполнено, и вместо условного оператора следует просто записать
с:=а+Ь;
Глава 2. Операторы
39
Поэтому, как правило, в качестве условия используется переменная логического типа (типа Boolean) либо один из операторов сравнения. Сравнивать между собой числа и другие значения в Turbo Pascal можно с помощью шести операторов. Речь идет об операторах > (больше), < (меньше), = (равно), о (не равно), >= (больше или равно) и <= (меньше или равно). Результат сравнения всегда представляет собой значение логического типа. Так, результатом сравнения 77>63 будет TRUE, а результатом сравнения 82<47 — FALSE.
В условии также широко могут использоваться три логических оператора: NOT, AND и OR. Например, выражение xl and х2 будет иметь значение TRUE, если XI и Х2 принадлежат логическому типу и оба равны TRUE.
Вот примеры операторов IF, которые могут встретиться в программах: if х>у then z:=x/2 else z:=y+2 if a and b>c then d:=a+b else d:=c
Во многих программах, в зависимости от некоторого условия, часто требуется выполнить не одно, а последовательность действий. Однако оператор IF в Turbo Pascal обеспечивает выполнение единственного оператора, присутствующего после зарезервированного слова THEN или ELSE. Выйти из положения можно, применив составные операторы. Оператор IF с составными операторами выглядит так:
if р then begin s2; s2; . ,sN end
else begin vx; v2; ,.vN end;
Здесь S[—Sn и	VN — некоторые операторы, образующие составные
операторы.
Turbo Pascal допускает вложенность операторов IF. Рассмотрим пример. Если некоторая переменная X положительна, требуется извлечь из нее квадратный корень, если отрицательна — возвести в квадрат, а если равна нулю— прибавить к ней 2. Эту задачу можно реализовать следующим образом:
if х>0 then x:=sqrt(x) else if x<0 then x:=sqr(x) else x:=x+2;
(Функции возведения в квадрат (Sqr) и извлечения квадратного корня (Sqrt) уже нам знакомы по программе вычисления корней квадратного уравнения в главе 1.)
При вкладывании операторов IF один в другой может возникнуть синтаксическая неоднозначность. В самом деле, к какому из двух ключевых слов IF относится ключевое слово ELSE в операторе: if х then if у then sx
else s2
Варианты можно представить, введя операторные скобки (пары зарезервированных слов BEGIN..END).
Первый вариант:
40
Turbo Pascal: учитесь программ! ipoearr
if x then
begin
if у then sx
end
else s2
Второй вариант:
if x then
begin
if у then Sj
else s2 end;
Какой из двух вариантов изберет компилятор Turbo Pascal? Все очень просто. Компилятор ассоциирует ключевое слово ELSE с ближайшим ключевым словом IF, расположенным в тексте программы выше и еще не связанным с иным ключевым словом ELSE, в нашем случае действенным окажется второй вариант. Если же потребуется реализовать первый вариант, можно воспользоваться операторными скобками.
В заключение рассмотрим пример программы. Предположим, даны три числа. Требуется возвести в квадрат те из них, значения которых неотрицательны. Текст соответствующей программы, введенный в окне редактора Turbo Pascal 7.0, содержится в примере 2.1 (рис. 2.1). Здесь же (в окне Output) можно видеть результаты работы этой программы.
Пример 2.1
cile i dit Search Run
program example;
van a.b.c:real; begin
read (a);
if a>=0 then writein (a);
a:=a*a;
end.
Тё lebug Tools options vnnciow help J- — 	-	---- — - Output
OOOOOCOOOtTCl
01
read (b);
if b>=0 then writein (b);
b:=b*b;
read (c);
if c>=0 then c:=c*c; writein (c)
/OOOOOOOOE :-01
9. OOOOOOOOGOE-bW
-4
-t.OOOOOOOOOOE+OO
8
6.4000000000E<-01
3
9

Рис. 2.1. Текст программы и результаты
На рисунке виден исходный текст программы, а также результаты ее работы в окне Output. Содержимое окна Output свидетельствует, что наша программа (имеющая имя Example) запускалась несколько раз. При
Глава 2. Операторы
41
последнем запуске были заданы числа 3, -5 и 8. Как и требовалось, первое и третье числа были возведены в квадрат, а второе оставлено без изменения, поскольку оно отрицательно. Так как задаваемые числа присваивались переменным типа Real, полученные результаты (9, —5 и 64) принадлежат тому же типу. Соответственно они представлены в знакомом нам формате с плавающей точкой.
Оператор CASE
Рассмотренный выше оператор IF позволяет осуществить выбор одной из двух альтернатив. Но что если число вариантов нужно иметь больше? Например, если требуется согласно номерам дней недели отображать на экране их названия? Многие начинающие программисты для решения подобной задачи предпочтут воспользоваться последовательностью операторов IF:
if х=1 then write if x=2 then write if x=3 then write if x=4 then write if x=5 then write if x=6 then write if x=7 then write
(понедельник);
(вторник);
(среда);
(четверг);
(пятница);
(суббота);
(воскресенье);
Однако такой подход затрудняет понимание исходного текста программы, поскольку сразу неочевидно, что здесь будет выполнен один и только один из семи операторов IF. Кроме того, такая конструкция малоэффективна, поскольку при этом условие придется проверять во всех семи операторах IF и это неизбежно увеличит время выполнения программы.
Целесообразнее воспользоваться вложенным оператором IF. Один вложенный оператор часто будет выполняться быстрее последователь ности из нескольких операторов IF, поскольку при совпадении первого условия управление сразу передается следующему (после вложенного) оператору, без проверки оставшихся условий.
Эквивалентный оператор IF с несколькими уровнями вложения может выглядеть так:
if х=1
then write (понедельник)
else if х-2’’
then write (вторник)
else if x=3
then write (среда)
else if x=4
then write (четверг)
else if x=5
then write (пятница)
42
Turbo Pascal: учитесь программировать
else if x=6
then write (суббота)
else if x=7
then write (воскресенье);
Очевидно, что данная конструкция чересчур громоздка. (Считается, что в операторе IF допустимы не более двух-трех уровней вложения.) Здесь всего семь альтернатив, а что если вариантов выбора потребуется иметь несколько десятков? Применение оператора IF в этом случае крайне неудобно. Выйти из положения позволяет оператор CASE.
Оператор CASE имеет вид.
case р of
a:Sj;
b:s2;
n:sn;
else
end;
При выполнении этого оператора сначала вычисляется некоторое выражение Р, называемое селектором выбора, а затем, в зависимости от полученного значения (если оно равно одной из констант А, В, ..., N, которые называются константами выбора4), выполняется один из операторов: S], S2, ..., SN, помеченный соответствующей константой. Причем каждый из этих операторов может быть составным. Операторы Sj, S2, .... SNотделяются один от другого точками с запятой. Значение селектора выбора в операторе CASE может повторяться, однако в этом случае будет выполнена только первая подходящая ветвь, а затем управление передается следующему (после CASE) оператору в программе.
Если значение выражения Р не совпадает ни с одной из констант выбора, выполняется оператор S^,, содержащийся после ключевого слова ELSE, причем ветвь ELSE в операторе CASE необязательна. Использованные здесь зарезервированные слова CASE, OF, ELSE и END имеют смысл вариант, из, иначе и конец соответственно.
Выражение, играющее роль селектора выбора, должно принадлежать порядковому типу данных (т.е. типу, имеющему конечное число значений). К порядковым относятся, например, типы данных Integer, Boolean и Char. Однако тип Real порядковым не является. (В самом деле, если бы мы попытались перечислить все вещественные числа, лежащие в диапазоне между 5.1 и 5.2, например, нам пришлось бы упомянуть не только числа 5.11; 5.12; 5.13..., но и 5.111; 5.112; 5.113..., а также
4 Используемые в операторе CASE константы выбора не являются метками, хотя внешне они очень похожи на метки. На константы выбора нельзя ссылаться с помощью операторов перехода и они не перечислены в разделе описания меток. Об операторах перехода и метках речь пойдет в этой главе дальше.
Глава 2. Операторы	43
5.1111; 5.1112; 5.1113... и многие другие числа, с еще большим числом дробных разрядов.)
Кроме одиночных констант, в вариантах оператора CASE могут использоваться диапазоны значений и списки (представленные через запятую):
case х of
1..5: Si
2, 3, 8:s2
4, 6, 9..13:s3 *
else
s4
end;
Так в этом примере оператор S3 будет выполнен, если переменная X имеет одно из значений: 4,6,9, 10, 11, 12, 13.
Вернемся теперь к предыдущему примеру вложенного оператора IF (отображение названий дней недели). Попробуем реализовать эту задачу с помощью оператора CASE. Вот как это должно выглядеть:
case х of
l:write ('понедельник');
2:write ('вторник');
3:write ('среда');
4:wr ite ('четверг');
5:write ('пятница');
6:write ('суббота');
7:write ('воскресенье');
end;
В заключение попробуем создать небольшую программу, в которой бы использовался оператор CASE. Предположим, требуется определить, равны ли два заданные числа, а затем вывести соответствующее текстовое сообщение. Текст программы Matching, введенный в окне редактора Turbo Pascal 7.0, содержится в примере 2.2 (рис. 2.2). Здесь же (в окне Output) можно видеть результаты работы этой программы.
Ни текст программы, ни вывод на экран здесь в особых объяснениях не нуждаются. Следует только сказать, что первый оператор WriteLn (сразу после BEGIN) потребовался для того, чтобы вставлять пустые строки между данными ввода-вывода для различных запусков программы.
Нетрудно прийти к выводу, что это не самый типичный пример использования оператора CASE. Здесь всего два варианта выбора, поэтому вполне можно было бы использовать оператор IF. Впрочем, это не очень упростило бы данную программу.
44
Turbo Pascal: учитесь программировал
I
Пример 2.2
Int* r,,c t
Рис. 2.2. Программа запускалась пять раз и как будто работает правильно
Операторы цикла
Для многократного повторения одних и тех же действий в Turbo Pascal предусмотрены три оператора цикла. Если число повторений цикла (или итераций) заранее неизвестно, однако известно условие завершения цикла, в таких случаях применяются операторы REPEAT и WHILE. Если же число повторений известно, то применяется оператор FOR.
Оператор WHILE
Оператор цикла WHILE, известный как оператор цикла с предусловием, имеет вид:
while р do s;
При выполнении этого оператора сначала вычисляется некоторое логическое выражение Р (условие), принадлежащее типу Boolean, в случае истинности которого выполняется оператор S (являющийся, как правило, составным оператором). После этого вычисление условия, его проверка и выполнение оператора S повторяются до тех пор, пока выражение Р не становится равным FALSE. Затем управление передается следующему (после WHILE) оператору в программе. Использованные здесь ключевые слова WHILE и DO имеют смысл пока и выполнять соответственно.
Глава 2. Операторы
45
Если условие Р равно FALSE с самого начала, оператор S, который называется телом цикла, не выполнится ни разу. Если условие Р тождественно TRUE (while true do s), цикл будет бесконечным. Очевидно, для того чтобы тело цикла выполнилось несколько раз (чтобы количество циклов было больше нуля, но меньше бесконечности), условие должно каждый раз преобразовываться в теле цикла.
Рассмотрим пару примеров использования оператора WHILE. Предположим, даны числа Хи У (Х> 1). Требуется получить все члены бесконечной последовательности X, Х~, X3..которые меньше Y. Исходный
текст программы содержится в примере 2.3 (рис. 2.3). Здесь же в окн< Output представлены вычисленные члены последовательности для заданных чисел Хи Y.
Пример 2.3
I File tait Search RunCoepile Debus* tools Options Ti lo.. ..₽>
program sequence, var x,y,z:real; begin
readfx,v);
z:=x;
while z<v do begin writeln(z); z:=z«x end end.
\ЙОЙДг“(*1	------ Output - •
lurbo Pascal Version 7.0 Copyright (c) 1983 92 Bor 3 A 00 3.0000000000E-00 9.00OOOOflO00E«OO 2.7O0O00O000E-01 8.1000000000E-01 2.43000O0000E-02
| Fl Help П Scrol l 110 Menu
Рис. 2.3. Программа вычисления последовательности степеней
Копия экрана демонстрирует исходный текст программы Sequence и ее вывод на экран. Здесь в качестве значений X и У заданы числа 3 и 400 соответственно и в результате, согласно условиям задачи, вычислены члены последовательности: 3 (З1), 9 (З2), 27 (З3), 81 (З4) и 243 (З5), представлен ные в экспоненциальном формате, поскольку это значения типа Real.
В качестве второго примера попробуем вычислить число л с помо щью формулы Грегори: л/4=1-1 /3+1 /5-1 /7+...5. Причем вычисления будем производить только до тех пор, пока абсолютная величина оче
5Правило формирования этой последовательности будет понятнее, если ее пер вый член представить в виде 1 /1.
46
Turbo Pascal: учитесь программировать
редно.о члена ряда 1-1/3+1/5-1/7+... не станет меньше чем 0.5*10 7 0сХ°Днь,и текст соответствующей программы содержится в примере 2 4 (рис. 2.4).
Пример 2.4
ргоогви pi; const с=0 5Е-7; var о.sub:real: sign.integer; n:longint; I oeflin wri teln; sign:’ 1; sub:=1.0. a • ’1 . 0; n:"l; while abs(a)>c do begin a:*sion/(2-n-l). suB:=suB-a; sign:»- sign: n:-n*l; end. sub:- 4“sub. wri tel’Pi-’.sub); iend		 —	Output — Turbo Раче	Version / M Cnpvr	T 1983 Pj 3 14139?8?гДГ*08-в I
шяотякюампцвг	ВСЦ	
Рис. 2.4. Программа вычисления числа /г
В этой программе (с именем Pi) константа С определяет точность выделения числа л; переменная Л содержит значение очередного члена яда 1-1/3+1/5-1/7+...; значение переменной Sum равно текущей умме вычисленных членов ряда (т е. приближенному значению числа ); переменная Sign содержит знак очередного члена ряда; переменная N •ужит для нумерации членов ряда (и итераций оператора WHILE).
Возможно, читатель обратил внимание, что переменная N (номер 'вредного члена ряда 1-1/3+1/5-1/7+... и цикла оператора WHILE) л.явлепа с неизвестным нам пока типом данных Longlnt. Это целочис-1е|П1Ыи тип данных, о сличающийся от типа Integer только диапазоном |>г,У<’Тимых значений (переменные типа Longlnt могут принимать зна-"Ния н пределах -2 147483648 — 2 1 47483647. в то время как перемен
Integer--32768 — 32767) 11ервоначалык> была предприняв п<>-
||4|ка объявить эту переменш’Ю с типом Integer, однако обнаружило* ъ. " ДЛЯ ВЫЧИГДгНИЯ СУММЫ членов ряда 1 — 1/3+1/5—1 /7+	до 1еХ Пор
лбе<)дя>т пая величина очередного члена не станет меньше О гтЕ 7, р,Г,У"1ся 10000001 циклов оператора WHILE. И поскольку лиана юн ,|j4'-hhh. дощч 1ИМЫ.Х ДЛЯ типа Integer, гораздо уже. происходило
Глава 2. Операторы
47
“зацикливание” программы6. О типе Longlnt и прочих целочисленных типах подробнее мы будем говорить в главе 4).
Первый оператор (WriteLn) в теле программы Pi служит для перевода курсора в окне Output в начало новой строки. Операторы 1-5 присваивают переменным Sign, Sum, А и N начальные значения. Далее следует оператор цикла WHILE, условие которого Abs(А)>С служит для проверки7, не стала ли уже абсолютная величина очередного члена ряда 1— 1/3+1/5-1/7+... меньше значения константы С (С=0,5*1СГ7).
Тело цикла WHILE состоит из четырех операторов. Первый (a:=Sign/(2*n+l)) вычисляет значение очередного члена ряда, второй (Sum:=Sum+A) прибавляет вычисленное значение очередного члена ряда к сумме предыдущих членов, третий (Signs =-Sign) меняет знак следующего члена ряда на противоположный (по сравнению с предыдущим). Наконец, последний оператор тела цикла (N:=N=1) служит для вычисления номера очередного члена ряда (и номера очередной итерации оператора WHILE).
После оператора WHILE в программе имеются еще два оператора. Первый из них (Sum:=4*Sum) умножает вычисленную сумму членов ряда на 4 (поскольку, как указывалось вначале, эта сумма приближается к четверти значения числа л). Второй оператор (Write('Pi='), Sum) выводит вычисленное значение числа л на экран.
Оператор REPEAT
Оператор цикла REPEAT, известный как оператор цикла с постусло вием, имеет вид:
repeat s until р;
При выполнении этого оператора сначала выполняется тело цикла (S), затем вычисляется некоторое логическое выражение Р (условие), принадлежащее типу Boolean, в случае ложности которого вновь выполняется тело цикла. Затем выполнение тела цикла, вычисление условия Р и его проверка повторяются до тех пор, пока выражение Р не становится равным TRUE. После этого управление передается следующему (за REPEAT) оператору в программе. Использованные здесь зарезервированные слова REPEAT и UNTIL имеют смысл повторять и пока не соответственно.
6 Как это удалось обнаружить? Для этого оказалось достаточно ввести (временно, в составной оператор цикла WHILE еще один оператор: Write (п) В результате номер каждого очередного цикла стал выводиться на экран и это позволило уви деть, что временами данное значение становится отрицательным, т.е. после то го, как N принимает значение 32767 (наибольшее), при прибавлении очередной еди ницы при следующей итерации эта переменная становится равной —32768.
7 Функция ABS(A) вычисляет абсолютную величину числа А.
48	Turbo Pascal: учитесь программировал
Оператор цикла REPEAT отличается от оператора WHI1 К, во-первых, ем, что здесь условие проверяется после выполнения тела цикла. Иными словами, гарантируется хотя бы однократное его выполнение. Во-вторых, оператор REPEAT выполняется до тех пор, пока условие равно FALSE, и управление передается следующему (за REPEAT) оператору, когда условие становится равным TRUE (для оператора WHILE имеет место обратная зависимость).
Даже если условие Р равно TRUE с самого начала, тело цикла выполнится хотя бы раз. Если условие Р тождественно FALSE (repeat s until false), цикл будет бесконечным.
Для того чтобы понять разницу между операторами цикла WHILE и REPEAT, рассмотрим соответствующие фрагменты программ, вычисляющих степени числа 3 в диапазоне между 1 и 300.
Цикл WHILE	Цикл REPEAT
a:=l;	a:=l;
while a<300 do	repeat
begin	writein (a);
writein (a);	a:=a*3
a:=a*3	until a>=300
end;	
Прежде всего бросается в глаза, что условия повторения цикла для двух случаев противоположны. Это объясняется тем, что в операторе WHILE цикл выполняется, пока условие не примет значение FALSE, а в операторе REPEAT — пока условие не примет значение TRUE.
Также следует обратить внимание, что тело цикла REPEAT не требуется заключать в операторные скобки BEGIN..END. Если в операторе WHILE после ключевого слова DO выполняется единственный оператор (и если требуется циклически выполнять несколько действий, приходится несколько операторов объединять в составной оператор), то в операторе REPEAT между ключевыми словами REPEAT и UNTIL можно ввести любое количество операторов, без необходимости заключать их в операторные скобки.
Наконец, внимательный читатель может заметить, что в операторе REPEAT после последнего оператора в теле цикла нет точки с запятой. Это еще одна особенность оператора REPEAT — перед ключевым словом UNTIL точка с запятой необязательна.
В заключение рассмотрим пример программы. Попробуем создать программу вычисления квадратного корня для заданного неотрицательного числа X. Представим себе бесконечный ряд , А^, А3,....
где i=2, 3, 4,...
Глава 2, Операторы
49
lr 2 A
A2=- 1.5 + —— = 1.4166666,
2l	1.5 I
Дело в том, что разница между очередным членом этого ряда и вели чиной корня квадратного от числа X, по мере увеличения числа i, стано вится все меньше.
Предположим, требуется определить корень квадратный от 2 (который, как известно, приблизительно равен 1,4142135). Попробуем вычислить несколько первых членов ряда А,, А3,...:
л 2 + 1	- с
А. =— = 1.5,
Л2 1
z 2
А3=—I 1.41666666 +
21
Тенденция очевидна. Как и указывалось, величина At становится все ближе значению корня квадратного от двух.
Исходный текст соответствующей программы содержится в примере 2.5 (рис. 2.5).
2 1.41666666
= 1.4142156.
iternet
Пример 2.5
Ul
		хШ/ ^-Tool &~ ~ Options ' Window Holo -	
		\ииидик JLXrHSu program root; var a.xrreal; begin writein; write(chr(251));	“i  1				— ~tpi 42 = 1 4142.135624E-O0 <3 = 1.73205081001-00	Outpi
	read(x); a:=(x*l)/2; repeat a:=0.5“(a*x/a) until abs(sqr(a)-x)<0.000001; writelnl'=',a) end.	44 = 2.00000009291*00 45 = 2.23606797751*00 45.2 = 2.28035085021*00 46 = 2.44948974281-00 47 = 2.645/5131111-08	
 ffilp	&.ОТ1 Hi М..„и		-	
Рис. 2.5. Вычислить квадратный корень — проще простого
Программа запускалась несколько раз и были вычислены квадратные корни для различных чисел. Интересно, что вычисленное значение корня квадратного из 4 не равно строго 2. Это наглядно демонстрирует, что точность данного метода приблизительна.
50
Turbo Pascal: учитесь программировать
В этой программе значение переменной X— это число, из которого требуется извлечь квадратный корень, а значение переменной А равно вычисленной величине очередного члена ряда.
Первый оператор программы (WriteLn) переводит курсор к началу новой строки. Второй оператор (Write(Chr(251))) отображает на экране имвол радикала (причем функция (Chr( 251 (преобразует порядковый номер символа (251) из таблицы ASCII в соответствующий символ). Третий оператор служит для ввода числа, из которого предстоит извлечь юрень, а четвертый вычисляет значение первого члена ряда. Далее слезет оператор цикла REPEAT, назначение которого — вычислять значе-1ия членов ряда, начиная со второго и до тех пор, пока не будет выполнено условие завершения цикла. Условие становится равным TRUE, когда абсолютная величина разницы между квадратом значения очередного члена ряда и значением переменной X станет меньше 0.000001. На этом цикл завершается.
Наконец, последний оператор программы (WriteLn (' = ', а)) отображает на экране символ “равно” (=), а затем — вычисленное значение квадратного корпя от заданного числа.
В качестве домашнего задания читатели могут попробовать создать трограмму вычисления числа л, как в предыдущем разделе, но с исполь-юванием оператора цикла REPEAT взамен WHILE.
Оператор FOR
Оператор цикла FOR, известный как оператор цикла с параметром, имеет вид:
for i=a to b do s;
При выполнении этого оператора сначала вычисляется некоторое начальное значение А, которое присваивается переменной I, называемой параметром цикла. Затем вычисляется конечное значение В и проверяется, имеет ли место равенство 1=В. Если равенства нет, выполняется оператор S, который может быть составным, и переменная I увеличивается на единицу. После этого проверка (не равен ли параметр конечному значению), выполнение оператора S и увеличение переменной I на единицу выполняются циклически до тех пор, пока не наступает равенство 1=В. Параметр цикла I, а также начальное и конечное значения (А и В) могут принадлежать любому порядковому типу (например, Integer или Char). (Но при этом все они должны быть одного типа.) Если начальное значение превышает или равно конечному значению с самого начала, оператор S не выполнится ни разу.
Использованные здесь зарезервированные слова FOR, ТО и DO имеют смысл от, Зои выполнять соответственно.
ча 2. Операторы
Оператор цикла FOR имеет такие особенности:
	в теле цикла запрещается явно изменять значение параметра цикла (с помощью оператора присваивания, например);
	по завершении работы оператора цикла FOR, значение параметра (I) считается неопределенным.
Возможна и другая форма оператора цикла с параметром:
for i=a downto b do s;
Здесь, чтобы выполнялся оператор S, начальное значение А должно превышать конечное значение В. Кроме того, в этом случае параметр I с каждым циклом уменьшается на единицу, пока не становится равным конечному значению В.
Оператор цикла с параметром следует использовать тогда, когда заранее точно известно, сколько раз должно быть выполнено тело цикла.
Вот примеры оператора цикла с параметром:
for i:=l to 5 do x:=sqr(x);
for i:=z downto a do write (i);
В первом примере значение переменной X возводится в квадрат, затем полученная величина присваивается переменной X— и так пять раз.
Во втором примере оператор цикла с параметром использован для вывода букв латинского алфавита в обратном порядке (с z по а). Дело в том, что тип Char является порядковым, причем буквы начала алфавита (как значения типа Char) считаются меньше букв, взятых в конце алфавита. Не будет, например, ошибочным неравенство А<В.
Для того чтобы понять разницу между операторами цикла WHILE и FOR, рассмотрим соответствующие фрагменты программ, выводящие на экран пустые строки.
Цикл WHILE	Цикл FOR
line:=l	for line=l to n do
while line<n do begin writein; line:= line+1 end;	writein
Если переменная Line объявлена (в разделе описания переменных) как принадлежащая типу Integer, оператор FOR выведет на экран N пус тых строк. Реализация задачи с помощью оператора FOR выглядит проще, поскольку здесь нет нужды в операторах присваивания line:=l и line:= line+1.
Рассмотрим программу, выводящую на экран все символы таблицы ASCII. Исходный текст этой программы содержится в примере 2.6 (рис. 2.6). Здесь же (в окне Output) можно видеть вывод этой программь на экран.
52
Turbo Pascal: учитесь программировать
Пример 2.6.
Рис. 2.6. Простая программа и неприглядный вывод на жран
Как известно, таблица ASCII, принятая для персональных компьютеров, включает 256 кодов (с О по 255). Соответственно в нашей про-рамме имеется оператор цикла FOR, значение параметра которого по-ледовательно принимает те же значения. Тело цикла содержит два шератора: A:=Chr(I) и Write (А). Первый присваивает переменной (типа har) значение, соответствующее очередному символу из таблицы ASCII функция Chr преобразует числовой код в соответствующий символ), а второй выводит этот символ на экран. В данном случае вместо двух вполне можно было бы обойтись единственным оператором vrite(Chr(i)).
Требовательный читатель может заметить, что такую программу । рудно признать совершенной. Что следовало бы сделать, чтобы симво-ы на экран выводились не в одну строку, а более упорядоченно. Что ж, в этом есть доля истины. Программу, выводящую символы и коды таблицы ASCII на экран (именно в виде таблицы), мы создадим в следую-цем разделе.
Вложенные циклы
В программах на Turbo Pascal возможно использование вложенных 'иклов. Это подразумевает, что существует внешний цикл и один или •есколько внутренних циклов. Каждое повторение внешнего цикла оз-1ачает завершение всех внутренних циклов; при этом всем выражени
лава 2. Операторы
53
ям, которые управляют внутренними циклами, вновь присваиваются начальные значения.
Рассмотрим программу, исходный текст которой содержится в примере 2.7 (рис. 2.7). Здесь же в окне Output можно видеть вывод на экран этой программы.
Internet
Пример 2.7
-!!
lurbo Pascal Version 7.0 Copyric
I Цикли	I J
1
1
2
2
2
1
file Slit Search ftun	Qrfsua Sols Nations
-------------:------\мсидс< x-’AStmi miuhkiw-1-1---------------- — 3
program NestLoop; oar i,j:integer; begin writelnl'Циклы':6,'I :10,'J’:3); writelnt’ -----------------------
for i:=1 to 4 do begin {начцро внешнего цикла!
writelnt'Внешний':8,I:8); for j:"1 to i do writelnt'Внутренний':13,I:3,J:3); end {конец внешнего цикла! end.
Внешний
Внутренний
Внешний
Внутренний
Вну1 реннин Внешний
Внутренний Buy I реннин Внутренний
Внешний
Внутренний
Внутренний Внутренний Внутренний
1
2
з э
3
1
2 3
4
4
4
4
1.
2
3
4
Рис. 2.7. To, что выводит на жран эта программа, позволяет лучше понять смысл вложенных циклов
Данная программа содержит два оператора цикла с параметром, вложенные один в другой. С каждым повторением внешнего цикла (таких повторений четыре) количество итераций внутреннего цикла увеличивается на единицу (с 1 до 4). Программа выводит на экран таблицу, в которой фиксируются количество повторений внешнего (словом Внешний) и внутреннего (словом Внутренний) циклов, а также отображаются порядковые номера всех итераций (как внешних, так и внутренних).
• Две переменные (I и J) типа Integer представляют собой управляющие параметры для внешнего и внутреннего циклов соответственно.
Первый оператор программы (Wr iteLn (' Циклы': 6, ’ I': 10, ' J': 3)) выводит на экран “шапку” будущей таблицы. Параметр 'Циклы': 6 функции WriteLn означает, что после вывода слова “Циклы” курсор должен сдвинуться на шесть позиций от края экрана. А параметр 'I': 10 означает, что после вывода символа “I” курсор должен сдвинуться на десять позиций от конца слова “символы” (или на 16 позиций от края экрана) и т.д. Конечно, чтобы расположить нужным образом на экране слова и сим
54
Turbo Pascal: учитесь программировать
волы, можно задать в тексте программы вывод соответствующего числа робелов как текста, ограничив их с обеих сторон символами “штрих” ('), >днако использованный выше способ представляется проще.
Второй оператор WriteLn отделяет “шапку” от данных таблицы. Дальше расположен оператор цикла с параметром, организующий внешний цикл. Тело оператора цикла представляет собой составной оператор. Первый, входящий в него оператор (WriteLn('Внешний* :8,1:8)), фиксирует итерацию внешнего цикла (выводя слово Внешний) и отображает номер текущей итерации внешнего цикла (переменная /). Дальше расположен оператор цикла с параметром, организующий внутренний цикл. Тело внутреннего цикла представляет собой единственный оператор (WriteLn (' Внутренний *:13,I:3,J:3)), фиксирующий итерацию внутреннего цикла (словом Внутренний) и отображающий номера текущих итераций внешнего (переменная I) и внутреннего (переменная J) циклов.
Данная программа призвана наглядно продемонстрировать функционирование вложенных операторов цикла.
А теперь попробуем создать программу вывода на экран содержимого таблицы ASCII, как было обещано в предыдущем разделе. Исходный текст соответствующей программы содержится в примере 2.8 (рис. 2.8).
nternet
Д^ЬПоимео 2.8
-!•]---------------— \MOMflOK~l\PBSCAL\nUHKTM\SVMBOLS.PnS --------------—-l-111-j
program table; var i,j,a:integer; begin for i:=0 to 15 do
begin a -1-32; for j:=2 to 15 do begin
write(chr(186));
if a<100 then write!’ ’): {Вывод пробела для сдвига! write (a.chrta)),	(Вывод кода и символа]
а:=а-16; end. writein _end end.
ТГШрЗСТуЙфэ BLar	в . ГЛ] w»™
Рас. 2.8. Текст программы для вывода символов таблицы ASCII
Трудность задачи в том, что в таблице ASCII нумерация символов осуществляется по столбцам, а на экран информация выводится построчно. Иными словами (с учетом того, что первые два столбца табли-
I выводиться не будут), коды (вместе с соответствующими символами)
лава 2. Операторы
55
должны отображаться на экране в таком порядке: 32, 48, 64, ..., 240 Далее следует переход на новую строку, в которой нужно отобразит символы 33, 49, 65.. 241 и т.д., пока не окажутся выведены все 16
строк. Иными словами, здесь без двух циклов, вложенных один в другой обойтись сложно.
В этой программе переменные I и J являются параметрами внешнего и внутреннего циклов соответственно. Значение переменной А соответствует коду очередного символа, предназначенного для вывода. Внеш ний цикл (for i:=0 to 15 do) отсчитывает строки выводимой таблицы (16 строк — с 0 по 15).
Далее начинается составной оператор, являющийся телом внешнего цикла. Этот составной оператор включает оператор присваивай1 " a:=i+32. Здесь переменной, предназначенной для содержания кода очередного символа, присваивается значение кода первого символа в еле дующей строке. Поскольку первые два столбца таблицы решено не вы водить (почему — см. далее), чтобы вывод начинался с третьего столбца значение этой переменной в начале вывода каждой строки следует увеличивать на 32.
Далее следует оператор цикла for j:=2 to 15 do, организующий внутренний цикл. Если внешний цикл отсчитывает строки выводимой таблицы (с 0 по 15), то внутренний цикл обеспечивает вывод символов очередной строки (со 2 по 15). Символы в строке выводятся, начиная со второго, а не с нулевого, поскольку пропускаются первые два столбца таблицы.
Тело внутреннего цикла включает четыре оператора. Первый (Write Chr(186)) выводит на экран символ псевдографики “двойная вертикальная линия”. Эти символы образуют разделители между столбцами таблицы. Второй оператор (if а<100 then Write (' ')) предназначен ддг сдвига некоторых кодов (меньших 100) и соответствующих символов на одну позицию вправо. Это делается для выравнивания столбцов таблицы. Третий оператор (Write (a, Chr(a)) отображает на экране код очередного символа и сам символ. Наконец четвертый оператор (а:=а+16) вычисляет код следующего символа. (Вспомним, что коды символов первой строки представляют собой ряд 32, 48, 64.240, т.е. имеет ме-
сто приращение на 16.)
На этом внутренний цикл завершается. Далее следует третий (последний) оператор внешнего цикла (WriteLn), обеспечивающий переход на новую строку и являющийся последним оператором всей программы.
Теперь посмотрим, что у нас получилось. Мы помним, что д ля запуска программы следует выбрать в меню Run компилятора одноименный пункт меню (или воспользоваться комбинацией клавиш <Ctrl+F9>). Как выглядит таблица символов, будучи выведена на экран, позволяет судить рис. 2.9.
56
Turbo Pascal: учитесь программировать
Searchsfain Cowpile vDebug Tools Options Шпф» .Bate -
”'	----------- Output	-.
turbo Pascal Version /.0 Copyright (c) 1983.92 Borland International
I 32 I ! 33» 1
34 i
Э5Н1 36$ 37% 38& 39’ 401 41) ! 42» I 43» I 44.
I 4H 46.
i 47/i
2411
480 • п	6ч@ 650	80Р 810	97a	112pJ128fl 113q11298		I144Pfl60a 145C11616	(176 il/T	[192Ч2081 193- 209т		224p 225c	240E 2416
502	668	828	98b	114r	1308	146T 1,162b	17ЕГ	194i	210 r	226т	2426
513	67С	83S	99с	115s	131Г	1479 163r	179	195(12115		227g	243e
524	68D	841	100с!	1161	132П	148<t 16. T	186-1	196-	212-	,228»	2441
535	69Е	850	101е	117u	133E	1498 H65e	181-1	1971	213 ?	229x	2451
546	70F	86V	102f	118u	134Ж	15011 166*	1821	198 *	214 r	230ц	2469
557	71G	87W	103g	L19w	1353	1514 il 167з	183j	1991	215	231ч	24 /il
568	72Н	888	104h	120x	1360	152ШЦ68И	1841	200“	216+	232a	248®
579	731	89V	105i	121y	137Й	153ЩИ69Й	.8b,	201 г	li217J	233i«	249»
58:	74J	90Z	106 j	122z	138K	1541> 1 'Си	186,5	202“	i218-	234ъ	250-
59;	75К.	911	107k	1231	139П	155Ы 171л	187-.	203г	219|	235ы	I
60<	76L	92\	1081	124!	14 ом	156b 172м	188J	204 г	220-	236ь	2S2IF
61=	77М	931	10Jn	125.1	141H	1573 173n	189J	205-	2211	237э	2530
62>	78N	)4~	L10n	126”	1420	158Ю 174o	190J	206+	2221	?3U	254»
63?	7905	95	lllo	127'0	143.1	L59fliil75n	191i	207-	223“	239ЯИ255	
>< 4roll at rfew
Puc. 2.9. Почти идеально
Здесь представлены коды таблицы и рядом (справа) соответствующие символы. Как уже указывалось, первых двух столбцов таблицы здесь нет. Дело в том, что кодам с О по 31 таблицы ASCII соответствуют ie символы, а управляющие команды, наподобие перевода строки или табуляции. Поэтому при выводе данных кодов на экран возникли про-темы. Еще одно неудобство: во втором столбце для символов 0-9 код ямвола и сам символ могут восприниматься как единое целое. В ос-альном полученная таблица выглядит вполне прилично.
В заключение раздела следует сказать, что вкладываться один в другой могут отнюдь не только операторы цикла с параметром (FOR), но и 'ругие операторы цикла (WHILE и REPEAT), причем, в любых сочетаниях и количествах, в зависимости от стоящей задачи. Поэкспериментировать с такими комбинированными вложенными операторами читателю предоставляется самостоятельно.
Оператор перехода и пустой оператор
Оператор перехода имеет вид:
goto р
где Р— метка, которой помечен некоторый иной оператор в программе. Использованное здесь зарезервированное слово GOTO имеет < мысл перейти. В данном случае речь идет о переходе на метку, ука
Глава 2. Операторы
57
занную после оператора GOTO (и которой помечен иной оператор в про грамме).
Оператор перехода предназначен для передачи управления в другую точку в программе (т.е. для нарушения естественного порядка выполнения операторов). Так, оператор перехода
goto 11
передаст управление оператору с этой меткой, например
И: writein
В Turbo Pascal допускается использовать в качестве меток как числ (от 1 до 9999), так и идентификаторы.
После оператора GOTO должна быть указана единственная метка и такой же меткой обязательно должен быть помечен один (и только один) из операторов в программе. Однако один и тот же оператор может помечаться несколькими метками. Иными словами, каждый оператор перехода передает управление в одну (и только в одну) точку программы, однако возможна передача управления из разных точек программы в одну точку.
Все метки, используемые в программе, должны быть объявлены. Раздел описания меток находится между заголовком и телом программы. (Подробнее о структуре программы и о месте в этой структуре раздела описания меток речь пойдет в приложении Г)
Текст программы, в которой использован оператор перехода, содержится в примере 2.9.
Пример 2.9
nternet
program jump;
label 1;
var n:integer;
begin
read (n);
if n>1000 then goto 1
else n:=n+100;
write(n);
l:end.
В программе Jump в разделе описания меток (LABEL) объявлена мет ка 1. Программа работает так. Вводится с клавиатуры значение пере менной N(типа Integer). Если это значение превышает 1000, программ сразу завершается (поскольку метка 1 расположена рядом с зарезерви рованньКм словом END, завершающим программу). В противном случа к значению N прибавляется 100 и оно выводится на экран.
Злоупотреблять использованием операторов GOTO не рекомендует ся, поскольку в результате получаются малопонятные программы. Тек более, что без оператора GOTO, как правило, можно обойтись другим! средствами Turbo Pascal. Так, тело программы из предыдущего пример, можно преобразовать следующим образом:
58
Turbo Pascal: учитесь программировать
begin
read (n);
if n<=1000 then
begin
n:=n+100;
write(n)
end;
end.
В заключение заметим, что если метка используется внутри процедуры или функции, она “видна” только в пределах этой процедуры или функции и должна быть описана в ней. Иными словами, передача управ-юния снаружи внутрь процедуры или функции с помощью оператора перехода невозможна. О процедурах и функциях речь пойдет в главе 3.
О пустом операторе. Обратим внимание на метку в предыдущем примере. Вот как выглядит соответствующий фрагмент этой программы:
if n>1000 then goto 1
else n:=n+100;
write(n);
l:end.
Здесь метка расположена рядом с зарезервированным словом END, являющимся признаком конца тела программы. Однако по определению метками могут помечаться только операторы. Зарезервированное же слово END оператором не является, т.е., строго говоря, передать управление на конец составного оператора невозможно. Однако если считать, что метка здесь предшествует некоторому пустому оператору, то тогда такая конструкция становится легитимной.
Пустой оператор не выполняет никаких действий и в тексте про-1 раммы о его присутствии свидетельствует только один символ “точка с запятой” (;). Мы уже знаем, что в конце составного оператора, перед зарезервированным словом END точка с запятой необязательна. Однако, когда рядом со словом END расположена метка, в этом случае перед меткой обязательно должна присутствовать точка с запятой, назначение которой в этом случае — послужить разделителем между последним реальным оператором и пустым оператором.
Понятие пустой оператор делает возможными в программах такие экзотические конструкции, как
begin ;;;;; end;
или
while р do begin end;
Разумеется, от подобных операторов мало проку и чуть ли не единственная практическая польза от пустого оператора — возможность пере-1ать управление (с помощью оператора перехода) на конец составного оператора.
лава 2. Операторы
59
Оператор WITH
Оператор WITH (его еще называют оператором над записями), в соответствии с названием, предназначен для работы с записями. Подробно он рассматривается в главе 4.
60
Turbo Pascal: учитесь программирова
Глава 3
 Процедуры я и функции
В этой главе...
	Понятие подпрограммы
	Описание процедур
	Описание функций
	Сферы действия имен
	Параметры
	Рекурсия
	Опережающее описание
Всякую сложную задачу для лучшего понимания и облегчения ее решения полезно разделить на простые подзадачи. Если каждая программа предназначена для решения определенной задачи, то должен существовать способ разделения программ на некоторые структурные единицы. Структурным единицам программ, известным как подпрограммы, и посвящена данная глава.
Что такое подпрограмма
Часто в программах возникает необходимость выполнить несколько раз одну и ту же последовательность операторов (не циклически). Конечно, можно соответствующий фрагмент скопировать в программе несколько раз в нужные места, однако при таком подходе текст программы получается обширным и трудным для понимания. Кроме того, для объемной программы требуется больше памяти. Поэтому для упрощения текста программ, а также для исключения необходимости заниматься копированием предложена концепция подпрограмм.
Функционально самостоятельная часть программы, обладающая собственным именем и набором локальных имен, известна как подпрограмма. Вызов подпрограммы осуществляется по ее имени из любых точек тела программы и любое количество раз.
Помимо упрощения текстов программ и избавления от копирования, подпрограммы— это еще средство структурирования программ. Идея в том, чтобы программа состояла не из огромного числа операторов, а из относительно самостоятельных частей (подпрограмм), каждой из которых назначена отдельная, сравнительно узкая роль. Причем подпрограммы могут включать в себя другие подпрограммы, т.е. допускается вложенность подпрограмм.
Для того чтобы понять суть структурирования программ, рассмотрим задачу “Попасть из города А в город Б.” Эту задачу можно структурировать следующим образом.
I.	Добраться до вокзала
II.	Приобрести билет
III.	Сесть в поезд
IV.	Доехать до города Б
Каждое из перечисленных действий также поддается структуризации. Например:
I.	Добраться до вокзала
1)	выйти из дому
2)	поймать такси
3)	доехать до вокзала
Возможна дальнейшая детализация:
62
Turbo Pascal: учитесь программировать
1.	Выйти из дому
а)	собрать вещи
б)	перекрыть воду и все выключить
г) запереть дверь д) выйти на улицу
И так до тех пор, пока задача не будет разложена на самые элементарные действия — как раз то, что нужно, когда требуется создать программу решения задачи на компьютере. Если бы решение задачи “Попасть из города А в город Б” потребовалось описать средствами языка программирования, то отдельные действия, на которые мы разложили эту задачу, можно было бы представить в виде подпрограммам, вложенных одна в другую.
Структурированные программы более просты в понимании, их легче создавать и отлаживать. Кроме того, отдельные подпрограммы, имеющие определенное, узкое назначение, можно использовать в различных программах многократно.
Подпрограмма, чтобы ее можно было вызывать в программе, должна быть объявлена в разделе описаний программы. (Подробнее о структуре программы и о месте в этой структуре описаний подпрограмм речь пойдет в Приложении Г) Объявить подпрограмму — значит указать ее заголовок (с используемыми в ней формальными параметрами), описать локальные переменные и, наконец, задать ее тело. В разделе описаний подпрограммы могут быть объявлены новые подпрограммы, которые, в свою очередь, также могут включать подпрограммы. Иными словами, возможно множество уровней вложения подпрограмм, как это показано на примере задачи “Попасть из города А в город Б” выше.
В языке программирования Turbo Pascal приняты два вида подпрограмм: процедуры и функции.
Описание процедур
Предположим, создается программа-редактор текстов. В этой про-рамме должна быть предусмотрена возможность отделять фрагменты Редактируемых текстов один от другого чертой, состоящей из одинако-ых символов, скажем, знаков “минус”. Чтобы реализовать эту возмож-ость, в программе-редакторе можно создать соответствующую проце-уру. Схематически и эта программа с процедурой выглядит так:
program editor;
{Разделы описания меток, констант, типов и переменных}
procedure line;
var symbol:integer;
лава 3. Процедуры и функции
63
begin {Начало тела процедуры}
write ('{');
for symbol:=l to 78 do write
writein ('}');
end; {Конец тела процедуры}
begin {Начало тела программы}
line; {Вызов процедуры}
end. {Конец тела программы}
Здесь в программе Editor описана процедура Line. На схеме программы видно, что описания процедур (это же касается и функций) должны находиться в конце раздела описаний программы (после описаний меток, кон стант, типов и переменных), перед началом ее тела. Бросается в глаза, что структура процедуры повторяет структуру программы — в ней также есть заголовок, раздел описаний и тело. Начинается процедура с зарезервированного слова PROCEDURE, за которым через пробел следует имя процедуры. Строка заголовка обязательно должна завершаться точкой с запятой. Затем идет раздел описаний процедуры. В рассматриваемой процедуре описана всего лишь единственная переменная, но, как и в программе, здесь могут быть объявлены метки, константы, типы, а также функции и другие процедуры, вложенные в процедуру Line.
После раздела описаний процедуры следует ее тело. Тело процедуры содержит последовательность операторов, заключенных в операторные скобки (представляющие собой пару зарезервированных слов BEGIN . END). Для вызова процедуры Line из тела программы достаточно указать ее имя в нужном месте. Пример вызова нашей процедуры можно видеть в теле программы Editor.
Данная процедура отображает на экране строку из 78 символов “минус” (—). А если возникнет необходимость, чтобы в различных редактируемых документах фрагменты текста разделялись строкой других символов, или чтобы длина этой строки была иной? Тогда в теле программы, вероятно, должен быть предусмотрен специальный оператор Read, позволяющий задать нужную информацию (символ и длину строки), которую затем каким-то образом следует передать в процедуру. Пе-,4 редача информации из тела программы в процедуру осуществляется с помощью механизма параметров (о параметрах речь пойдет в разделе “Параметры ” дальше в этой главе). Соответствующим образом модифицированная схема программы, представленная выше, выглядит так:
program editor;
{Разделы описания меток, констант, типов и переменных}
64
Turbo Pascal: учитесь программироват
procedure line (ch:char; In:integer);
var symbol:integer;
begin {Начало тела процедуры}
write ('{');
for symbol:=1 to In do
write ('ch');
writein ('}');
end; {Конец тела процедуры}
begin {Начало тела программы}
read(a,b); {Задаются символ и длина строки} line(a,b); {Вызов процедуры}
end. {Конец тела программы}
Чем вторая схема программы отличается от первой? В описании процедуры, в заголовке после ее имени, во-первых, заданы формальные параметры (ch:char; In:integer), предназначенные для передачи информации о выбранном символе (ch) и длине строки (In) из программы в процедуру. Кроме того, идентификаторы указанных параметров заменили в теле процедуры фиксированные значения (78 и '-'). Кстати, формальными параметрами, представленными в описании процедуры, можно манипулировать в теле этой процедуры так же, как и переменными. (Как уже отмечалось, подробнее о параметрах речь пойдет в разделе "Параметры ” дальше в этой главе.)
В теле программы также имеют место два изменения. Во-первых, появился новый оператор (Read (а, b)), позволяющий задать произвольные символ и длину строки. Во-вторых, оператор вызова процедуры (Line (а,Ь)) теперь снабжен фактическими параметрами. Переменные А и В, значения которых вводятся (с клавиатуры) с помощью оператора Read, а затем передаются соответствующим формальным параметрам, указанным в описании процедуры Line, должны быть описаны в разделе объявления переменных программы как переменные типов Char и Integer соответственно.
Описание функций
Помимо процедур, в Turbo Pascal применяются подпрограммы и ино-о вида — функции (чем функции отличаются от процедур, мы выясним и конце данного раздела). Рассмотрим конкретный пример.
В Turbo Pascal не существует стандартной функции, вычисляющей заданную степень заданного числа. Однако ничто не мешает создать такую функцию самостоятельно. Вот как может выглядеть схема некоторой программы, в которой определена функция вычисления степени
Глава 3. Процедуры и функции	65
3 2016
(пусть числа, степени которых вычисляет функция, а также показате. степеней являются целыми):
program example;
{Разделы описания меток, констант, типов и переменных}
function power (num,pow:integer):integer;
var i:integer; a:real;
begin {Начало тела функции}
a:=num;
for i:=l to pow do
a:=a*num;
power:=num
end; {Конец тела функции}
begin {Начало тела программы}
read(a,b);
x:=power(a,b)+y; {Обращение к функции}
end. {Конец тела программы}
В программе Example описана функция Power. На этой схеме про граммы видно, что описания функций (как и процедур) должны находиться в конце раздела описаний программы (после описаний меток, констант, типов и переменных), перед началом ее тела. Структура функции (как и процедуры) повторяет структуру программы. Первой идет строка заголовка, которая начинается с зарезервированного слова FUNCTION. За ним через пробел следует имя функции; далее в скобках— перечень формальных параметров; затем двоеточие, за которым указывается тип значения, возвращаемого функцией. Завершается строка заголовка точкой с запятой. Сразу под заголовком функции расположен ее раздел описаний. В рассматриваемой функции определены всего лишь две переменные, но, как и в программе, здесь могут быть объявлены метки, константы, а также другие функции и процедуры, вложенные в функцию Power.
После раздела описаний функции следует ее тело. Тело функции содержит последовательность операторов, заключенных в операторные скобки. Для обращения к функции Power в теле программы достаточно указать ее имя в нужном месте.
КстаТи, в отличие от процедур, активизируемых с помощью оператора вызова (включающего имя процедуры и, может быть, фактические параметры), имя функции должно упоминаться в выражении. Пример обращения к нашей функции можно видеть в теле программы Example (здесь взято произвольное выражение).
У функций (в отличие от процедур) имеются и другие особенности Например, в результате использования функции возвращается некоторое значение. Тип возвращаемого значения указывается в описании
66
Turbo Pascal: учитесь программировать
функции (в заголовке). Если имя процедуры используется только для ее вызова, то с именем функции ассоциируется некоторое возвращаемое значение.
Чем еще функции отличаются от процедур? Поскольку функция должна возвращать некоторое значение, в ее теле обязательно должен присутствовать оператор присваивания, в правой части которого указано имя функции.
Когда лучше использовать процедуры и когда функции? Это зависит от конкретного случая. Если подпрограмма вычисляет единственный результат, ее можно реализовать как функцию. Если же от подпрограммы требуется вычислить несколько значений, ее лучше оформить в виде процедуры.
Сферы действия имен
Мы уже знаем, что структура подпрограммы повторяет структуру программы и, что в каждой из подпрограмм можно объявлять свои переменные, метки, константы, типы и вложенные подпрограммы (с собственными именами). Кроме того, упоминалось, что описание подпрограммы может включать список формальных параметров и что с этими параметрами можно обращаться в данной подпрограмме как с переменными. Однако как избежать при этом путаницы? Можно ли манипулировать в теле программы именами, объявленными в одной из подпрограмм? И наоборот, можно ли имена, объявленные в разделе описаний программы, использовать в одной из подпрограмм? А что если имена совпадут? Все эти вопросы мы и выясним в данном разделе. Здесь речь пойдет о том, как точно определить, какие имена доступны в той или иной подпрограмме.
Структуру программы (т.е. схему вложения в нее подпрограмм), а также сферы действия имен лучше всего изобразить графически. Обычно для этого используются прямоугольники, вложенные один в другой (рис. 3.1).
На этой схеме представлена программа А, в которой объявлены подпрограммы В (процедура) и С (функция). Подпрограмма В, в свою очередь, содержит вложенные подпрограммы D (функция) и Е (процедура).
Program А х, у, z
	Procedure В m, п	
	Function D g.h	
		
	Procedure Е k, 1	
		
Function С р, г, s
Рис. 3.1. Каждое имя доступно в своей подпрограмме, а также во всех “объемлющих" подпрограммах
Глава 3. Процедуры и функции
3*
67
Итак, какие идентификаторы доступны в той или иной подпрограмме? Имена X, Y, Z, объявленные в программе А, доступны во всех подпрограммах, существующих в этой программе. Имена М, N, объявленные в процедуре В, кроме самой этой подпрограммы, доступны также в функции D и процедуре Е. Имена, объявленные в подпрограммах С (Р. R, S), D (G, Н) и Е (К, L) доступны только в пределах этих подпрограмм. Иными словами, для любой подпрограммы доступны все имена, объявленные в ней, а также во всех “объемлющих" подпрограммах, а также в самой программе (т.е. “выше”). Однако для той же подпрограммы недоступными все имена, объявленные во вложенных в нее подпрограммах (или “ниже”).
Имена, объявленные в подпрограмме (и доступные во всех вложенных подпрограммах), будут для данной подпрограммы локальными, а для вложенных в нее подпрограмм— глобальными. Иными словами, понятия “локальные” и “глобальные” часто относительны. Однако имена, объявленные в основной программе, глобальны для всех описанных в ней подпрограмм.
Существует еще одна проблема: что если в подпрограмме и в основ ной программе были объявлены две переменные с одинаковыми именами? Ответ прост: в этом случае основная программа “видит” свою пере менную, а подпрограмма — свою, т.е. для данного идентификатора все гда используется “наиболее локальное” описание. Это одно и преимуществ языка Turbo Pascal— возможность выбирать имена в подпрограммах, не заботясь о том, что они могут совпасть с именами из объемлющих подпрограмм.
Параметры
При знакомстве с описаниями процедур и функций не раз употреб лялся новый термин параметры (см. разделы “Описание процедур” и “Описание функций”). Роль параметров при использовании процедур i функций настолько важна, что нелишне посвятить этому специальны! раздел.
Итак, для начала вспомним, с какими параметрами нам пришлось имеуъ дело в программе Editor (см. раздел “Описание процедур” выше) Процедура Line в первом ее варианте предназначена для вывода на экран строки символов “минус” (и никаких других) фиксированной длины. Когда потребовалось сделать так, чтобы для различных документов можно было указывать иной символ и варьировать длину строки, про цедуру Line пришлось описать с соответствующими формальными параметрами (см. второй вариант схемы программы). Кроме того, в про грамму Editor был введен оператор Read(a,b), позволяющий задавать
68
Turbo Pascal: учитесь программироват
нужные значения с клавиатуры. Затем процедура Line вызывается с этими значениями (Line(a,b)) в качестве фактических параметров.
Итак, при вызове процедуры Line переменные А и В (которые при этом задаются как фактические параметры) передаются внутрь процедуры с помощью формальных параметров Ch и Ln. Причем фактические параметры передаются формальным параметрам в том порядке, в каком они представлены в операторе вызова процедуры.
Для лучшего запоминания повторим, что параметры, указываемые в операторе вызова процедуры, называются фактическими параметрами, а параметры, перечисленные в заголовке описания процедуры, — это формальные параметры.
Таким образом, в описание подпрограммы (точнее, в ее заголовок) может быть включен список параметров. В этом случае заголовок подпрограммы (пусть это будет процедура) принимает вид:
procedure proc_name (a,b,c:type_l; d,e,f:type_2;...x.y.z:type_n) ;
Здесь А, В, C, D, Е, F, ..., X, Y, Z— формальные параметры, a Type_l, Type_2....Type_N — типы данных, которым принадлежат эти парамет-
ры. Само собой разумеется, что групп параметров (т.е. типов параметров) может быть любое количество, так же как любое количество параметров может быть в той или иной группе.
Если в описании подпрограммы имеются формальные параметры, при ее вызове непременно должны указываться фактические параметры. При этом количество фактических и формальных параметров и их принадлежность к определенным типам данных должны совпадать.
Вот пример процедуры:
procedure proc_name (х, у:integer);
begin
х := 8;
У := 5;
writein (х*у/2) end;
Процедура Proc_Name описана с двумя формальными параметрами, принадлежащими типу Integer. Этим двум параметрам в процедуре присваиваются некоторые значения, которые затем участвуют в каких-то вычислениях.
Теперь, предположим, вы вызвали эту процедуру из основной программы:
number := 55;
proc_name (number, 4);
Здесь переменная Number (которой до этого было присвоено значение 55) указывается в качестве первого фактического параметра при вызове процедуры Proc_Name. Какое значение будет иметь переменная Number по возвращении управления в основную программу? Естественно, 55. Конечно, значение переменной Number было передано формальному параметру X, которому затем в подпрограмме было присвоено
\ава 3. Процедуры и функции
69
значение 8. Однако в данном случае параметр X на переменную Number никак не воздействует. Значение переменной в основной программе здесь абсолютно не зависит от того, что происходит в процедуре. Тут mi имеем дело с параметром-значением, который просто передает значе ние переменной Number в процедуру.
Существует и иной вид параметров, известный как параметры-переменные. Часто результатом работы подпрограммы может быть не только вывод на экран (как в процедуре Line из примера выше), но и вычисление некоторых данных, т.е., требуется передавать значения не только из программы в процедуру, но и обратно — из процедуры в программу. Это осуществляется с помощью параметров-переменных. При их использовании создается (до окончания работы подпрограммы) устойчивая связь между фактическим и соответствующим ему формальным параметром. Когда в процедуре значение формального параметра изменяется, претерпевает изменение и значение фактического параметра. Но каким образом отличить параметры-значения от параметров-переменных? Все очень просто. Для этого в перечень формальных па раметров в описании процедуры вводится зарезервированное слове VAR. Параметры, представленные в списке формальных параметров д< слова VAR, являются параметрами-значениями. Параметры, перечне ленные после слова VAR, представляют собой параметры-переменные Заголовок процедуры, в которой описаны как параметры-значения, так и параметры-переменные, имеет следующий вид:
procedure proc_name (a,b,c:type_l; d,e.f:type_2; varx.y.z:type_n) ;
Здесь А, В, C, D, E, F— параметры-значения (поскольку перед ним! зарезервированного слова VAR нет), аХ. Y, Z—параметры-переменные.
Примечание
В качестве фактических параметров, предназначенны для передачи формальным параметрам-переменным, нс допускается использование констант, поскольку их зн чения могут быть изменены в процедуре.	-г
Вот пример описания процедуры:
procedure proc_name (х, : integer; VAR у : real); begin
у := x*5
end;
(Процедура Proc_Name описана с двумя параметрами — параметре, значением X и параметром-переменной Y. Затем в теле процедуры этими параметрами производятся некоторые действия.)
А вот фрагмент основной программы:
number := 1;
power := 50;
proc_name(number, power);
70
Turbo Pascal: учитесь программироват -
(Здесь переменные Number и Power, которым до этого были присвоены значения 1 и 50 соответственно, указывается в качестве фактических параметров при вызове процедуры Proc_Name.)
После завершения работы процедуры переменная Number останется со значением 1, поскольку она передается в качестве фактического параметра формальному параметру X, а X— это параметр-значение. Однако переменная Power примет новое значение— 5, поскольку она передается в качестве фактического параметра формальному параметру А, который представляет собой параметр-переменную.
Формальные параметры и фактические параметры... Параметры-переменные и параметры-значения... Как бы получше разобраться во всех этих параметрах? Возможно, некоторую ясность внесет рис. 3.2.
Заголовок процедуры из ее описания	Формальные параметры
I	'----:--------1--------------?
— Procedure proc name (х : integer; var у : real) ;
~	L_____________1 I------и-----1
Параметр-значение
I--'	| | П	Параметр-переменная
Гргос_паше (number, power);
1-------------f
Вызов процедуры в теле программы Фактические параметры
Рис. 3.2. Это поможет разобраться
На этом рисунке представлены взятые из последнего примера строка заголовка из описания процедуры и строка вызова этой процедуры из тела программы. Здесь же указаны все разновидности используемых параметров.
Запомним, что параметр-значение копирует значение некоторой переменной из программы и передает его в процедуру. Процедура каким-то образом манипулирует этой копией значения, а затем по завершении работы процедуры эта копия теряется. Исходное значение переменной при этом остается неизменным. Параметр-переменная предоставляет доступ процедуре непосредственно к самой переменной из программы. При этом процедура манипулирует значением этой переменной и по завершении работы процедуры переменная из программы остается с новым значением.
Иными словами, параметр-значение— это средство передачи данных в одном направлении: из программы в процедуру, а параметр-переменная позволяет передавать данные в обоих направлениях.
То, что говорилось здесь о параметрах применительно к процедурам, олностью относится и к функциям. Вот как могут выглядеть строка заголовка из описания функции и обращение к этой функции в теле программы:
function func_name (х, : integer; VAR у : real):real;
с:=func_name(a,b)+d+e;
Глава 3. Процедуры и функции
71
Разумеется, здесь отражены особенности, присущие функциям. Например, в заголовке описания функции указано, значение какого типа возвращает данная функция (Real). Также при обращении к функции в теле программы имя функции употреблено в выражении (в нашем примере взято произвольное выражение). Что же касается параметров, здесь все так же, как и для процедур.
Примечание
Кстати, дурным тоном считается применение зарезервированного слова VAR в списке формальных параметров функции, хотя это и не запрещается прямо, т.е., использование в функции параметров-переменных нежелательно-— функция по определению должна возвращать единственное значение.
Рекурсия
Что произойдет, если в теле подпрограммы окажется оператор вызова этой же подпрограммы? Видимо, подпрограмма вызовет саму себя и теоретически будет продолжать делать это бесконечное количество раз, если автор программы не предусмотрел выхода при определенных условиях из данного замкнутого круга.
Примечание
Во всех рекурсивных подпрограммах должно присутствовать какое-то условие прекращения рекурсии. При этом единственном условии рекурсия должна прекратиться: при всех остальных условиях она будет продолжаться.
Итак, в Turbo Pascal допускается присутствие в теле подпрограммы оператора вызова самой себя. Такие подпрограммы называются рекурсивными, а такой способ вызова— рекурсией. Рекурсия оказывается весьма удобным подходом при решении некоторых задач, например, вычисления факториала. Вот как определяется факториал положительного целого числа:
!а=1*2*..,*(а-1)*а
Еслиа=1,то 11=1; еслиа=2,то !2=1*2 ; еслиа=3, то 13=1*2*3 ит.д. Иными словами, здесь при вычислении факториала для каждого последующего числа используется предыдущий результат.
А вот как может выглядеть текст описания соответствующий функции: function fact (a:integer):integer;
begin
if a=0 then fact:=l
else fact:=a*fact(a-l)
end;
72
Turbo Pascal: учитесь программировать
Для того чтобы обратиться к данной функции из основной программы (и тем самым инициировать рекурсию), в теле программы должно присутствовать выражение, в котором фигурирует имя функции Fact (например, write(factfb))), где В— число, факториал которого требуется вычислить. Кроме того, В здесь— фактический параметр, который передается формальному параметру А в описании функции. В результате первого рекурсивного обращения к функции Fact (т.е. обращения к самой себе) в памяти компьютера создается копия этой функции (с собственными локальными переменными), которой передается параметр со значением В—1. В результате второго рекурсивного обращения к функции Fact создается еще одна копия этой функции (как бы вложенная в первую и тоже с собственными локальными переменными), которой передается параметр со значением В-2. Затем функция Fact будет обращаться к самой себе (и при этом будут создаваться все новые ее копии, существующие независимо одна от другой) до тех пор, пока она (в последней своей копии) не возвратит значение 1 (т.е. во всех этих копиях будет вычисляться значение параметра, каждый раз уменьшающееся на 1). Схематически это изображено на рис. 3.3.
“Движение вглубь” продолжается до тех пор, пока параметр, с которым в очередной раз будет иметь место обращение к функции Fact, не окажется равным О. К моменту завершения рекурсии в программе будут созданы В копий функции Fact, в последней из которых ее значение окажется равно 1. После этого будет иметь место “движение изнутри наружу”, т.е. значение функции Fact из очередной “внутренней” копии функции будет умножаться на значение А из “внешней” копии и при этом “внутренняя" копия функции будет ликвидироваться. По завершении этого процесса окажется вычислен факториал числа В.
Рассмотренная только что функция реализует рекурсивный алгоритм вычисления факториала. Мы уже знаем, что при этом создается множество копий функции (каждая из которых имеет собственные локальные переменные). Вся эта информация содержится в стеке— особым образом организуемой области памяти.
Рекурсия— не единственный способ решения подобных задач. Например. ничто не мешает вычислить факториал положительного числа В с использованием итерационного (в противоположность рекурсивному) алгоритма. Текст описания соответствующей функции может выглядеть так:
function fact (а:integer):integer;
var f:integer;
begin
while a>0 do
begin
f:=fact(a-l); fact:=f*a
end;
end;
лава 3. Процедуры и функции
73
'¥’ЯЛ1ОУг°льник представляет на ин из рекурсивных вызовов функции Fact
74
Turbo Pascal: учитесь программироват
Здесь /• переменная, предназначенная для временного хранения текущего значения факториала. Вычисление условия оператора цикла W1IH.E. его проверка и выполнение составного оператора повторяются до тех пор. пока значение А не становится равным нулю. Составной оператор, выполняемый циклически, включает два оператора:
f:=fact(a-l); fact:=f*а
11ервый из них присваивает переменной F текущее значение функции Fact, вычисленное в предыдущем цикле, а второй вычисляет следующее значение Fact.
Первый вариант функции Fact (реализованной на основе рекурсивного алгоритма) выглядит несколько компактнее, однако такая функция работает медленнее и к тому же, как уже отмечалось, при ее использовании не исключено переполнение стека.
Опережающее описание
В предыдущем разделе речь шла о непосредственной рекурсии (когда подпрограмма вызывает саму себя). Помимо непосредственной, возможна косвенная рекурсия, при которой подпрограмма А вызывает подпрограмму В, а подпрограмма В, в свою очередь, — подпрограмму А. Но как описать две подпрограммы, вызывающие одна другую? Ведь в описании любой из них, которое расположено первым в разделе описаний основной программы, будет вызов подпрограммы, описываемой дальше (т.е. в момент вызова еще неизвестной). Выход из этого затруднения предоставляет так называемое опережающее описание.
В Turbo Pascal допускается применение опережающего описания используемой подпрограммы, которое состоит только из ее заголовка, за Спорым следует зарезервированное слово FORWARD. В этом случае полный текст подпрограммы может быть расположен дальше в любом месте раздела описаний процедур и функций.
Как это будет выглядеть на примере подпрограмм А и В, о которых ni.ia речь выше? Схема исходного текста программы, в которой описаны Указанные подпрограммы, может выглядеть так:
program к;
var izinteger; jsreal;
procedure a (x:integer); forward; {Опережающее описание} procedure b (yzreal);
begin
a(i) {Вызов еще не определенной процедуры} end;
procedure а;
Глава 3. Процедуры и функции
75
begin
b( j)
end;
Здесь для процедуры А использовано опережающее описание. Затем идет описание процедуры В, из которой вызывается процедура А. Однако, благодаря опережающему описанию процедуры А компилятор не зафиксирует это как присутствие неизвестного идентификатора (т.е. ошибку). За описанием процедуры В следует описание процедуры А (без повторения списка формальных параметров, поскольку информация о параметрах уже содержится в опережающем описании процедуры А).
Стандартные процедуры и функции
В языке программирования Turbo Pascal, помимо подпрограмм, определенных пользователем, существует множество стандартных (или встроенных) процедур и функций. Так, мы уже познакомились со стандартными процедурами Read и ReadLn (ввод с клавиатуры), Write и WriteLn (вывод на экран), а также функциями Sqr (возведение в квадрат), Sqrt (извлечение квадратного корня), Chr (преобразование кода ASCII в соответствующий символ) и Abs (вычисление абсолютного значения). Со многими другими стандартными подпрограммами мы познакомимся в различных главах этой книги.
76
Turbo Pascal: учитесь программировать
ШЭД
'лава 4
(Типы данных
В этой главе_________________
	Концепция и классификация типов.
	Простые типы
	Строки
	Массивы
	Записи
	Множества
	Совместимость типов
Эта глава посвящена одному из самых важных предметов языка программирования Turbo Pascal — типам данных. Все данные, которыми манипулируют программы, написанные на Turbo Pascal, обязательно должны принадлежать тому или иному типу. Здесь мы узнаем, какие существуют типы данных, а также научимся ими пользоваться.
Понятие типа данных
Тип однозначно определяет, как будет интерпретироваться та или иная информация; в результате исключаются попытки проводить над ней неприемлемые операции. Например, если в программе фигурирует переменная, имеющая смысл “количество штук”, понятно, что ее значе ние не должно представлять собой дробное число. Чтобы этого избежать, такой переменной при объявлении должен быть присвоен один иг целочисленных типов (например, Integer). Также недопустимы арифметические операции над символами, чтобы этого не случилось, соответствующие переменные должны принадлежать символьному типу (Char). А если в программе имеется переменная, способная принимать только значения, имеющие смысл “Да" или “Нет” (либо “Правда” или “Ложь”), чтобы обеспечить правильную интерпретацию ее значения, эта переменная должна принадлежать логическому типу (Boolean). Иными словами, принятая в Turbo Pascal типизация переменных направлена на повышение надежности программ.
Полезность любого типа данных определяется в первую очередь набором операций, допустимых над значениями этого типа. Соответствующие сведения приведены в данной главе по каждому из рассматри ваемых типов. Типы данных, принятые в Turbo Pascal, показаны на структурной схеме (рис. 4.1).
Здесь прямоугольники нижнего ряда представляют типы данных, а прямоугольники, которые выше, — категории типов. Типы данных, де лятся на стандартные и образованные пользователем. Стандартные ти пы (их всего 5) выделены на структурной схеме (см. рис. 4.1). Что каса ется пользовательских типов, то они создаются на основе стандартных Не совсем понятно? Данная глава, посвященная типам данных, как ра и предназначена внести ясность. Целесообразно усвоить материал дан ной главы, а затем вернуться к представленной выше схеме.
В этой главе рассматриваются все типы данных, за исключением файлов, указателей и объектов, которым посвящены специальные гл а вы —5, 6 и 12 соответственно.
78
Turbo Pascal: учитесь программировать
Типы данных
Стандартные
Рис. 4.1. Типы данных
Простые типы
К простым относятся такие типы данных, как вещественные, целочисленные, символьный, логический, перечислимый и интервальный (или диапазон). Первые четыре из упомянутых (вещественные, целочисленные, символьный и логический) относятся в Turbo Pascal к стандартным типам данных. А перечислимый и интервальный — к типам, oi 'редгляемым пользователем. Для указанных типов возможна еще одна градация. Все они, за исключением вещественных, относятся к порядковым типам данных. Место простых типов в иерархии типов Turbo Pascal демонстрирует структурная схема (см. рис. 4.1)
Мы уже встречались в главе 1 со стандартными типами данных Real (одним из вещественных). Integer (одним из целочисленных). Char (символьным) и Boolean (логическим). Теперь нам предстоит познакомиться с оставшимися вещественными и целочисленными типами, продолжить знакомство с типами Char и Boolean, а также узнать о простых типах, определяемых пользователем, таких как перечислимый и интервальный.
Слава 4. Типы данных
79
Вещественные типы
К вещественным типам данных, используемых в языке программ!1 рования Turbo Pascal, относятся Real, Single, Double, Extended и Comp Между собой они отличаются диапазонами допустимых значений (т.е значений, которые могут принимать переменные этих типов). Для хра нения переменных того или иного вещественного типа требуются рас личные объемы памяти. Соответствующие характеристики веществен ных типов представлены в табл. 4.1.
Таблица 4.1. Характеристики вещественных типов, принятых в Turbo Pascal			
Вещественный тип	Диапазон значений	Число значащих цифр мантиссы	Требуемая память (байт)
Real	2.9E-39 ..1.7E38	11-12	6
Single	1.5E-45.. 3.4E38	7-8	4
Double	5.0E-324 ..1.7E308	15-16	8
Extended	1.9E-4951 ..1.1E4932	19-20	10
Comp	-2E+63+1 ..2E+63-1	19-20	8
Вот как выглядят описания переменных вещественных типов: var
a:real; b:single; с:double; d:extended; e:comp;
Для чего потребовалось иметь несколько типов данных, имеющих сходный смысл? Почему бы не обойтись единственным вещественным типом, например Real? Дело в том, что, в зависимости от программируемой задачи, разные переменные могут иметь отличающиеся диапазоны допустимых значений, в соответствии с которыми и следует выбирать для той или иной переменной тип данных.
Почему бы не назначать для всех переменных наибольший диапазон допустимых значений, подходящий для всех случаев? Такой подход не го ди гея потому, что для содержания переменных разных вещественных типов выделяется различный объем памяти (см. таблицу выше), и это оказывает влияние на быстродействие программы. В самом деле, на обработку 4-байтового числа уйдет больше времени, чем 1-байтового. Поэтому в зависимости от диапазона значений которые может принимать та или иная переменная, следует выбрать для нее наиболее подходящий тип.
Среди упомянутых выше вещественных типов особого внимания заслуживает Comp. Данный тип — нечто среднее между вещественным и целочисленным типами, одновременно обладающий свойствами и тех, и других. Переменные типа Comp могут принимать только целые значения — особенность целочисленных типов. Однако при этом Comp не является порядковым типом и именно потому его относят к категории вещественных типов.
80
Turbo Pascal: учитесь программирован
Применимые операции
l£ вещественным числам применимы четыре арифметических деист -вия; полученный при этом результат также будет вещественным числом. Речь идет о таких действиях, как сложение (+), вычитание (-), умножение (*) и деление (/). В одном выражении могут присутствовать переменные как одного, так и разных вещественных типов. Например, объявленные выше переменные А, В, С, D и Е могут участвовать в следующих выражениях:
a+b+e; c-d; (a*b+c*d)/2; e/(c+d);
Причем, даже если один из операндов, участвующих в операциях сложения, вычитания или умножения, окажется целым числом (это допускается), полученный результат все равно будет вещественным. А если речь идет об операции деления, результат окажется вещественным даже при двух целочисленных операндах.
Что касается операций сравнения, то выражения, в которых применены эти операции, дают логический результат. Например, если А=333.44, а В=32.55, то выражение а>Ь даст результат TRUE, а выражения а<Ь и а=Ь — результат FALSE. К вещественным значениям применимы все операции сравнения; эти операции представлены в табл. 4.2.
Таблица 4.2. Операции сравнения
Обозначение	Операция
=	Равно
о	Не равно
>	Больше
<	Меньше
>=	Больше или равно
<='	Меньше или равно
Любая из этих операций даст логический результат.
В заключение необходимо упомянуть, что в одном выражении могут присутствовать переменные как одного, так и разных вещественных типов (совместимость в выражении). Кроме того, переменной вещественного типа может присваиваться выражение вещественного типа, если возможные значения выражения принадлежат диапазону значений, допустимых для переменной (совместимость по присваиванию). Подробнее об этом сказано в разделе “Совместимость типов” дальше в этой главе.
Применимые стандартные подпрограммы
К переменным и значениям, принадлежащим вещественному типу. Применимы все математические функции, а также две функции преобразования типов — Round и Trunc. Описания указанных функций можно найти в Приложении Б.
Глава 4. Типы данных
81
Порядковые типы
Данное понятие включает в себя все целочисленные, символьный логический, перечислимый и интервальный типы. Каждый из указан ных типов подробно рассматриваться ниже.
Целочисленные типы
К целочисленным относятся такие типы данных, как Integer, Shortlnt, Longlnt, Byte и Word. Так же, как и с вещественными типами, между собой они отличаются диапазонами допустимых значений и объемом памяти, требуемой для содержания переменных этих типов. Соответствующие характеристики для перечисленных типов представлены в табл. 4.3.
Таблица 4.3. Характеристики целочисленных типов
Целочисленный тип	Диапазон значений	Требуемая память (байт)
Integer	-32768 .. 32767	2
Shortlnt	-128.. 127	1
Longlnt	-2147483648.. 2147483647	4
Byte	0 .. 255	1
Word	0 .. 65535	2
Из целочисленных типов, помимо Integer, мы имели дело с Longlnt Помните, в главе 2 (где речь шла об операторе цикла WHILE) мы создали программу вычисления числа л с помощью формулы Грегори. Тогда мы были вынуждены воспользоваться типом Longlnt, поскольку диапазона допустимых для типа Integer значений оказалось недостаточно.
Существование в Turbo Pascal нескольких целочисленных типов обусловлено теми же причинами, что и для вещественных типов, о которых шла речь выше. В самом деле, если в некоторой программе имеется переменная, определяющая порядковый номер дня в году, понятно, что допустимые для нее значения лежат в диапазоне от 1 до 366. В этом случае объявить данную переменную как принадлежащую типу Longlnt нерационально. а типы Shortlnt и Byte здесь просто не подходят, поскольку значения переменной могут выйти за пределы соответствующих диапазонов. Для этой переменной наиболее подходят типы Integer и Word, причем последний предпочтительнее, поскольку наша переменная может принимать только положительные значения (т.е. исключаются ситуации, когда переменная случайно может принять отрицательное значение)8.
8 В действительности, для переменной, значение которой соответствует дню в году, наиболее подходит интервальный тип (1..366). Об интервальных типах речь пойдет в разделе “Диапазоны” в этой главе дальше.
82
Turbo Pascal: учитесь программировать
Возможно, у читателя возникнет вопрос, для чего нужны сразу дня вида типов данных (целочисленные и вещественные), предназначенные для числовых значений, ведь любое целое число можно представить как вещественное, у которого дробная часть равна нулю? Причина все та же. Операции с целыми числами выполняются быстрее и для хранения целых чисел требуется меньше компьютерной памяти. Кроме того, операции над целыми числами всегда дают точный результат, в то время как при обработке вещественных чисел вполне возможна определенная погрешность.
Примечание
В Turbo Pascal, помимо переменных и констант, явно указываемые в программе числа тоже разделяются на целые и вещественные. Если в записи числа использована точка, то оно вещественное; если точки нет —-число целое.
Применимые операции
К значениям целочисленных типов применимы те же арифметические операции, что и к вещественным значениям. Причем если операции сложения (+), вычитания (—) и умножения с двумя целыми значениями дадут целочисленный результат, то операция деления (/), примененная к двум целым значениям, даст вещественный результат. (Об этом уже шла речь, когда мы рассматривали вещественные типы.)
Кроме обычных арифметических операций, к целочисленным значениям в Turbo Pascal применимы две специальные операции деления, обозначаемые зарезервированными словами DIV и MOD. Что собой представляют эти операции? Предположим, в программе определены две целочисленные переменные: А и В. Тогда результатом операции а div b будет целая часть частного от деления А на В. Например:
33 div 2=16;
3 div 7=0;
8 div 2=4;
А результатом операции a mod b будет остаток от деления А на В (не путать остаток с дробной частью), например:
33 mod 2=1;
3 mod 7=3;
8 mod 2=0;
Что касается операций сравнения, то здесь все обстоит так, как и с вещественными значениями (см. соответствующий раздел выше).
В заключение необходимо упомянуть, что в одном выражении могут присутствовать переменные как одного, так и разных целочисленных типов (совместимость в выражении). Кроме того, переменной целочисленного типа может быть присвоено выражение целочисленного типа, если возможные значения выражения принадлежат диапазону значений, до
Глава 4. Типы данных
83
пустимых для переменной (совместимость по присваиванию). Подробна t об этом смотри в разделе “Совместимость типов” далее в этой главе
Применимые стандартные подпрограммы
К переменным и значениям, принадлежащим одному из целочи< ленных типов, применимы процедуры и функции для работы с поряд ковыми типами, математические функции, а также некоторые функци! преобразования типов (такие как Chr, High. Low, Ord). Описания всех этих подпрограмм можно найти в Приложении Б.
Символьный тип
В Turbo Pascal принят единственный стандартный символьный тин данных — Char. Переменные этого типа предназначены для хранения отдельных символов — букв, цифр и специальных знаков. Например, если переменная Symbol принадлежит типу Char, то оператор Symbol: = ’B' присвоит этой переменной значение, соответствующее букве “В". А если этой переменной присвоить значение ’ 3', то необходимо понимать, что это всего лишь символ, а не число, над которым можно проводить арифметические действия. К символьным значениям относятся все символы таблицы ASCII9, кроме символа “штрих” ('), который используется при явном указании в программе значения типа Char.
Применимые операции
Над значениями типа Char возможны операции сравнения =, о, >, >=, <, <= (см. табл. 4.2). Причем они дают тот же результат, что и будучи применены к кодам соответствующих символов. Например, 'а'<'Ь' точно так же, как и 9 7<98 (97 — это код символа “а”, а 98 — код символа “Ь” — см. таблицу ASCII). Результатом применения операций сравнения к значениям типа Char будет значение типа Boolean (так же, как и при применении этих операций к значениям других типов).
Применимые стандартные подпрограммы
К переменным и значениям, принадлежащим символьному типу применимы процедуры и функции для работы с порядковыми типами, а также некоторой функции преобразования типов (такие как High, Low. Ord). Кроме упомянутых выше, к символьным значениям применима функция UpCase, преобразующая аргумент (значение типа Char) в символ верхнего регистра. Описания всех этих подпрограмм можно найти в Приложении Б.
9 ASCII (American Standard Code for Information Interchange — Американский стан дартный код для информационных обменов). Таблицу с кодами ASCII вы найдете в Приложении Е в конце книги.
84
Turbo Pascal: учитесь программировать
Логический тип
Переменные типа Boolean принимают значения TRUE и FALSE (правда и ложь), которые также могут быть представлены в виде двоичных цифр— соответственно 1 и О.
Применимые операции
Над значениями логического типа допустимы операции сравнения (см. табл. 4.2), причем считается, что TRUE больше FALSE. Возможно, такое утверждение вызовет недоумение, однако если эти логические значения заменить эквивалентными им двоичными цифрами, все становится на место. Конечно же 1>0.
К логическим значениям также применимы логические операции, оторые перечислены в табл. 4.4.
1 аблица 4.4. Логические операции Обозначение операции Выполняемое действие AND (И)	Логическое умножение
OR (ИЛИ)	Логическое сложение
XOR (исключающее ИЛИ)	Сложение по модулю 2
NOT (НЕ)	Логическое отрицание
Предположим, в программе определены переменные А и В, принадлежащие типу Boolean. Результаты применения к этим переменным (при различных значениях) логических операций демонстрирует табл. 4.5.
Таблица 4.5. Результаты применения логических операций
Значения	Операции
a	b	a and b	a or b	a xor b	not a
false	false	false	false	false	true
false	true	false	true	true	true
true	false	false	true	true	false
true	true	true	true	false	false
Здесь, вероятно, уместно напомнить, что результат типа Boolean возвращают операции сравнения, примененные к вещественным, целочисленным и символьным значениям (об этом уже шла речь в предыдущих разделах). Например, 4>3 имеет значение TRUE; 5.3303.22 даст значение TRUE; 'a'>’b' имеет значение FALSE.
Применимые стандартные подпрограммы
Логический тип относится к перечислимым типам, причем переменные и значения типа Boolean могут принимать только два значения: TRUE и FALSE (TRUE>FALSE).
лава 4. Типы данных
85
К переменным и значениям, принадлежащим логическому типу применимы (с учетом особенностей этого типа, изложенным в преды дущем абзаце) все процедуры и функции для работы с порядковыми ти пами, а также некоторые функции преобразования типов (такие как High, Low, Ord). Описания всех этих подпрограмм можно найти в При ложении Б.
Перечислимый тип данных
В Turbo Pascal допускается образование новых типов данных путем перечисления всех допустимых значений. Каждое значение представ ляет собой некоторый идентификатор, а перечень таких идентификаторов заключается к круглые скобки. Например, если в программе фигурируют переменные, значения которых соответствуют дням недели (допускается всего семь значений), то соответствующий тип данных и переменные можно (и целесообразно) описать следующим образом:
type
day=(Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday); var
x,y,z:day;
Объявленный здесь тип Day относится к перечислимым типам. Переменные X, Y, Z— переменные типа Day (перечислимого), объявленно го пользователем.
Конечно, переменные X, Y, Z здесь можно было бы объявить как при надлежащие типу Integer, и обозначить дни недели соответствующими цифрами. Однако цифры не всегда и не у всех ассоциируются напрямую с днями недели, поэтому предложенное выше решение следует признать более удобным и естественным.
Три переменные, соответствующие дням недели, можно объявить в программе и следующим образом:
var
x,y,z:(Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
Иными словами, перечислимый тип можно также определить ано нимно (без имени). Для этого в разделе VAR для соответствующей пере менной вместо типа следует указать (в скобках) перечень допустимых значений. Тем не менее первый подход (создание нового перечислимогс типа с именем) предпочтительнее, поскольку в этом случае программа получается нагляднее.
Имена значений перечислимого типа, указанные в круглых скобках очень удобно использовать в операторе CASE, например:
case х of
Sunday: write('Воскресенье');
Monday: write(’Понедельник');
Tuesday: write('Вторник');
Wednesday: write('Среда');
86
Turbo Pascal: учитесь программироват >
Thursday: write('Четверг');
Friday: write('Пятница');
Saturday: write('Суббота') end;
Здесь оператор CASE использован для перевода названий дней недели с английского языка на русский. (Названия дней являются здесь идентификаторами, а мы помним, что в программе на языке Turbo pascal нельзя использовать буквы русского алфавита — см. главу 1.)
Имена значений перечислимого типа, указанные в круглых скобках, считаются константами соответствующего типа. На имена этих констант распространяются правила сферы действия имен, которые мы рассматривали в главе 3. Иными словами, эти имена не должны повторяться в одном разделе описаний (программы или подпрограммы). Например:
var
х:(blue,red,white);
у:(yellow,white,green);
Здесь объявлены две переменные перечислимого типа. Среди допустимых значений обеих переменных имеется значение WHITE. Подобное описание переменных некорректно — если в программе встретится идентификатор WHITE, то не ясно, к какой переменной он относится — X или Y.
Перечислимый тип используется в примере 4.1.
Применимые операции
Считается, что представленные в скобках значения перечислимого типа упорядочены по возрастанию. Поэтому к переменным и значениям перечислимого типа могут применяться операции сравнения =, <>, >, >=, <, <= (см. табл. 4.2), если сравниваемые значения или переменные тносятся к одному типу. Например, если обратиться к объявленному ыше типу Day, то значение Sunday считается меньше значения Monday.
Применимые стандартные подпрограммы
К переменным и значениям, принадлежащим перечислимому типу, применимы процедуры и функции для работы с порядковыми типами, а также некоторые функции преобразования типов (такие как High, Low, Ord). Описания всех этих подпрограмм можно найти в Приложении Б.
Диапазоны
Для создания нового типа, помимо перечисления всех допустимых значений (перечислимый тип), можно указать некоторый диапазон значений, являющийся частью какого-либо базового типа. В качестве базо
Глава 4. Типы данных
87
вого подходит любой простой стандартный тип, за исключением веще ственных типов. При создании таким образом нового типа задаются дв< константы, определяющие минимальное и максимальное значения диапазона значений. Причем значение, определяющее начало диапазо на, не должно превышать конечное значение. Подобные типы данных называются также интервальными.
Вот примеры объявления интервальных типов:
var
х:1..12;
у:—10..10;
z:'А'..'Z';
Здесь объявлены три переменные интервального типа, причем есл для первых двух базовым является один из целочисленных типов, то да третьего — символьный тип (Char). Кстати, две точки, разделяютщ минимальное и максимальное значения интервала, рассматривают! как единый символ. Иными словами, пробел между ними недопустим.
Новый интервальный тип можно определить как в качестве аноним ного (в разделе описания переменных), так и явно, с именем (в разделе описания типов). Например:
type
Туре1=1..12;
Туре2=-10..10;
ТуреЗ='А'.. 'Z';
var
x:Typel;
у:Туре2;
z:Type3;
Приведенные в этом разделе два объявления переменных X, Y и Z вивалентны.
Интервальные типы используется в примерах 4.2, 4.3 и 4.4.
Применимые операции
Интервальный тип наследует все свойства базового типа, в том чис/ и перечень допустимых операций. Например, если значение перемет ной интервального типа представляет собой целое число, к этой пере менной применимы все операции, подходящие для целочисленных зн; чений (арифметические действия, две специальные операции делени DIV и MOD, а также операции сравнения). Какие операции применил для каждого из простых типов, мы выяснили выше.
Применимые стандартные подпрограммы
Как уже отмечалось, интервальный тип наследует все свойства ба вого типа, в том числе и перечень применимых подпрограмм. Напр мер, если значение переменной интервального типа представляет со<"
88
Turbo Pascal: учитесь программиров<
целое число, для него применимы все подпрограммы, подходящие для целочисленных значений. Какие подпрограммы применимы к значением каждого из простых типов, а также особенности их применения в каждом случае, мы выяснили выше.
Строки
Строки занимают промежуточное положение между простыми и структурированными типами данных. Почему строки нельзя отнести к простым типам? Здесь все ясно. Строка — это последовательность символов, иными словами — структура, состоящая из элементов простого типа.
Почему строки нельзя отнести к структурированным типам? Это объяснить сложнее. Во-первых, строковый тип в Turbo Pascal относится к стандартным типам данных, а ни один из структурированных типов, с которыми мы познакомимся позже, стандартным не является. (Иными словами, строковый тип в компании структурированных типов выглядел бы “белой вороной”.)
Во-вторых, над строками применимы некоторые действия, допустимые для данных простых типов и неприменимые к структурированным типам. Например, строку можно ввести с клавиатуры или вывести на экран, воспользовавшись операторами Read(x) и Write(х) соответственно, где X— строковая переменная. Также допустимо сравнивать целые строки. Однако эти действия невозможны с данными структурированных типов — массивами или записями, о которых речь пойдет позже. Впрочем, мы несколько забежали вперед. Итак, приступим к знакомству с записями.
Строковый тип данных известен также как тип STRING. (STRING — это не идентификатор, а зарезервированное слово). Тип STRING наряду с целочисленными и вещественными типами, а также типами Char и Boolean, о которых речь шла выше, относится к стандартным типам данных. Значение типа STRING представляет собой строку, длиной до 255 символов. Вот примеры таких значений:
'12345' '@#§6' 'TRUE' 'АБВГД' 'Введите значение А'
Следует понимать, что строка '12345' не имеет ничего общего с числами и над ней нельзя проводить арифметических действий, как и со значениями типа Char ' 1' ' 5' ' 8'. Также строка ' TRUE' вовсе не является значением типа Boolean.
1ак может выглядеть раздел описаний переменных, в котором объявлены переменные типа STRING:
var
a:string;
b:string[80];
1 лава 4. Типы данных
89
Как уже отмечалось, значение типа STRING представляет соб строку, длиной до 255 символов (с 1 по 255). При этом нулевой ба строки содержит информацию о ее текущей длине.
В случае, если максимальная длина строки не указана явно (как у nt ременной А в примере выше), по умолчанию она считается равной 25 символов. Однако при объявлении переменной можно задать иную Mai симальную длину строки. Так. значение переменной В (см. выше) пре ставляет собой строку длиной до 80 символов.
Текущая длина строки — величина изменяющаяся, определяем реальными данными, которая, однако, не может превышать макс мальную длину, указанную для данной строковой переменной. Как уз упоминалось, информация о текущей длине строки содержится в ее i левом байте.
Читатель может спросить, каким будет содержимое оставшихся не использованными байтов строковой переменной, текущее значение к< торой короче максимальной длины? Дело в том, что длина текущез значения строковой переменной фиксируется постоянно (в нулево байте). Благодаря этому, к “лишним” байтам просто нет доступа, поэт' му их содержимое совершенно не важно.
С примерами использования данных типа STRING мы встретит» разделе “Записи” дальше в этой главе.
Применимые действия (операции)
В этом разделе речь идет о действиях, позволяющих манипулирова строками. Причем выделяются три категории действий: применимые отдельным символам строки, строкам в целом, а также манипулиров ние длиной строки.
Действия над отдельными символами
Обратиться к отдельному символу строки можно, указав имя строко вой переменной, а также порядковый номер символа в строке. Наприме
a[5]:='F'; write(b[33]);
Поскольку отдельные символы строки представляют собой значени типа Char, над элементами строки допустимы те же действия, что и на символьными значениями — прежде всего операции сравнения =, о, >=, <, <= (см. табл. 4.2). Результатом применения этих операций к эл ментам строки будет значение типа Boolean (так же, как и при примеь нии этих операций к значениям других типов). Вот примеры исполь. вания операций сравнения с элементами строк:
if a[5]>'F' then ...
while b[ll]='4' do ...
90
Turbo Pascal: учитесь программиров^
Действия над строкой
Что касается операций над строкой в целом, то, как указывалось в начале раздела о строках, можно значения типа STRING вводить с клавиатуры и отображать на экране с помощью единственного оператора. Цапример:
read(а);
write(Ь);
В первом случае значение переменной А (цепочку символов, длина которой не превышает максимальной длины строки) придется ввести с клавиатуры (опустив при этом апострофы). Во втором случае значение строковой переменной В (последовательность символов) окажется выведено на экран.
Также можно всей строке (т.е. строковой переменной) сразу присвоить нужное значение. При этом явно заданное значение типа STRING заключается в апострофы. Например:
а:= 'Это строка'
Ь: = "
В последнем случае строковой переменной В присвоена в качестве значения так называемая “нулевая строка” (т.е. строка, включающая только нулевой символ с информацией о ее длине, которая равна нулю).
Кроме того, для строк допустима операция объединения (или сцепления, или конкатенации). Вот как это выглядит:
а:= 'Это строка, '+'которая '+'служит примером.'
После выполнения этого оператора значением переменной А станет строка:
'Это строка, которая служит примером.'
При этом, если длина объединенной строки превысит максимальную длину, допустимую для переменной А, “лишние” символы окажутся отброшены.
Операцию объединения можно применять не только к явно заданным значениям, но и к переменным типа STRING:
a:=b+c;
Здесь А, В и С — строковые переменные. В результате выполнения этого оператора текущие значения переменных В и С окажутся слиты и Полученное строковое значение будет присвоено переменной А.
Также к строкам применимы операции сравнения. Например, в программе мотут встретиться операторы:
'АВС'с'АВс';
а<Ь;
В первом случае сравниваются строковые значения, заданные явно, в° втором — переменные строкового типа.
Глава 4. Типы данных
91
Примечание
Здесь рассматриваются действия над целыми строками, осуществимые с помощью единственного оператора. А вообще действий над строками, реализуемых с помощью подпрограмм, как стандартных, так и определенных пользователем, может быть много. Этому посвящен отдельный раздел дальше.	_____ _ ___
Манипулирование длиной строки
Возможно также воздействие на длину строки. Как уже упоминалось информация о текущей длине строки содержится в ее нулевом байте, к которому можно обратиться так же, как и к остальным элементам строки, например, j:=ord(a[0])
Таким образом можно выяснить текущую длину строки. (Правда, для этого существует специальная функция Length, о которой мы узнаем дальше.) Таким же образом можно изменить текущую длину строки — например уменьшить, присвоив иное значение, чтобы "отсечь” ненужное содержимое строковой переменной.
Судя по оператору j:=ord(a[OJ) (см. выше), информация о длине строки хранится в ее нулевом байте не как число, а в виде символа из таблицы ASCII, код которого и соответствует длине. Это предположение подтверждает тот факт, что максимальная длина строки составляет 255 символов (не считая нулевого байта), а в таблице ASCII содержится 256 символов (с О по 255). Иными словами, если воспользоваться оператором write (а[ 0 ]), то на экран окажется выведено не число, а символ.
Применимые стандартные процедуры и функции
Подпрограммы, предназначенные для работы со строками, содержатся в модуле SYSTEM. Речь идет о таких процедурах и функциях, как Concat, Copy, Delete, Insert, Length, Pos, Str и VaL Их описания можно найти в Приложении Б.
Примечание
В модуле CRT имеется три процедуры, которые, как сказано в описании, также предназначены для работы со строками: ClrEoI, InsLine, DelLine. Однако в данном случае подразумеваются строки текста на экране, которые ни в коем случае не следует путать со строками как типом данных. О модулях речь пойдет в главе 8. Процеду-ры и функции модуля CRT рассматриваются в главе 10.
92
Turbo Pascal: учитесь программировать
Структурированные типы данных
Простые типы (как стандартные, так и определенные пользователем) предназначены для элементарных значений, для хранения которых достаточно единственной ячейки памяти. Однако часто при программировании различных задач возникает необходимость оперировать логически связанными наборами простых данных. Структурированные типы, которым посвящен данный раздел, как раз позволяют объединять элементарные значения в сложные структуры. К структурированным относятся такие типы данных, как массивы, записи, множества, файлы и объекты. Если массивам, записям и множествам посвящены одноименные разделы данной главы, то файлам и объектам— отдельные главы (5 и 12 соответственно).
Массивы
Одним из структурированных типов данных является регулярный тип или массив. Массив представляет собой совокупность связанных данных, состоящую из фиксированного числа элементов одного типа, который, как уже упоминалось, называется базовым. Для определения массива достаточно указать его базовый тип, а также число элементов в массиве и метод их нумерации. Возможен доступ к отдельным элементам массива — для этого достаточно указать имя массива и номер (индекс) нужного элемента. Описание регулярного типа имеет следующий вид:
type s=array [i] of a
Здесь ARRAY и OF — зарезервированные слова, имеющие смысл массив и из; S — имя регулярного типа; I —» тип индексов (указывается в квадратных скобках); А — тип элементов массива (базовый тип). Элементы массива могут представлять собой значения любого типа. Для индексирования массива в Turbo Pascal используется тип данных. Это может быть любой из целочисленных типов (за исключением Longlnt), Char и Boolean, а также перечислимый и интервальный типы (за исключением интервальных типов на основе Longlnt). Вещественные типы для индексирования массивов гге годятся.
Вот примеры описания регулярных типов (анонимных): var
al:array [byte] of boolean;
a2:array [char] of boolean;
a3:array [Red,Yellow,Green] of char;
Глава 4. Типы данных
93
a4:array [1..100] of integer;
Здесь Al (первый пример) представляет собой массив из 256 (О..255' значений типа Boolean. А2 — это массив также из 256 значений тип; Boolean, однако, в отличие от массива А1, он индексируется значениями типа Char. Обращения к отдельным элементам массивов А1 и А2 выгля дят так:
al (90]:=false;
а2 [ z ]:=true;
Содержимое массивов Al и А2 может быть следующим:
1 -й элемент	2-й элемент	3-й элемент	4-й элемент	...	256-й	элемент
TRUE	FALSE	TRUE	FALSE	. ..	TRUE
(Элементы 1 — 256 массива Al будут обозначаться числами с О п< 255, а массива А2 — символами таблицы ASCII по порядку.)
Третий пример (АЗ) представляет собой массив из трех элементов тип Char. Элементы этого массива обозначаются именами Red, Yellow и Gret (для индексирования здесь использован перечислимый тип). Пример» обращений к элементам этого массива можно видеть в табл. 4.6.
Таблица 4.6. Манипуляции над элементами массива	
Пример обращения	Комментарий
a3(Red]:=chr(100)	Элементу Red массива АЗ присваивается значение типа Char соответствующее букве “d"
a3[Red]:='d'	Эквивалент предыдущего оператора
write(a3(Yellow])	Значение элемента Yellow массива АЗ выводится на экран
read(a3[Green])	Значение элемента Green массива АЗ вводится с клавиатуры
Содержимое массива АЗ может выглядеть так:
АЗ [Red]	АЗ [Yellow]	АЗ [Green]
'А'	'8'
Наконец четвертый пример (массив А4) — это массив из 100 элеме тов, принадлежащих типу Integer. Индексным типом здесь служит hi тервальный тип (диапазон). (Кстати, для индексирования массива эт тип используется очень часто, поскольку наиболее наглядно задает гр ницы изменения индексов.)
Следует понимать, что индексы массива могут представляться i только в виде явно заданных значений, но и переменных, и выражени Предположим, в некоторой программе объявлены переменные А5 и I:
var
а5:array[1..20] of integer;
i:integer;
94
Turbo Pascal: учитесь программирова
Затем элементам массива А5 и переменной I присвоены некоторые значения. После этого в программе могут фигурировать следующие обращения к элементам массива А5:
а5[i+1];
a5[2*i];
a5[i/2-5);
a5[22-i];
При этом необходимо, чтобы значения выражений в квадратных сКобках (т.е. значения индекса) не выходили за пределы допустимых значений (в нашем случае 1 ..20).
Само собой разумеется, массивы можно объявлять не только в качестве анонимных типов, но и как типы с собственным именем — в разделе описания типов:
type
LogScale=array [byte] of boolean;
var
al:LogScale;
Читатель может заметить, что массивы очень похожи на строки. Действительно, массив — это последовательность однотипных элементов, так же, как и строка, однако если символы строки представляют собой только значения типа Char, то элементы массива могут принадлежать различным типам — как простым, так и структурированным.
Обращения к отдельным элементам строк и массивов выглядят одинаково — для этого достаточно указать имя строки или массива и индекс.
Однако имеются и отличия: если текущей длиной строки можно манипулировать, то для массивов ничего подобного не предусмотрено. Длина строки также ограничена 255 символами, в то время как для массивов такого ограничения нет. Кроме того, можно ввести или вывести значение всей строковой переменной с помощью единственного оператора (например, Read(X) или Write(X), гдеХ — значение типа STRING), а для массивов это невозможно.
В целом же вместо массива символьных значений часто можно использовать строку, и наоборот. Какому типу данных следует отдать предпочтение в том или ином случае, зависит от особенностей применения.
Последовательный доступ к элементам массива
Часто необходимо осуществить последовательную обработку элементов массива, начиная с первого. Для реализации последовательного Доступа к элементам массива очень удобно использовать оператор FOR »оператор цикла с параметром). Попробуем создать программу, в которой элементы массива обрабатываются последовательно. Текст соответствующей программы содержится в примере 4.1 (рис. 4.2).
лева 4. Типы данных
95
Пример 4.1
Рис. 4.2. Программа с последовательным доступом к элементам массива
В этой программе объявлен массив из трех элементов, предст ляющих собой значения типа Integer, причем в качестве индексного па для этого массива выбран перечислимый тип. В теле программе ществуют два цикла FOR. В первом осуществляется последователен ввод значений элементов, во втором вычисляются квадраты значегп содержащихся в элементах массива, и полученные новые значен присваиваются тем же элементам. Результаты работы програл SequentAccess демонстрирует окно Output (см. рис. 4.2).
Само собой разумеется, таким образом можно обработать содерз мое массива любого типа, включающего любое количество элементов
Поиск элемента в массиве
Часто возникает необходимость найти в массиве определенный э мент, т.е. известно, что в массиве имеется элемент с определенным 31 чением, и требуется выяснить индекс этого элемента. Программа, шающая подобную задачу, содержится в примере 4.2 (рис. 4.3).
В этой программе объявлен массив из трех элементов, предс' ляющих собой значения типа Char, причем в качестве индексного ti для этого массива выбран интервальный тип. В теле программы cyi ствуют два цикла FOR. В первом вводятся значения элементов масси а во втором значения элементов массива последовательно сравнива ся с искомым значением. Результаты работы программы Search/ демонстрирует окно Output (см. рис. 4.3). Само собой разумеется, та’
96
Turbo Pascal: учитесь программиров*.
образом можно осуществить поиск нужного значения в любом массиве, включающем любое количество элементов.
-	Пример 4.2
internet
Рис. 4.3. Программа поиска элемента
Конечно, вряд ли на практике целесообразно существование специальных программ, решающих задачу поиска элемента в массиве, однако ничто не мешает оформить соответствующий алгоритм в виде функции, которой в качестве параметра передается значение искомого элемента и которая возвращает значение индекса. За^ем такую функцию можно использовать во многих программах, манипулирующих массивами.
Дотошный читатель может заметить, что данная программа находит первый элемент, значение которого совпадает с искомым, и на этом завершает работу. А что если в массиве окажется несколько элементов с таким значением? Все верно. Усовершенствовать программу SearchArray таким образом, чтобы она выдавала перечень соответствующих индексов, читателям предоставляется самостоятельно.
Сортировка массива
Часто возникает необходимость упорядочить элементы массива. Решить эту задачу можно, например, с помощью алгоритма сортировки выбором либо алгоритма сортировки обменами. Рассмотрим каждый из способов.
Глава 4. Типы данных
97
Сортировка выбором
Предположим, имеется массив целых чисел, который требуется упс рядочить по возрастанию. Алгоритм сортировки выбором состоит в ton чтобы первое место в массиве занял наименьший элемент, второе -наименьший из всех оставшихся и т.д. Программа, решающая данну задачу, содержится в примере 4.3 (рис. 4.4).

Пример 4.3
program SortArray;
: var Ar:array [1..5] of integer;
!	i:1..5;
j.k:integer;
i begin
writel n;
writeln(' Введите пять целых чисел1);
for i:=l to 5 do read(ArEi]);
for i : =1‘ to 5 do
begi n
for k:=i to 4 do
begin
j:=Ar[i];
if j>Ar[k+l] then begin
i	Ar fi ] : =Ar[k+l] ;
Arfk+1]: =j
end
end;
writeCArEi],' ');
end; writein end.
Введите пя:ь целых чисел г 4 6 7 8 3
3 4 6 7 8	11
Введите пять целых чисел i 9 7 3 0 7
0 3 7 7 9	I
Введите пять целых чисел • 97 54 87 4 6 4 6 54 87 97
Введите пять целых чисел  876 43 7 55 5 5 7 43 55 876
Введите пять целых чисел . I 555 44 333 22 1111 22 44 333 555 1111
Рис. 4.4. Программа сортировки выбором
В этой программе объявлен массив из пяти элементов, предста ляющих собой значения типа Integer, причем в качестве индексного ti па для этого массива выбран интервальный тип. В теле программы с ществуют несколько циклов FOR. В первом вводятся значения элемег тов массива, во втором (в котором имеется вложенный цикл) реализова алгоритм сортировки выбором. Результаты работы программ SortArray демонстрирует окно Output (см. рис. 4.4 справа). В этом ою первая строка чисел — это исходное содержимое массива, вторая — с держйКюе массива после сортировки. Само собой разумеется, подобнь образом можно осуществить сортировку массива любого объема и с л; бым содержимым.
Приведенная выше программа сортирует массив по возрастали' однако часто возникает противоположная задача. Преобразовать пр грамму SortArray таким образом, чтобы она осуществляла сортирог массива по убыванию, читателям предоставляется самостоятельно.
98
Turbo Pascal: учитесь программировс
Кроме того, программа рассчитана на массив из пяти элементов. Если бы потребовалось изменить это число, пришлось бы вносить изменения по всему тексту нашей программы. Почему бы читателям не попробовать усовершенствовать программу так, чтобы число элементов массива определяла единственная константа. Тогда, чтобы задать иное количество элементов, достаточно просто ввести другое значение для этой константы.
Сортировка обменами
Вернемся к массиву из пяти целых чисел (см. предыдущий раздел), который снова требуется упорядочить по возрастанию, однако на этот раз, используя алгоритм сортировки обменами. Этот способ состоит в том, чтобы последовательно просматривать массив, сравнивая очередной его элемент с предыдущим. При этом если очередной элемент оказывается больше предыдущего, элементы меняются местами — и так до конца массива. Таким образом в результате первого просмотра наибольший элемент массива окажется перемещен на последнее место. Следующий просмотр опять начинается сначала, однако число просматриваемых элементов уменьшается на единицу. В последнем цикле просматриваются только первый и второй элементы. Программа, реализующая алгоритм сортировки обменами, содержится в примере 4.4 (рис. 4.5).
Internet
Пример 4.4
।
i I
File Edit ч- ch	is hotdogs ч tndow help
--------\МиИДОК~1\РА5САкхПРОГРА'1\СН2|-М—------—------—
program SortArrayl;	
var Аг:array Е1--5] of integer;	Введи re пять целых чисел
i:l..S;	0 9 8 7 6
j .k,m:integer;	0 6 7 8 9
begi n	
wri teln;	Введите пять целых чисел
wri telnВведите пять целых чисел1);	65 78 90 74 31
for i:=l to 5 do readCAr[i]);	31 65 74 78 30
for i:=5 dc«nto 1 do	
begin	Введите пять целых чисел
for 1 :=2 to 1 do	651 860 951 569 905
begin j:=Ar[k-l]; if j>ArEk] then begin	563 651 860 905 951
	
ArEk-l]:=ArEk];	введите пять целых чисел
Ar Ek J :=j	43£6. 9804 7337 8490 8310
end	4386 7937 8310 8490 9804
end.
LiCZ
end
end;
for i:=l to 5 do wri te(Ar[i ] , ‘ 1 );
wri teln
Введите пять целых чисел
77 9Я 66 44 11
11 44 66 77 99
Рис. 4.5. Программа сортировки обменами
Глава 4. Типы данных
99
Читатель может сравнить эту программу с предыдущег (реализующей сортировку выбором). Чтобы яснее понять разницу межд\ двумя программами, вспомним: суть сортировки выбором в том, чтоб! первое место в массиве занял наименьший элемент, второе — Hai меньший из всех оставшихся и т.д. А идея сортировки обменами в том чтобы последнее место в массиве занял наибольший элемент, предпо следнее— наибольший из остальных и т.д. Иными словами, в первоt случае отсортированный массив начинает формироваться с начала, во втором — с конца. Этим и обусловлено, что в первом случае операто цикла FOR, управляющий внешним циклом сортировки, имеет вид
for i:=l to 5 do
а во втором —
for i:=5 downto 1 do
Кроме того, поскольку во втором случае отсортированный масси! начинает формироваться с конца, выводить значения его элементов п< одному невозможно, поэтому пришлось использовать еще один опера тор цикла FOR для вывода сразу всего массива, аналогично тому, ка осуществлялся его ввод.
Так же, как и с программой сортировки выбором, читатели могуг по пытаться изменить программу, чтобы осуществлять сортировку пс убыванию и чтобы число элементов массива задавала единственная константа.
Многомерные массивы
В Turbo Pascal элементы массива могут представлять собой значеш не только простых, но и структурированных типов. Допускается, н пример, существование массивов, элементами которых являются таки массивы. Описание подобного массива выглядит так:
al=array (1..5J of array [1..4] of integer;
Этот массив можно представить в качестве двумерной матрицы с 2 элементами (4 на 5). Возможна сокращенная запись приведенного вып описания массива:
al=array (1..5, 1..4] of integer;
Эти описания эквивалентны. Обращение к одному из элемент< данного массива выглядит так:
а1[3][4]
или
а1[3,4]
А вот так выглядит этот двумерный массив (или матрица) полностью:
100
Turbo Pascal: учитесь программировг
al[1,1 ] al[2,1} al[3,l] al[4,l] al[5,lJ
al[l,2] al[2,2] al[3,2] al[4,2] al[5,2]
al[l,3J al[2,3] al(3,3] al[4,3] al[5,3]
al[l,4] al[2,4] al[3,4] al[4,4] al[5,4]
>зможны не только двумерные, но и многомерные массивы, причем число измерений не ограничивается. Однако при этом сохраняется ограничение в 64К (или 65520 байт) на размер переменных регулярного типа. Это связано с максимальным объемом памяти, выделяемой для одной переменной.
Применимые операции
13 этом разделе суммируются сведения о действиях, позволяющих манипулировать массивами. Причем выделяются две категории действии: над элементами массивов и массивами в целом.
Действия над элементами массива
Поскольку элемент массива трактуется как переменная, он может фигурировать в выражениях. (Как обратиться к элементу массива, мы выяснили выше — достаточно указать имя массива и индекс элемента.) Набор операций над элементами массива соответствует операциям, допустимым для базового типа. Какие операции и подпрограммы подходят для того или иного простого типа (которому могут принадлежать элементы массива), мы уже знаем (см. соответствующие разделы, посвященные простым типам, выше). Примеры манипулирования элементами массива можно видеть в табл. 4.7.
Таблица 4.7. Действия над элементами массива
Пример действия	Комментарий
write(6,al[5])	На экране отображается число 6, а затем значение 5-го элемента массива А1
a4[5]:=a4[3]+a4[2]	Значения 3 и 2-го элементов массива А4 складываются и полученная сумма в качестве значения присваивается элементу 5 того же массива
abc:=abc+a4[88]	Значение 88-го элемента массива А4 суммируется со значением переменной Abe и полученная сумма присваивается этой же переменной
abc:=a4[55]+a4[56]	Значения 55 и 56-го элементов массива А4 складываются и полученная сумма присваивается переменной Abe
a4[33]:=a4[33]+20	Значение 33-го элемента массива А4 увеличивается на 20
101
Глава 4. Типы данных
Действия над массивами
Что касается набора операций над массивами в целом, то скопир< вать все элементы из одного массива в другой можно единственны оператором присваивания. Например, если Хи У — массивы, припал лежащие одному типу, то правомерен оператор
х:=у;
Этот оператор копирует значения всех элементов массива Xв массив У Однако нельзя использовать с массивами операции сравнения. Не верно, например, было бы к массивам Хи У применить оператор
while х=у do...
Тем не менее, если такая необходимость существует, можно органи зовать поэлементное сравнение массивов.
Также абсолютно неприменимы к массивам арифметические и логи ческие операции.
Кроме того, напомним, что к массивам (в отличие от строк) нельз применять стандартные процедуры Read и Write. Однако можно opraHi зовать считывание или вывод на экран каждого элемента массива в о-, дельности.
Записи
Подобно массиву запись представляет собой совокупность родстве! них данных. Однако, в отличие от массива, запись может содержа г элементы, принадлежащие различным типам. Этим обуславливаются различия в механизмах доступа к отдельным элементам. Место элемег та в массиве определяется его индексом и элементы массива можно ра личным образом сортировать. Что касается записей, то здесь кажда элемент имеет собственное имя, а операция сортировки для элементе записи (т.е. полей) смысла не имеет.
Запись (или комбинированный тип данных) очень хорошо подход! для объединения разнородной информации о каком-либо объекте. Э мшут быть технические характеристики некоторого устройства, экон< мические данные предприятия или сведения о человеке. Элементы, oi разующие запись, называются полями.
Описание записи имеет вид:
type
a=record x,y:m;
z:n end;
Здесь A— имя объявляемого комбинированного типа.
102
Turbo Pascal: учитесь программироват
RECORD и END — зарезервированные слова, имеющие смысл запись конец;
X, Y. Z — имена полей;
М и N — типы, которым принадлежат те или иные поля.
После зарезервированного слова RECORD точка с запятой не ставит-я Описания отдельных полей (или групп полей, принадлежащих одному типу) завершаются точкой с запятой (кроме последнего поля перед 1ужебным словом END). Описания полей записи похожи на описания >бычных переменных. Поля могут принадлежать любым типам— как ростым, так и структурированным, как стандартным, так и определенным пользователем. Например, допустимы записи, поля которых представляют собой также записи или, например, массивы.
Количество полей в записи фиксировано и определяется описанием записи. Имена полей в пределах записи не должны повторяться. Если в программе объявлены несколько комбинированных типов, имена полей, принадлежащих разным типам, могут совпадать; конфликта имен при этом не будет, поскольку обращение к отдельным полям производится с указанием имени записи (об этом далее). Как и с другими идентификаторами в программах на Turbo Pascal, следует стремиться, чтобы имена полей соответствовали смыслу информации в том или ином поле. А информация, в свою очередь, должна соответствовать типу своего поля.
Организация данных о людях — один из наиболее типичных случаев применения записей. Например, если существует информация о какой-то группе людей (предположим, объединенных в производственный коллектив), то эту информацию лучше всего организовать в виде набора записей, где для каждого члена коллектива предусмотрена своя запись. 11ри этом все записи будут принадлежать одному типу, структуру которого определяет характер данных. Вот как может выглядеть объявление подобного типа в разделе описаний программы:
type
Employee=record
IDsword; {Идентификатор (личный номер)}
FirstName,SecondName,SurName:string[20]; {Имя, фамилия, отчество} Standing:byte; {Стаж}
Salary:real {Зарплата}
end;
var
Assistant:Employee;
Описанный выше комбинированный тип Employee включает шесть полей, три из них — FirstName (Имя). SecondName (Отчество) и SurName (Фамилия) — представляют собой строки по 20 символов каждая. (Кстати, это и есть обещанный ранее пример использования типа ' 1 RING.) Для остальных полей — ID (Идентификатор), Standing (Стаж) и Salary (Зарплата) — выбраны типы, также подходящие для соответствующей информации.
Глава 4. Типы данных
103
Содержимое одной из записей, принадлежащих типу Employee, в; глядит так:
ID	SurName	FirstName	SecondName	Standing	Salary
14873	Петров	Иван	Кузьмич	15	1000
Доступ к отдельным полям проводится с помощью составных им включающих имя записи и имя поля, разделенные точкой. Вот как моз обратиться к различным полям переменной Assistant из примера вып
Assistant.ID:=19876;
wtitefAssistant.FirstName);
read(Assistant.SecondName);
Assistant.SurName:='Петров';
a:=As s istant.Standing;
Assistant.Salary/100;
Иными словами, манипулировать полями записи можно так же переменными, с учетом типа, которому принадлежит то или иное (Указывать каждый раз составное имя — занятие не из самых ув тельных и к тому же текст программы получается громоздким, осо, если используются длинные мнемонические имена. Как сделать те программы, манипулирующей записями, более компактным, мы вы: ним в разделе “Оператор WITH”.)
Поля, предназначенные для содержания фамилии, имени и отчесз из примера выше, представляют собой строки. Поэтому ничто не меп. ет обратиться к любому из символов этих етрок, указав имя записи, ип поля и номер символа в строке. Вот как может выглядеть такое обраще ние. Этот оператор выведет на экран первую букву имени:
write(Assistant.FirstNamef1]);
Для чего нужно обращаться к отдельным буквам фамилии имени и от’ ства? Например, может возникнуть необходимость из имени и отче< “извлечь” инициалы. Вот фрагмент программы, решающий эту задачу:
write(Петров ');
write(Assistant.FirstName[1],'. ');
write(Assistant.SecondName[1],'.');
В результате выполнения этой последовательности операторог экране отобразится:
Петров И. К.
Оператор WITH
Как указывалось выше, если в операторах используются составн имена (имя записи, плюр имя поля), такие операторы получаются ресчур громоздкими. Ситуация еще больше ухудшится, если нескол! подобных операторов окажутся сосредоточены в одном месте прогр; мы. В этом случае неплохо бы каким-то образом вынести имя запи
104
Turbo Pascal: учитесь программировс
'.=7„И,К— ироводатся различные действия, в некоторый за-здать такой заголовок позволяет оператор WITH (его еще на-<ывают оператором над записями).
Оператор WITH имеет вид:
with р do s;
Использованные здесь зарезервированные слова WITH и DO имеют мысл с и выполнить соответственно. Идентификатор Р — имя пере-теннои комбинированного типа. Идентификатор S — оператор (часто оставной).
Обращения к шести полям записи Assistant, представленные выше, южно преобразовать так (предполагается, что эти операторы следуют в фограмме один за другим):
with Assistant do
begin
ID:=19876;
wtite(FirstName);
read(SecondName);
SurName:='Петров';
a:=Standing;
Salary/100
end;
Здесь имя переменной Assistant употребляется всего один раз — после оператора WITH. Затем все действия над полями (в составном операторе) выполняются только с указанием имен полей.
Иными словами, оператор WITH особенно полезен, когда обрабатывается несколько полей одной переменной комбинированного типа. Однако злоупотреблять использованием оператора WITH также не следует, поскольку в результате часто неочевидно, к чему относится тот или иной идентификатор. Например, идентификатор Assistant. ID более информативен, чем просто ID. Это особенно верно, если составной оператор, выполнение которого инициирует оператор WITH, включает множество операторов.
Иерархические (вложенные) записи
Возможно существование записей, отдельные поля которых представляют собой также записи. Для того чтобы понять, как это реализуется, попробуем добавить в описание комбинированного типа Employee (см. начало раздела “Записи”) пару полей-записей. Пусть это будут поля, содержащие информацию об адресе служащего (почтовый код, город. Улица, дом, квартира) и его дате рождения (число, месяц, год). В принципе соответствующие поля (пять полей и три поля с данными соответственно об адресе и дате рождения) можно добавить непосредственно в описание комбинированного типа Employee. А что если эту информа
Глава 4. Типы данных
105
Цию впоследствии потребуется использовать в качестве полей еще в к. ких-нибудь комбинированных типах? Поэтому лучше для адреса и дат рождения создать самостоятельные комбинированные типы в разде описаний программы, которые затем добавить как поля в тип Employee Описание этих типов может выглядеть так:
type
Addre s s=record
PostCode:1..999999; {Почтовый
City,Street:string[20];
House:word;
Apartment:word
end;
Date=record
Day:l. .31;.
Month:1..12;
Year:1900..2000
end;
NewEmployee=record
ID:word;
FirstName,SecondName,SurName
Standing:byte;
Salary:real;
BirthDate:date;
Habitation:address
end;
var
NewAssistant:NewEmployee;
код}
{Город, улица}
{Дом}
{Квартира}
{address}
{Число}
{Месяц}
{Год}
{date}
{Идентификатор (личный номер)} string[20]; {Имя, фамилия, отчество}
{Стаж}
{Зарплата}
{Дата рождения}
{Место жительства}
Описанный выше комбинированный тип NewEmployee включает во семь полей, два из которых — BirthDate (Дата рождения) и Habitation (Место жительства) — представляют собой записи, типы которых (Date и Address соответственно) объявлены перед описанием типа NewEmployee Структура комбинированного типа NewEmployee представлена на рис. 4.6.
Составные имена, с помощью которых можно обращаться к поля вложенных записей, должны включать имя основной записи, имя вл женной записи и имя поля. Например:
NewEmployee.Address.PostCode
НЛГГ
NewEmployee.Date.Day
Если имеют место несколько уровней вложения записей, состав* имена могут быть очень длинными. Однако ничто не мешает в этих cj чаях широко применять оператор WITH. Как им пользоваться, мы в’ яснили в разделе “Оператор WITH” выше в этой главе.
106
Turbo Pascal: учитесь программировч.
NewEmployee
String[20]
Рис. 4.6. Tun NewEmployee
Записи с вариантами
Иногда возникает необходимость, чтобы в зависимости от значения определенного поля записи структура этой записи частично изменялась. Например, одно из полей комбинированного типа Employee (см. начало раздела “Записи”), которое представляет собой вложенную запись, содержит информацию о месте жительства служащего. Однако городской адрес обычно выглядит не так, как загородный. Что если кто-либо из членов коллектива проживает за пределами города? Для решения этой проблемы Turbo Pascal позволяет в структуре комбинированного типа Address создать вариантную часть, в которой набор полей мог бы изменяться в соответствии с видом адреса. Итак, в структуре адреса необходима некоторая фиксированная часть — группа полей, присутствующих постоянно, независимо от характера адреса, и вариантная часть с изменяющимся набором полей. Фиксированная часть в нашем случае могла бы включать поля PostCode (почтовый код), Street (улица) и House (дом) — элементы, присутствующие в любом адресе. Вариантная часть записи для городского адреса могла бы включать поля City и Apartment (город и квартира), а для загородного адреса — поля Area (область). District (район) и Community (населенный пункт). Для управления вариантной частью адреса введем в структуру комбинированного типа Address поле City_or_Countiy (город/загород), для которого допустимы только значения City и Country. ° г как может выглядеть описание такого преобразованного комбиниро-ваиного типа (присвоим ему имя NewAddress):
Глава 4. Типы данных
type
NewAddress=record
PostCode:1..999999;	{Почтовый код}
Street:string[20];	{Улица}
House-.word;	{Дом}
case City_or_Country : City,Country of
City	:(City:string[20];	{Город}
Appartment:word);	{Квартира}
Country :(Area,District,	{Область, район}
Community:	string[20]); {Населенный	пункт}
end;	{NewAddress}
Фиксированная часть записи всегда предшествует вариантной чае Описание фиксированной части ничем не отличается от описания об: ной записи (без вариантов). Вариантная часть начинается со строки
case City_or_Country : City,Country of
которая объявляет специальное поле City_or_Country, способ: i принимать только два значения (City и Country — т.е. принадлежит речислимому типу). Это поле, которое называется полем признака (и1 если угодно, селектором выбора — по аналогии с оператором CASE), о ределяет вариантную часть записи.
Строка, начинающая вариантную часть, включает зарезервирова ные слова CASE и OF, имеющие смысл вариант и из соответствен:: Дальше следует перечень меток, представляющих собой все допустим: значения поля признака (в нашем случае две метки — City и Country После каждой метки (за двоеточием, в круглых скобках) представлен п речень полей для данного варианта, причем для каждого поля указыв; ется тип. Завершение данной конструкции (CASE-OF —перечень мето ключевым словом END не предусмотрено. Правда, в конце описан: комбинированного типа NewAddress слово END все же имеется, одна: оно здесь служит парой зарезервированному слову RECORD, а не CAS Иначе говоря, то, что мы здесь видим, вовсе не представляет собой о: ратор CASE, а является всего лишь конструкцией, внешне похожей оператор CASE, описывающей вариантную часть записи.
Структура комбинированного типа NewAddress представлена рис. 4.7.
При использовании записей с вариантами следует иметь в виду сл дующие особенности.
	В записи может быть только одна вариантная часть, котор должна быть описана непременно после фиксированной части
	Поле признака вариантной части не принадлежит ни к фиксир ванной, ни к вариантной частям и выносится в заголовок вя} антной части.
108
Turbo Pascal: учитесь программирова
	Идентификаторы всех полей записи — как в фиксированной, так и в вариантной части—должны быть уникальными (не совпадать).
	Для некоторых меток допускается “пустой вариант”. В этом случае после двоеточия следует пара круглых скобок, без перечня полей.
	Объем памяти, выделяемый для записи, определяется суммой длин полей. Объем памяти для записи с вариантами опрецеляется по самому объемному варианту.
NewAddress
String[20]
Рис. 4.7. Тип NewAddress
В созданном нами комбинированном типе NewEmployee мирно сосуществуют вложенные записи (Date и NewAddress) и записи с вариантами. Собственно, вложенная запись NewAddress одновременно является записью с вариантами. Этот пример наглядно иллюстрирует, насколько сложные структуры данных можно создавать с использованием записей.
И это еще не все. что касается сложности структур, которые позволяют создавать комбинированные типы. К сожалению, за рамками обсуждения (объем книги ограничен) остались такие интересные темы, как массивы записей и записи как параметры подпрограмм. Иными словами, когда требуется объединить в единую совокупность данные Различных типов и организовать обработку таких данных, комбинированные типы (или записи) незаменимы.
Применимые операции
в этом разделе суммируются сведения о действиях, позволяющих Манипулировать записями. Причем выделяются две категории действий: применимые к полям записей и к записям в целом.
Глава 4. Типы данных
109
Действия над полями записи
Поскольку поле записи трактуется как переменная, оно может фиг рировать в выражениях. (Как обратиться к полю записи, мы выясни выше — для этого достаточно указать имя записи и имя поля.) Наб< операций над полями записи соответствует операциям, допустим! для типа, которому принадлежит данное поле. Какие операции и п» программы применимы к тому или иному простому типу, мы уже зна (см. соответствующие разделы, посвященные простым типам, выше)
Действия над записями
Здесь, вероятно, уместно повторно упомянуть оператор WITH, торый так и называется: оператор над записями. С этим операторе который позволяет не упоминать имя записи в идентификаторе ка дого ее поля, мы познакомились в разделе “Оператор WITH" в этой гл ве выше.
Кроме того, как и с массивами, значения переменных, припадаем, щих комбинированному типу, можно присваивать другим переменю того же типа. Например, если переменные X и Y представляют собой писи, принадлежащие одному комбинированному типу, то допусти оператор присваивания
х:=у;
В результате значения всех полей записи X окажутся присвоены лям записи Y.
Однако нельзя использовать с записями операции сравнения. I верно, например, было бы к записям X и Y применить оператор
while х=у do...
Тем не менее, если такая необходимость существует, можно сравни по очереди каждое поле одной записи с полями другой.
Совершенно не применимы к записям (в целом) арифметические логические операции.
Кроме того, следует особо подчеркнуть, что к записям (подобно ма сивам, но в отличие от строк) нельзя применять стандартные процед ры Read и Write. Однако можно организовать считывание или вывод i экран каждого поля записи в отдельности.
Множества
Подобно массиву, множество— это совокупность связанных да ных, состоящая из элементов одного типа, который называется ба. вым. Однако, в отличие от массива (в котором число элементов фикс ровано), множество может включать произвольное число элементов.
Описание множественного типа:
110
Turbo Pascal: учитесь программирова
type
s=set of a
Здесь SET и OF — зарезервированные слова, имеющие смысл мно-•ство и из; S — имя объявляемого множественного типа; А — базовый ш множества.
Вот примеры описаний множественных типов и переменных, при-(длежащих этим типам:
type
al=set of 1..3;
a2=set of a..e;
a3=set of char;
var
x:al; y:a2; z:a3;
В качестве базового для множественного типа А1 задан интервальной тип (1..3). Переменная X. принадлежащая множественному типу \ 1, может принимать значения [ ], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3] всего 8 (23) значений). Иными словами, значениями множества могут Зыть все входящие в него подмножества — от нуля элементов (пустое множество) до всех возможных значений базового типа. Кстати, в Turbo Pascal допускается использование (например, в операторах присваивания) явно заданных значений множественного типа, подобно, например, целочисленным или вещественным значениям. В этом случае элементы множества задаются через запятую и все значение заключается в квадратные скобки. Например:
х:=[1,3);
х:=[];
Во втором случае переменной X присваивается так называемое пустое множество, т.е. множество, не содержащее ни одного элемента.
В качестве базового для множественного типа А2 задан диапазон а..е Переменная Y, принадлежащая множественному типу А2, может принимать значения, соответствующие всем подмножествам, входящим в это множество (всего 32 (25) значения).
Наконец, в качестве базового для множественного типа АЗ выбран стандартный тип Char. Число значений, которые может принимать переменная Z (объявленная как принадлежащая типу АЗ), равно 225е, причем значения эти представляют собой произвольные наборы символов Из таблицы ASCII. Например, переменная Z может иметь значение
Значение переменной Z можно представить и так:
[chr(45),chr(54),chr(58),chr(65),chr(73),chr(78),chr(89)].
11омимо того, что множество может включать произвольное число здементов, имеет место еще одно отличие множеств от массивов. Если
111
глава 4. Типы данных
массив — это упорядоченная совокупность элементов, то в множесп порядок элементов никак не фиксируется. Так, [1,2,3,4,5] и [5,2,1,4, — это одно множество. Кроме того, все элементы в множестве должн быть различными. Иными словами, [1,2,3] и [1,1,2,3,3,3] —это таки одно множество.
Представление множества возможно путем перечисления входящи в него элементов или заданием диапазона (если члены множества обр зуют неразрывную последовательность), т.е. множество [1,2,3,4, можно также представить как [ 1.. 5 ]. Допускается сочетание двух мет< дов:[1..5,7,9].
Число элементов множества в Turbo Pascal не должно превышать 2 (причем, для целочисленных типов эти значения должны лежать в ди пазоне (0. 255).	Вследствие этого ограничения в качестве базовьг
типов для множеств (из стандартных типов) могут служить только Byt Char и Boolean. Вам не удастся использовать для множества в качесч базового, например, тип Integer, хотя подходят интервальные типы, о( разованные на основе Integer.
Применимые действия
Набор допустимых для множеств операций включает проверку npi наддежности элемента множеству; объединение, пересечение и вычит ние множеств; сравнение множеств (проверку равенства и неравенсп множеств, а также проверку принадлежности одного множества другому
Проверка принадлежности элемента множеству
Для этой операции в Turbo Pascal имеется специальный оператор I Выражение с этим оператором возвращает значение типа Boolean. В пример использования оператора IN:
a in [1,3,5,7,9]
Это выражение проверяет, принадлежит ли значение переменной данному множеству и возвращает значение TRUE либо FALSE. В случ. если бы оператора IN не существовало, нам пришлось бы воспольз ваться гораздо более громоздким выражением для проверки данного у ловил:
(а=1).аг (а=3) or (а=5) or (а=7) or (а=9)
В случае, если переменная А принадлежит множеству [ 1,3,5,7, оба выражения возвратят значение TRUE.
Еще примеры:
3 in [1,3,5,7,9];
4 in [1,3,5,7,9];
Эти выражения возвратят значения TRUE и FALSE соответственно
112
Turbo Pascal: учитесь программирог
Объединение, пересечение и вычитание множеств
Эти операции, будучи применены к двум множествам, формируют третье. В Turbo Pascal эти операции обозначаются символами: + (объединение), * (пересечение), - (вычитание).
В результате объединения двух множеств А и В формируется третье, содержащее все элементы, встречающиеся в первых двух множествах (см. рис. 4.8). Примеры можно видеть в табл. 4.8.
Таблица 4.8. Примеры объединения двух множеств
Объединение множеств	Результат
[1,2,3,4,5,]4 [3,4,5,6,7] [1,2]+[3,4] ['a','b','c']+['A',’B','C'] ['1','3','5','7','9']+['1','3','5','А','В']	[1,2,3,4,5,6,7] [1,2,3,4] ['а','Ь','с','А','В','С'] ['1’,'3','5','7','9','А','В']
Примечание
Часто вооникает необходимость добавить в множеств! новый элемент (частный случай операции объединения). Эта задача может быть решена следующим образом:
[1,2 3,4,5]+[6]
В результате пересечения двух множеств А и В формируется третье множество, содержащее только элементы, одновременно принадлежащие первым двум множествам (см. рис. 4.8). Примеры можно видеть в табл. 4.9.
Таблица 4.9. Примеры пересечения двух множеств
Пересечение множеств	Результат
[1,2,3,4,5,]*[3,4,5,6,7 ]	[3,4,5]
[1,2]*[3,4]	[]
['а','Ь','с']*['А','В','С']	[]
['1','3','5','7','9']*['1','3’,'5','А','В']	['1-,-3','5']
При вычитании множества В из множества А, формируется третье множество, содержащее только элементы, принадлежащие множеству А и не принадлежащие множеству В (см. рис. 4.8). Примеры можно видеть в табл. 4.10.
Таблица. 4.10. Примеры вычитания множеств
Вычитание множеств	Результат
[1,2,3,4,5,]-[3,4,5,6,7]	[1,2]
[1,2]-[3,4]	[1,2]
['а','Ь','с']-['А’,'В','С']	['а','Ь','с']
_Г1',' 3',' 5',' 7',' 9']-[ '1','3','5','А’,'В']	['7','9']
Глава 4. Типы данных
113
Необходимо иметь в виду, если в случае объединения и пересечения множества А и В поменять местами, результат не изменится, однако это вовсе не так для вычитания множеств. Пример можно видеть в табл. 4.11.
Таблица 4.11. Перестановка множеств при вычитании
Вычитание множеств	Результат
[' 1',' 3',' 5',' 7 ',' 9' ]' 1',' 3',' 5','А','В']	('7','9']
['1','3','5','А','В']-['1','3','5','7','9']	['А','В']
Операции объединения, пересечения и вычитания множеств А и В можно представить графически, если изобразить эти множества в виде некоторых фигур (например, кругов), закрашенные части которых соответствуют множествам-результатам (рис. 4.8).
Объединение (А+В)
Пересечение (А*В)
Рис. 4.8. Объединение, пересечение и вычитание множеств
Вычитание (А-В)
Сравнение множеств
К операциям сравнения множеств относятся проверка равенства и неравенства множеств, а также проверка принадлежности одного множества другому. Символы, которыми в Turbo Pascal обозначаются эти операции, представлены в табл. 4.12 вначале данной главы.
Таблица 4.12. Операции сравнения множеств
Обозначение	Действие
=	Проверка равенства множеств
<	>	Проверка неравенства множеств
<	=	Проверка вхождения множества слева в множество справа
>	-	• *	Проверка вхождения множества справа в множество слева
Результат сравнения представляет собой значение типа Boolear (TRUE или FALSE — в зависимости от успеха проверки). Два сравнивав мых множества должны иметь один базовый тип.
Операции = и о проверяют, совпадает ли набор элементов в сравни ваемых множествах. Примеры этих операций можно видеть в табл. 4.1-и 4.14.
114
Turbo Pascal: учитесь программировав
'блица 4.13. Проверка равенства множеств	
Сравниваемые множества	Результат
[1,2,3]=[1,2,4]	FALSE
[1,2,3]=[1,2,3]	TRUE
[1,2,3] = [3,2,1 ]	TRUE
[1,2]=[1,1,2,2,3]	FALSE
аблица 4.14. Проверка неравенства множеств	
Сравниваемые множества	Результат
[1,2,3]<>[1,2,4]	TRUE
[ 1,2,3 ] <> [ 1,2,3 ]	FALSE
[1,2,3]<>[3,2,1]	FALSE
[1,2]<>[1,1,2,2,3]	TRUE
Операции <= и >= проверяют, входит ли одно множество в другое. Множество слева входит в множество справа, если все элементы левого множества встречаются среди элементов правого множества. Примеры проверок по вхождению одного множества в другое представлены в табл. 4.15 и 4.16.
Таблица 4.15. Проверка вхождения левого множества в правое	
Сравниваемые множества	Результат
[1,2,3]<=[1,2]	FALSE
[1,2,3]<=[1,2,3,4,5]	TRUE
[1,2,3]<=[4,3,2,1]	TRUE
[1,2,3]<=[1,3]	FALSE
Множество справа входит в множество слева, если все элементы правого множества встречаются среди элементов левого множества.
Табл. 4.16. Проверка вхождения правого множества в левое	_	
Сравниваемые множества	Результат
[1,2,3]>=[1,2]	TRUE
[1,2,3]>=[1,2,3,4,5]	FALSE
[1,2,3]>=[4,3,2,1]	FALSE
__ [1,2,3]>=[1,3]			TRUE
Пример программы
Читатель мог заметить, что, в отличие от других структурировэнных типов, практическая ценность множеств неочевидна. Действительно, если говорить о массивах и записях, то вопроса, для чего нужны эти типы, как-то не возникает, тем более, что в посвященных им разделах этой книги имеются конкретные примеры использования данных соответст
Глава 4. Типы данных
115
вующих типов. Однако не так обстоит дело с множествами. Кроме все’' прочего, множества, например, нельзя вводить с клавиатуры и выво дить на экран (даже по одному элементу за раз), используя стандартны процедуры Read и Write. Словом, места для сомнений хоть отбавляй
Так вот, чтобы устранить сомнения, рассмотрим программу, в ко торой используются множества. Программа использует метод решет Эратосфена для вычисления простых чисел10, лежащих в определен ном диапазоне. Это классический пример использования множеств, подобные программы можно обнаружить во многих книгах, посвященных Turbo Pascal. Программа, о которой идет речь, содержится примере 4.5.
Пример 4.5
program prime;
const n=255;
var
sieve, primes : set of 2..n;
next, i : integer;
begin writein;
sieve:=[2..n];
primes:=[];
next:=2;
repeat
while not (next in sieve) do next:=next+l;
primes:=primes+[next];
i:=next;
while i<=n do
begin
end
sieve:=sieve-[i]; i:=i+next;
until sieve=[];
for i:=2 to n do
if i in primes then write(i:4); writein
end.
Решето Эратосфена функционирует следующим образом. Берется минимальное простое число (2) и добавляется в результирующее множество Prime. Затем из исходного множества Sieve удаляются все числа, кратные этому простому числу. Каким образом удаляются кратные числа? К значению переменной I циклически прибавляется очередное простое число, затем полученное число (кратное простому) удаляется из ис-
10 Простыми называются числа, делящиеся без остатка только на 1 ина само себя.
116
Turbo Pascal: учитесь программировать
-дного множества — и так до тех пор, пока не будет достигнут конец тожества. Затем из исходного множества берется следующее число, горое после удаления всех кратных предыдущему простому числу, га-штированно также будет простым, и все повторяется снова — до тех ,i р, пока исходное множество не окажется пустым. Наконец, сформированное таким образом результирующее множество Prime выводится ца экран. Вывод на экран представленной выше программы можно видеть на рис. 4.9.
К сожалению. Turbo Pascal не позволяет находить таким образом простые числа за пределами диапазона О..255. Почему — читателю уже известно. В данном разделе (посвященном множествам) выше указывалось, что число элементов множества в Turbo Pascal не должно превышать 256, причем для целочисленных типов эти значения должны лежать в диапазоне О..255.
Теперь представим на минуту, что Turbo Pascal множеств не поддерживает. Тогда, чтобы выяснить, принадлежит ли данное значение определенному набору значений, пришлось бы использовать большое количество операторов IF (в нашем случае до 256). Легко вообразить, какой громоздкой в этом случае получилась бы программа.
Совместимость типов
В Turbo Pascal различают два вида совместимости типов: совместимость в выражении и совместимость по присваиванию. Совместимость
глава 4. Типы данных
117
первого вида позволяет операндам разных типов присутствовать в о., ном выражении. Правила второго вида совместимости (которые мене строги) определяют, в каких случаях справа и слева от оператора при сваивания мо1ут фигурировать выражения разных типов.
Совместимость в выражении
Два типа данных считаются совместимыми в выражении, если сс. блюдается хотя бы одно из следующих условий.
	Типы идентичны.
	Оба типа принадлежат вещественным типам (возможно, разным)
	Оба типа принадлежат целочисленным типам (возможно, раз ным).
	Один тип представляет собой поддиапазон другого.
	Оба типа представляют собой поддиапазоны одного и того ж третьего (базового) типа.
	Оба типа представляют собой множества с совместимыми базе выми типами.
	Один тип является строковым, а второй — строковым либо сим вольным.
	Один тип является нетипизированным указателем (POINTER), второй — любым другим ссылочным типом (об указателях реч! пойдет в главе 6.)
Совместимость по присваиванию
Выражение считается совместимым по присваиванию с переменной если соблюдается одно из следующих условий.
	Типы идентичны и ни один из них не является файлом или не принадлежит иному структурированному типу, компонентам! которого являются файлы (о файлах речь пойдет в главе 5).
	Оба принадлежат совместимым порядковым типам и при это возможные значения выражения принадлежат диапазону значе ний, допустимых для переменной.
	,Q6a принадлежат вещественным типам и при этом возможны значения выражения принадлежат диапазону значений, допус тимых для переменной.
	Переменная относится к одному из вещественных типов, выра жение — одному из целочисленных типов, и при этом все воз можные значения выражения принадлежат диапазону значений допустимых для переменной.
118
Turbo Pascal: учитесь программировав
	Переменная принадлежит строковому типу, а выражение — символьному.
	Оба принадлежат совместимым множественным типам и при этом возможные значения выражения принадлежат диапазону значений, допустимых для переменной.
	Оба являются совместимыми типами указателей (подробнее об указателях сказано в главе 6).
Если переменная и выражение совместимы по присваиванию, данное выражение может быть присвоено переменной и при этом ошибки зафиксировано не будет.
Приведение типов
Бывают случаи, когда без использования в операторе присваивания переменных разных типов не обойтись. Тогда можно применить допускаемый Turbo Pascal прием, известный как приведение типов переменных. Предположим, в некоторой программе раздел описания переменных выглядит так:
var
х:typel;
y:type2;
После того как переменные X и Y в программе получат некоторые значения, допустимы такие операторы присваивания:
x:=typel(y);
y:=type2(x);
В первом операторе значение переменной Y (типа type2) трактуется как принадлежащее типу typel и присваивается переменной X (т.е. тип type2 приводится к типу typel). В этом случае данные типа type2 рассматриваются как данные typel, к которым просто можно обратиться с помощью идентификатора Y. Второй оператор проделывает то же со значением переменной X, которое присваивается переменной Y.
Конкретизируем пример. Предположим, что typel — это Char, а type2 — Byte. Известно, что для переменных этих типов требуется один байт памяти, поэтому при преобразовании из одного типа в другой дан НЫе в этом случае ни расширяются, ни сокращаются. Для переменных и Yдопустимы операторы присваивания:
x:=byte(y);
y:=char(x);
Здесь первый оператор присваивает переменной X (принадлежащей типу Char) значение переменной У (типа Byte), представляя его при этом
Глава 4. Типы данных
119
тоже как принадлежащее типу Char. А второй оператор приводит тип Char к типу Byte.
При приведении типов преобразуемый тип и тип, к которому проис ходит преобразование, должны быть перечислимыми или указателями.
Помимо приведения типов переменных, Turbo Pascal допускает при ведение типов значений:
type(expression);
Здесь Expression — выражение, принадлежащее некоторому типу которое данный оператор позволяет трактовать как принадлежащее ти пу Туре (т.е. выражение Expression здесь приводится к типу Туре), на пример:
byte(’F’);
Здесь выражение 'F' приводится к типу Byte (т.е. символ преобрази ется в соответствующий код).
Еще пример:
char(77);
В этом случае целочисленное значение (являющееся частным случа ем выражения) 77 преобразуется в символ, соответствующий данному коду. Несколько примеров приведения типов можно видеть в табл. 4.17.
Таблица 4.17. Примеры приведения типов
Действие	Результат
Boolean(O)	FALSE
Boolean(1)	TRUE
Char(57)	’9'
lnteger('9’)	57
При приведении типов значений может иметь место как расшире ние, так и сокращение размера исходного значения. В случае расшире нии значения его знак всегда сохраняется.
Разумеется, приведение типов возможно для данных не только стат-дартных, но и созданных пользователем типов.
120
Turbo Pascal: учитесь программирова
В этой главе...___________________________
	Файловые типы и файловые переменные
	Операции над файлами
	Типизированные, текстовые и нетипизированные файлы
Файловый тип принципиально отличается от других типов данны> с которыми мы познакомились в предыдущей главе. Именно поэтом файлам посвящена отдельная глава. Здесь мы узнаем о том, какие сугщ ствуют типы файлов и как можно манипулировать информацией, с< держащейся в файлах.
Что такое файл
Типы данных, с которыми мы до сих пор имели дело, предназначен! для манипулирования информацией, содержащейся в оперативной па мяти компьютера. Однако, как известно, оперативная память способн хранить данные только временно — пока компьютер включен. Предста вим, что в течение дня производился какой-то сложный расчет, к р< зультатам которого придется обращаться впоследствии— иногда многс дней спустя. Как сохранить эти результаты, чтобы они были в целости i сохранное ги, постоянно под рукой, и при этом иметь возможность вы ключать компьютер, когда необходимо? Очевидно, что для эффектив ной работы нужен какой-то способ продолжительного хранения инфор мации, чтобы ею можно было воспользоваться после выключения включения компьютера снова. И такой способ существует. Для дол! временного хранения информация из оперативной памяти переносите в файлы11. Файл представляет собой некоторое поименованное место  внешнем носителе. В качестве внешнего носителя могут служить разн го рода диски (жесткие, гибкие, магнитооптические, компакт-диск! Zip- и Jaz-диски и т.д.), а также магнитные ленты. Наконец, в качеств этакого “условного” внешнего носителя могут рассматриваться вирт альные диски, которые можно создавать (с помощью команды VDISK) оперативной памяти компьютеров, работающих под управлением оп рационной системы MS DOS12.
Кроме “долговременности” у файлов имеется еще одна отличител ная особенность: их неопределенный объем (или длина). Если для к ждого из прочих структурированных типов всегда точно определен сколько элементов содержит то или иное значение, то сколько элемет тов должно быть в файле, при объявлении файлового типа не указ | вается. Максимальная длина файла ограничивается только свобг ным местом на диске, и это является основным отличием файлов < массивов. * '4
11 Английское слово File переводится как архив, подшивка, картотека— ины/ словами, хранилище информации.
12 Правда, такой виртуальный диск не решает главной задачи — долговременно-хранения данных, но создавать на нем файлы и записывать в них информащ можно так, словно это обычный магнитный диск.
122
Turbo Pascal: учитесь программирова
Файловые типы и файловые переменные
Все сказанное выше относится к долговременному хранению информации в компьютерах вообще. А как это реализовано в Turbo Pascal? Для сохранения информации в Turbo Pascal предусмотрена возможность определять файловые типы и файловые переменные. После этого информацию, которая может потребоваться впоследствии (те же результаты расчета, например), можно перенести в файл на диске (подробностям, как это делается, и посвящена данная глава). Существует три способа определения файлового типа (или файловой переменной): f=file of а;
f=text;
f=file;
Эти три способа соответствуют трем видам файлов, которыми позволяет оперировать Turbo Pascal. Речь идет (по порядку) о типизированных, текстовых и нетипизированных файлах. (Каждый из указанных видов имеет особенности, поэтому каждому из них дальше в этой главе будет посвящен свой раздел.) Вот как трактуются слова и обозначения в представленных выше объявлениях типов13:
FILE и OF — зарезервированные слова, имеющие смысл файл и из;
Text — это не зарезервированное слово, а идентификатор стандартного типа данных — как, например. Integer или Real;
F — имя объявляемого файлового типа или файловой переменной;
А— тип элементов, содержащихся в файле (любой тип кроме файлового).
Элементы файла могут представлять собой значения любого типа за исключением файлового, либо структурированного типа, элементами которого являются файлы, т.е. существование “файла файлов” не допускается. Вот примеры объявлений файловых переменных:
type
arrays:array of integer;
Date=record
Day:1..31;	{Число}
Month:1..12;	{Месяц}
Year:1900..2000	{Год}
end;	{date}
Здесь и дальше договоримся считать, что термины “типизированный”, ^текстовый” и “нетипизированный” характеризуют вид файла. А тип файла — эгЛо характеристика той или иной файловой переменной или файлового типа, Представленная в разделе VAR или TYPE программы.
Глава 5. Файлы	123
var
flzfile;
f2:text;
f3:file of integer;
f4: file of arrays; f5: file of date;
Выше объявлены пять файловых переменных. Среди них F1 — эт нетипизированный файл, F2 — текстовый, a F3, F4 и F5 — типизиро ванные файлы. Причем если среди типизированных файлов элемент файла F3 относятся к стандартному типу (Integer), то элементы файлов F4 и F5 — к типам, объявленным пользователем (тип Arrays представляет собой массив целых чисел, а тип Date — запись).
Как уже отмечалось, файлы, принадлежащие разным видам, имею свои особенности, однако существует и нечто общее, присущее все* файлам. Так, в файле в каждый момент может быть доступен толькс один элемент. Например, если вернуться к объявленным выше файло вым переменным, то в файле F3 каждую минуту можно иметь доступ к одному из целых чисел, из которых состоит файл; в файле F4 — к единственному массиву; наконец, в файле F5— к отдельно взятой записи Кроме того, файлы всех видов завершаются маркером конца файл (EoF—End of File).
Доступ к элементам файла обычно осуществляется последовательно путем их поочередного перебора. Иными словами, для того чтобь “добраться” до последнего элемента, прежде придется обработать (считать или записать) все предыдущие. Кроме того, для типизирован ных и нетипизированных файлов возможен переход к определенном}, элементу (минуя предыдущие — об этом далее).
Число элементов файла определяет его объем, или длину. Как уже отмечалось, длина файла при его объявлении не фиксируется. При этот, допускается существование файлов, не содержащих ни одного элемен та — такие файлы называются пустыми (сравните: пустое множество).
Попробуем представить себе все это наглядно. Указывалось, что ин формация (как правило) записывается на дисках. На поверхности диске имеются дорожки, расположенные по концентрическим окружностям которые и содержат информацию. Схематически это показано не рис. 5.1. (Разумеется, если взглянуть на поверхность реального диска никакой информации и дорожек разглядеть не удастся — так же, как не магнитофонной ленте не видно музыки.)
Рис. 5.1 позволяет представить, как информация содержится на ди* ке. Хорошо бы так же наглядно изобразить файл с информацией. Да вайте попытаемся это сделать. Как указывалось выше, информация н диске записывается на дорожках, располагающихся по концентриче ским окружностям. Поэтому логично представить файл в виде части до рожки — сектора (рис. 5.2).
124
Turbo Pascal: учитесь программировав
Элементы файлов
Рис. 5.1. Поверхность диска и дорожки
Рис. 5.2. Визуальное представление файла
Здесь изображен файл, содержащий пять элементов. Начинается файл идентификатором, который обозначен буквой f. Далее следуют несколько элементов и завершается файл маркером конца файла (EoF). Элементы, образующие файл, представляют собой значения, принадлежащие любому простому или структурированному типу, за исключением файлового. Стрелка на рисунке представляет собой указатель текущей позиции файла. Для чего этот указатель нужен? Если инициировать запись в файл или считывание из файла, запись будет проводиться, начиная с элемента, перед которым расположен указатель текущей позиции. Это же касается и считывания. Чтобы подчеркнуть,
лава 5. Файлы
125
что длина файла не ограничена, изображенный здесь сектор справа не замкнут.
Разумеется, данное визуальное представление файла очень условно Часто файл занимает не часть дорожки, а несколько дорожек. Кроме того, никакой стрелки в реальности не существует. Тем не менее, пред ставленные изображения должны помочь читателю лучше понять принципы сохранения данных в файлах на диске.
Это визуальное представление файла (вернее, его вариации) исполь зуется в дальнейшем при изучении различных операций над файлами.
Операции над файлами
В отличие от других типов данных, в Turbo Pascal нет встроенных операторов, предназначенных для манипулирования файлами. Напри мер, не удастся с помощью оператора присваивания присвоить файло вой переменной некоторое значение. В силу этого соответствующие операции реализованы в виде процедур и функций. Файловые процеду ры и функции условно можно разделить на пять групп.
	Организующие доступ к файлам
	Осуществляющие ввод-вывод
	Предназначенные для ориентирования в файле
	Специальные операции
	Завершающие операции
Рассмотрим процедуры и функции, относящиеся к каждой из групп.
Организация доступа к файлам
Поскольку файлы, в отличие от данных других типов, содержатся так называемом вторичной памяти (т.е. на дисках), для доступа ь файлам недостаточно только объявить файловую переменную. Дейст виям, необходим для подготовки обмена с файлами, и посвящен дан ный раздел.
Файловые переменные и реальные файлы. Процедура Assign
Присмотримся к объявленным выше файловым переменным Fl—F5 Здесь для каждой переменной указан идентификатор, вид соответст вующего файла и тип данных, которому должны принадлежать элемен
126
Turbo Pascal: учитесь программироват
ы того или иного файла (если данный файл относится к типизирован-1 im). Достаточно ли этого для манипулирования содержимым файлов?
если да, то каким образом наши действия над файловой переменной могут повлиять на конкретный файл на диске. Ведь при объявлении айловой переменной не указывается ни имя файла, ни в каком катало-
он содержится? Все верно. Для того чтобы конкретный файл стал дос-тпным, его необходимо как-то связать (или ассоциировать) с ранее । ьявленной файловой переменной. Такое связывание осуществляется помощью процедуры Assign, которая является стандартной процеду-( й Turbo Pascal.
Заголовок процедуры Assign выглядит следующим образом:
Assign(var f; file_name:string);
Здесь F — имя файловой переменной любого вида, с которой ассо-шруется файл с диска, имеющий имя FILE_NAME (параметр ILE_NAME принадлежит типу STRING). Обобщенный вид имени файла. >торое строится по правилам имен операционной системы MS DOS перационная система, под управлением которой работают многие рсональные компьютеры), выглядит так:
диск:\путь\имя_файла
Вот каков смысл отдельных составляющих этого обобщенного имени:
ДИСК: — это буква, обозначающая один из дисков компьютера. На->имер, А: или В: — гибкие диски; С:—Z: — жесткие диски, компакт-гски и прочие диски.
ПУТЬ — это каталог (или цепочка каталогов, указывающая располо-ение нужного файла на диске). Файл обнаружить не удастся, если не 1ать, в каком каталоге он содержится.
Наконец, ИМЯ_ФАЙЛА— идентификатор определенного файла в >еделах данного каталога.
Структурная схема, представленная на рис. 5.3, позволит лучше полть, как может выглядеть иерархия каталогов и файлов на диске.
На этой схеме представлен диск С:, на котором содержатся три катало-(SYS. PROGRAMS и DOC) и три файла (CONFIG.SYS, AUTOEXEC.BAT и )MMAND.COM). В каждом из указанных каталогов также содержатся налоги и файлы. Например, в каталоге SYS на этой схеме содержится >еди прочих) файл INFO. SYS. Так вот, путь к этому файлу выглядит едующим образом:
с:\sys\info.sys
С правилами MS DOS д ля имен мы познакомимся в следующем разделе.
ава 5. Файлы
127
Каталоги
Рис. 5.3. Структурная схема диска
Имена файлов
Имя файла включает до восьми символов и может быть дополнеис расширением (до трех символов). Имя и расширение разделяются точкой. В имени файла могут встречаться строчные и прописные латин ские буквы, цифры, а также символы ! @	% л	.Втоже
время в именах файлов (и в расширениях) ни в коем случае не должнс быть символов ?.,;:*/ \ + " |. Символы, допустимые для имен файлов, следует использовать и в именах каталогов.
Вот как можно в программе на Turbo Pascal связать файл на диске с объявленной файловой переменной:
var
fl:file;
begin
assign(fl,'c:\sys\info.sys');
end.
Устройства с символическими именами
В качестве параметра процедуры Assign вместо имени файла с диск можно использовать зарезервированное (за некоторым устройстве, имя. В MS DOS основным аппаратным средствам ПК присвоены симы лические имена, которые можно использовать в операциях ввод
128
Turbo Pascal: учитесь программиров m
вывода вместо имен файлов14. Перечень этих символических имен и соответствующих им устройств представлен в табл. 5.1.
Таблица 5.1. Символические имена устройств, принятые в MS DOS
Символическое имя	Устройство
CON	Консоль
PRN, LPT1, LPT2, LPT3	Принтеры
AUX, С0М1, COM2	Коммуникационные каналы
NUL	Фиктивное устройство
Рассмотрим упомянутые зарезервированные имена подробнее.
CON — символическое имя консоли. Под консолью подразумеваются одновременно и клавиатура, и монитор компьютера. Логическое имя CON можно указать для процедуры Assign вместо имени файла, когда информацию требуется ввести с клавиатуры или вывести на экран. Как система определяет, с клавиатурой или монитором ей следует иметь дело в том или ином случае? Система ориентируется по выполняемой операции. Вывести данные можно на экран, но не на клавиатуру, а ввести — только с клавиатуры.
PRN — символическое имя принтера. Его можно указать в качестве параметра процедуры Assign (вместо имени файла), когда требуется распечатать информацию на принтере. Что если к одному компьютеру подключены несколько принтеров? В MS DOS для принтеров предусмотрены еще несколько символических имен: LPT1, LPT2, LPT3, причем имена PRN и LPT1 взаимозаменяемые (или синонимы).
AUX— символическое имя коммуникационного канала. Коммуникационный канал предназначен для обмена информацией с другими компьютерами либо устройствами, подходящими для подключения к этому каналу. Символическое имя AUX можно указать в качестве параметра процедуры Assign, когда требуется передать информацию на другой компьютер (или устройство) либо принять ее извне. Но ведь у персонального компьютера обычно более одного коммуникационного канала! Верно, ситуация здесь такая же, как с принтерами. Помимо AUX, в MS DOS определены еще два символических имени для коммуникационных каналов — СОМ 1 и COM2, причем СОМ 1 и AUX — синонимы.
Наконец NUL— символическое имя так называемого фиктивного устройства. Предположим, идет процесс отладки некоторой программы, оперирующей объемными файлами. В этой программе среди прочих имеются операции вывода данных. Однако место надиске ограничено, а осуществлять вывод на экран не всегда удобно, и главное, в данный мо
J символические имена в MS DOS являются зарезервированными. Иными слова лщ, не удастся создать файл с именем, соответствующим зарезервированному за одним из устройств.
Глава 5. Файлы	^29
5 2016
мент интересует не сама информация а процесс ее вывода. В этой cj туации очень удобно в качестве устройства вывода указать фиктивн< устройство, чтобы ненужная информация в процессе отладки отпраг лялась “в никуда”.
Вот примеры ассоциирования файловых переменных с различным логическими устройствами:
var
fl,f2,f3,f4,f5:file;
begin
assignff1,'CON');
assign(f2,'LPT1');
assign(f3,'PRN');
assign(f4,'AUX');
assign(f5,'NUL');
end.
В завершение разговора о процедуре Assign заметим, что до выпол нения над файлом каких-либо действий всегда необходимо обратиться этой процедуре. После вызова процедуры Assign, связь между указан ными файлом и файловой переменной существует вплоть до заверше ния работы программы, либо пока к этой файловой переменной сн не будет применена процедура Assign.
Открытие файла
Открыть файл в Turbo Pascal можно для чтения, для записи, а так: для чтения и записи одновременно. До открытия файл должен быть св: зан (с помощью процедуры Assign) с ранее объявленной файловой пер менной. При открытии файла ищется уже существующий файл на ди< либо создается новый (если файл открывается для записи) и текущ: указатель устанавливается в начало файла.
Для открытия файлов предназначены процедуры Reset, Rewrite и А pend. Причем если процедуры Reset и Rewrite подходят для открыт: файла любого вида, то с помощью процедуры Append можно откры только текстовый файл. В силу этого первые две процедуры мы ра смотрим здесь, а третью — в разделе, посвященном текстовым файла <
Процедура Reset
Эта процедура, примененная к текстовому файлу, открывает е только для чтения. Процедура Reset, примененная к типизированном или нетипизированному файлу, открывает его как для чтения, так и д записи. Заголовок процедуры Reset выглядит следующим образом:
Reset(Var f [ : File; Recsize : Word ] );
130
Turbo Pascal: учитесь программировал
где F файловая переменная любого типа, с которой ассоциирован (с помощью процедуры Assign) некоторый файл либо устройство с символическим именем.
RecSize — необязательный параметр15, определяемый только для не-типизированных файлов и указывающий размер записи, которыми будет осуществляться передача данных. Если параметр RecSize при вызове процедуры Assign не определен, по умолчанию размер записи принимается равным 128 байт. (Подробнее о записях и обмене с нетипизи-рованным файлом — в разделе “Нетипизированные файлы”.)
Файл, открываемый с помощью процедуры Reset, непременно должен уже существовать. Если файла с таким именем и в указанном каталоге не окажется, имеет место ошибка. Что касается устройства с символическим именем, то это обязательно должно быть устройство, способное служить источником считываемых данных. Если, например, инициировать считывание информации с принтера, также будет иметь место ошибка.
Файл, открытый с помощью процедуры Reset, изображен на рис. 5.4.
Рис. 5.4. После открытия файла с помощью процедуры Reset указатель текущей позиции расположен перед первым элементом
Процедура Rewrite
Эта процедура, будучи применена к текстовому файлу, открывает его только для записи. Процедура Rewrite, примененная к типизированному или нетипизированному файлу, открывает его как для чтения, так и для записи.
В чем отличие между процедурами Reset и Rewrite применительно к типизированным или нетипизированным файлам? Если процедуру Reset применить к несуществующему файлу, будет иметь место ошибка (процедура Rewrite в этом случае создаст новый файл). Если же процедуру Reset применить к существующему на диске файлу, файл будет от
15 Здесь и дальше необязательные параметры в заголовках процедур или функций заключаются в квадратные скобки.
глава 5. Файлы
S*
крыт (процедура Rewrite при этом удалит содержимое старого файла и создаст новый файл с тем же именем).
Заголовок процедуры Rewrite выглядит следующим образом:
Reset(Var f [ : File; Recsize : Word ] );
где F— файловая переменная любого типа, с которой ассоциирова! (с помощью процедуры Assign) некоторый файл, либо устройство с сим волическим именем;
RecSize— необязательный параметр, определяемый только для нс типизированных файлов и указывающий размер записи, которыми бу дет осуществляться передача данных. Все, что было сказано выше о па раметре RecSize, применительно к процедуре Reset, верно и для проце дуры Rewrite.
Как уже говорилось, если процедуру Rewrite применить к уже суще ствующему файлу, его содержимое окажется удалено (без всякого преду преждающего сообщения), а затем будет создан новый (пустой) файл с тем же именем. Поэтому при использовании данной процедуры следуе проявлять осторожность. Что касается устройства с символически’ именем, то это обязательно должно быть устройство, способное служил приемником записываемых данных. Собственно этому условию отве чают все устройства, за которыми в MS DOS зарезервированы символ! i ческие имена.
Файл, открытый с помощью процедуры Rewrite, изображен на рис. 5.5.
Рис. 5.5. После применения процедуры Rewrite открывается пустой файл, в котором указатель текущей позиции расположен перед маркером конца файла
Ввод-ВЫ ВОД
Для осуществления ввода информации в файл и вывода из файл. Turbo Pascal для текстовых и типизированных файлов предназначен! процедуры Read и Write, а для нетипизированных— BlockRead
132
Turbo Pascal: учитесь программирос
plockWnte. Причем использование процедур Read и Write имеет особен-Н0™ зависящие °Т ВИДа файла (текстовый это файл или типизирован-лыи). Поэтому сведения об упомянутых процедурах вы найдете в разделах, посвященных соответствующим видам файлов.
Помимо Read и Write, для текстовых файлов применимы процедуры peadLn и WnteLn. Эти процедуры рассмотрены в разделе, посвященном текстовым файлам.
Кроме подпрограмм, осуществляющих ввод-вывод, имеется функция. которая осуществляет контроль за вводом-выводом. Речь идет о функции lOResult.
Функция lOResult
Возвращает код ошибки, возникшей при выполнении последней операции ввода-вывода.
Заголовок:
Function lOResult : Integer;
Если ошибки не было, функция возвращает нуль.
Для того чтобы контролировать ошибки ввода-вывода с помощью функции lOResult, должен быть выключен автоконтроль (директива компилятора {$!-}).
' Ориентирование в файле
К этой категории относятся процедуры и функции, позволяющие определять или изменять положение указателя текущей позиции в файле (или близкие к ним). Здесь рассматриваются две процедуры (Seek и Truncate) и три функции (FileSize, FilePos и EoF).
Существует еще одна функция, которую также можно отнести к этой группе — EoLn. Однако, поскольку она применима только к текстовым файлам, мы ее рассмотрим в соответствующем разделе.
Процедура Seek
Эта процедура позиционирует указатель на определенный элемент в файле. Файл, к которому применяется процедура Seek, должен быть открыт. Вот как выглядит заголовок этой процедуры:
Procedure Seek(Var f; n : Longlnt);
где F — файловая переменная любого типа, за исключением Text;
N — номер элемента в файле, (выражение, имеющее тип Longlnt).
Например, для того чтобы переместить указатель текущей позиции к третьему элементу файла, процедуру Seek следует применить так:
Seek(f,3);
гАава 5. Файлы
133
Файл, к которому таким образом применена процедура Seek, и бражен на рис. 5.6.
Рис. 5.6. Процедура Seek позиционировала указатель к третьему элементу файла
Пример использования процедуры Seek приведен в разд< “Функция FilePos”.
Процедура Truncate
Данная процедура, будучи применена к открытому файлу, удаля его содержимое от текущей позиции и до конца. Заголовок процедуры:
Procedure Truncate(Var f);
где F— файловая переменная любого типа, за исключением Text.
Программа, в которой используется процедура Truncate, содержи в примере 5.1.
Internei
Пример 5.И
program Trunc;
var f : file of char;
i : integer;
j:char;
procedure out;
begin
Reset(f);
while not EoF(f) do
begin
Read(f,j);
Write’( j)
end
end; {Out}
begin {Program}
Assignff, 'FILE.TXT');
Rewrite(f);
{Ввод A,B,C,D,E,F}
for j:='A' to 'F' do Writeff, j);
WriteLn('Файл до усечения:');
И34
Turbo Pascal: учитесь программирог
Out; {Вывод содержимого файла}
Reset(f);
{Считывание 3-х записей}
for i:=l to 3 do Read(f, j);
Truncate (f);{Усечение файла}
WriteLn;
WriteLn('Файл после усечения:');
Out; {Вывод содержимого файла}
Close(f);
Erase(f)
end. {Program)__________________________________________
В этой программе объявлена типизированная файловая переменная F, которая затем (с помощью процедуры Assign) ассоциируется с файлом FILE.TXT. (Имя выбрано произвольно; такого файла в данный момент еще нет.) После этого данный файл открывается с помощью процедуры Rewrite. Из раздела “Открытие файла ’’ мы уже знаем, что если файла с таким именем в указанном каталоге нет, при попытке открыть его с помощью процедуры Rewrite будет создан новый пустой файл. О каком каталоге; речь, если с именем файла FILE.TXT никакой каталог указан не был? Если при связывании файловой переменной с файлом каталог не указывается. по умолчанию используется текущий каталог. А текущим при работе с интегрированной средой разработки Turbo Pascal 7.0 всегда является каталог BIN, если только вы не изменили текущий каталог с помощью команды Change dir из меню File. Итак, файл FILE.TXT окажется создан в каталоге, в котором содержатся файлы Turbo Pascal. В принципе ничего страшного в этом нет, поскольку в конце программы Trunc вызывается процедура Erase, которая его удаляет, однако на всякий случай лучше указать иной каталог — например C:\WINDOWS\TEMP.
Таким образом, файл создан, открыт и после этого в него вводятся шесть элементов — символы А, В, С, D, Е, F, и содержимое файла выводится на экран. Затем организуется считывание трех элементов файла и проводится усечение файла с помощью процедуры Truncate (эта единственная строка программы является целью всего примера). Затем содержимое файла вновь выводится на экран, чтобы продемонстрировать последствия использования процедуры Truncate.
Наконец, созданный вначале файл FILE.TXT закрывается (процедура Close — см. раздел “Процедура Close”) и удаляется (процедура Erase — см. Раздел “Процедура Erase”). Вывод на экран содержимого файла FILE.TXT реализован в виде процедуры Out. которая в теле программы использует-{,я дважды (для вывода полного и усеченного содержимого файла).
Вот как выглядит вывод на экран программы Trunc:
Файл до усечения:
ABCDEF
Файл после усечения:
АВС
Глава 5. Файлы
135
Действие программы Trunc изображено на рис. 5.7.
Рис. 5.7. Программа Тплпс удалила вторую половину файла
Любознательный читатель может поэкспериментировать в этой пр грамме с операторами:
for j:='A’ to 'F' do Write(f, j);
и
for i:=l to 3 do Read(f, j);
Изменяя букву F и число 3 в первом и втором операторах, мож! варьировать длину ряда символов, записываемых в файл, и количест букв, которые остаются в файле после применения процедуры Truncate
Функция FileSize
Возвращает значение (имеющее тип Longlnt), соответствующее т< кущей длине файла (т.е. числу содержащихся в нем элементов). Пр этом файл должен быть открыт. Если файл пустой (в нем нет ни одног элемента), функция вернет значение, равное нулю. Вот как выгляди заголовок этой функции:
Function FileSize(Var f) : Longint;
где F— файловая переменная любого типа, за исключением Text
Пример использования функции FileSize имеется в разделе “Функщ FilePos”.
Функция FilePos
Возвращает значение (имеющее тип Longlnt), соответствующее п< ложению указателя текущей позиции в файле. При этом файл должс быть открыт. Заголовок этой функции выглядит так:
Function FilePos(Var f) : Longint;
где F— файловая переменная любого типа, за исключением Text
Если к файлу, изображенному на рис. 5.8, применить функци! FilePos, данная функция возвратит значение 3.
136
Turbo Pascal: учитесь программирова
Рис. 5.8. Функция FilePos возвратит значение, соответствующее положению указателя текущей позиции
Программу, в которой используются функции FilePos и FileSize, а также процедура Seek, можно видеть в примере 5.2 (рис. 5.9).
Internet
Рис. 5.9. Указатель текущей позиции перемещен в середину файла
В этой программе объявлена типизированная файловая переменная В, которая затем (с помощью процедуры Assign) ассоциируется с файлом A.PAS из каталога BIN. A.PAS — это файл с текстом программы на Turbo Pascal, который имеется в составе интегрированной среды программирования и содержится в указанном каталоге. В принципе, для нашего Примера подходит любой файл, a A.PAS под рукой у всех, у кого на компьютере установлен Turbo Pascal 7.0. Более того, каталог, в котором Расположен данный файл, является текущим, если только вы не изменили текущий каталог с помощью команды Change dir из меню File.
Глава 5. файлы
137
Иными словами, при связывании файла с файловой переменной можц даже не указывать путь.
После связывания файловой переменной с файлом данный файл оп крывается процедурой Reset. Затем с помощью функции FileSize опрел ляется размер файла и с помощью процедуры Seek указатель устав; ливается в середину файла. Причем второй операнд процедуры S< е указывающий, куда следует позиционировать указатель, имеет щ volume div 2, т.е. здесь берется целая часть от деления числа элемент файла (Volume) на 2.
Естественно, по ходу выполнения программы на экран выводя -необходимые сообщения и в заключение файл, связанный с файлщ переменной F, закрывается с помощью процедуры Close. (Об этой пр, цедуре речь пойдет в разделе “Процедура Close” дальше в этой главе.)
Функция EoF
Данная функция возвращает значение TRUE, если указатель теку щей позиции находится за последним элементом файла, либо если ф; пустой. В противном случае функция возвращает значение FALSE. I как выглядит заголовок этой функции.
Для типизированных или нетипизированных файлов:
Function Eof(Var f) : Boolean;
Для текстовых файлов:
Function Eof(Var f : Text) : Boolean;
где F— файловая переменная (текстовая, типизированная или не типизированная).
Присмотримся к трем изображениям на рис. 5.10.
Рис. 5.10. Указатель текущей позиции расположен в начале, в середине и в конце файла
Для представленных здесь трех ситуаций функция EoF в первом и в втором случае вернет значение FALSE, а в третьем — TRUE.
Программу, в которой используется функция EoF (а также процеду ры Read и Write, о которых речь пойдет дальше), можно видеть в прим ре 5.3 (рис. 5.11).
138
Turbo Pascal: учитесь программирова
иЛПЖ^^Пример 5.3
Рис. 5.11. Функция EoF позволяет, “нащупать” конец файла
В этой программе объявляется файловая переменная F типа Text, которая затем (с помощью процедуры Assign) ассоциируется с файлом AUTOEXEC.BAT из корневого каталога диска С. (Здесь этот файл выбран потому, что такой файл имеется на каждом компьютере и именно в этом каталоге.)
После связывания файловой переменной с файлом данный файл (процедурой Reset) открывается для чтения. Затем с помощью оператора цикла REPEAT организуется циклическое считывание содержащихся в нем символов. Составной оператор, служащий телом цикла, включает оператор считывания очередного символа (процедура Read) и оператор вывода этого символа на экран (процедура Write). В результате все содержимое файла AUTOEXEC.BAT оказывается выведено на экран (см. рис. 5.11).
Вместо AUTOEXEC.BAT читатели могут задать в качестве параметра процедуры Assign любой другой текстовый файл (т.е. файл, содержимое которого представляют собой строки текста), например A.PAS из предыдущего примера. В результате содержимое этого файла тоже окажется выведено на экран.
Специальные операции
К этой группе относятся процедуры и функции, имеющие различное Назначение, но в основном связанные с организацией структуры диска.
Глава 5. Файлы
139
Здесь мы рассмотрим пять процедур: Rename, ChDir, MkDir, Rm GetDir. Первая применима к файлам любого вида. Остальные чет процедуры манипулируют не файлами, а каталогами, поэтому вог, об их применимости к тому или иному виду файлов не возникает.
Процедура Rename
Данная процедура переименовывает файл. Файл, к которому приг няется процедура Rename, должен быть закрыт. Вот как выглядит заг ловок этой процедуры:
Procedure Rename(var f; NewName);
где F — файловая переменная любого типа:
NewName — параметр, имеющий тип STRING.
Файлу, ассоциированному с переменной F, присваивается нс имя, которое указывается при вызове процедуры как параме, NewName. С этого момента с файловой переменной F ассоциируег файл с новым именем.
Процедура ChDir
Данная процедура изменяет текущий каталог на каталог, коте, указывается в качестве параметра процедуры. Заголовок этой проце/г ры выглядит так:
Procedure ChDir(s : String);
где S — выражение типа STRING, содержащее путь к новому каталоге
Процедура MkDir
Данная процедура создает новый подкаталог. Заголовок:
Procedure MkDir(s : String);
где S — выражение типа STRING, содержащее путь и имя нового к талога.
Для вновь создаваемого каталога не подходят имена, совпадают именами уже существующих каталогов.
Процедура RmDir
Данная процедура удаляет пустой каталог. Вот как выглядит заго вок этой процедуры:
Procedure RmDir(s : String);
где S — выражение типа STRING, содержащее путь и имя удаляе’ каталога.
140
Turbo Pascal: учитесь программиро
Каталог, который указывается в качестве параметра процедуры ItrnDir, должен существовать, быть пустым и не быть текущим каталогом.
Процедура GetDir
Данная процедура позволяет выяснить, какой каталог на указанном диске текущий. Заголовок этой процедуры выглядит так:
Procedure GetDir(d : Byte; Var s : String);
где D — выражение типа Word, определяющее диск. Если D равно нулю, подразумевается устройство по умолчанию; если D = 1 — диск А; 2 — диск В; 3 — диск С и т. д.;
S— выражение типа STRING, возвращаемое процедурой и определяющее путь и имя текущего каталога на заданном диске.
Завершающие операции
К этой категории относятся три процедуры, которыми, как правило, завершается работа с файлами — Close, Flush и Erase. Процедуры Close и Erase, поскольку они применимы к файлам любого вида, рассматриваются здесь. Сведения о процедуре Flush, которая подходит только для текстовых файлов, читатели найдут в разделе “Текстовые файлы”.
Процедура Close
Данная процедура закрывает файл, открытый процедурой Reset, Rewrite или Append. Вот как выглядит заголовок процедуры Close:
Procedure Close(Var f);
где F — файловая переменная любого типа.
В принципе, процедуру Close для закрытия файлов применять не обязательно — все открытые файлы при нормальном завершении программы закрываются автоматически, однако использование процедуры Close все же считается признаком хорошего тона.
Пример использования процедуры Close имеется в программе ProcFunc в разделе “Функция FilePos” выше.
Процедура Erase
Данная процедура удаляет файл с диска. Процедура Erase отнесена к завершающим, поскольку в конце работы временно созданные файлы Часто приходится удалять. Вызов процедуры Erase выглядит так:
Erase(f);
где F — файловая переменная, принадлежащая любому типу.
Глава 5. Файлы
141
Виды файлов
В начале данной главы указывалось, что Turbo Pascal оперирует с файлами трех видов: типизированными, текстовыми и нетипизирован ними. Примеры объявлений файловых переменных для каждого из трех видов представлены в табл. 5.2.
таблица 5.2. Объявления файловых переменных для различных видов файлов		
Вид файла	Содержимое файла	Примеры объявлений переменных
Типизированный Текстовый Нетипизированный	Совокупность элементов, принадлежащих любому типу, за исключением файлового Совокупность строк Последовательность элементов произвольного типа	flzfile of integer; f2:file of real; f3:file of boolean; f:text; fsfile;
Рассмотрим каждый из упомянутых видов файлов подробнее.
Типизированные файлы
Итак, типизированный файл содержит совокупность элементов, принадлежащих типу, который определен в объявлении файловой переменной. Доступ к элементам файла, как правило, организуется последовательно. Можно также переместить указатель текущей позиции (с помощью процедуры Seek) к любому элементу файла.
Для того чтобы файл открыть как типизированный, его необходимо ассоциировать с файловой переменной, имеющий тип FILE OF ... Вместо трех точек здесь может присутствовать любой из простых или структурированных типов, как стандартных, так и созданных пользователем, за исключением файлового типа, либо структурированного элементами которого являются файлы, т.е. существование “файла файлов” не допускается.
Для манипулирования типизированными файлами подходят все процедуры, о которых шла речь выше (если только при описании той или иной процедуры не было указано обратное). Здесь необходимо заметить, что использование процедур Read и Write для типизированных файлов имеет особенности (об этом уже шла речь выше в разделе “Ввод-вывод”). Эти особенности мы и выясним в ближайших разделах.
442
Turbo Pascal: учитесь программировать
Процедура Read
Использование процедуры Read для типизированных файлов заключается в считывании одного или нескольких компонентов файла и присвоении считанного значения (значений) некоторой переменной (переменным).
Вот как выглядит заголовок процедуры Read для типизированных файлов:
Procedure Read(f , VI [, V2, Vn] );
Здесь F — файловая переменная, имеющая тип FILE OF
VI—Vn одна или несколько переменных, принадлежащих любому типу, за исключением файлового.
Пример программы, в которой используется процедура Read (для текстовых файлов) читатели найдут в разделе “Функция EoF” выше в этой главе.
Процедура Write
Запись в файл осуществляет процедура Write. Использование данной процедуры для типизированных файлов заключается в присвоении значения некоторой переменной (или переменных) компоненту (компонентам) файла.
Заголовок процедуры Write для типизированного файла выглядит так:
Procedure Write(f, Vl [, V2, _, Vn ] );
Здесь F — файловая переменная, имеющая тип FILE OF ...
VI—Vn— одна или несколько переменных, принадлежащих любому типу, за исключением файлового. Кроме того, эти переменные должны быть того же типа, что и компоненты файла.
После записи каждой переменной (очередному элементу файла при этом присваивается значение переменной, т.е. старое значение элемента заменяется новым), указатель текущей позиции файла перемещается к следующему элементу. Если указатель находится в конце файла, то при записи очередного элемента этот элемент дополняет файл.
Текстовые файлы
Текстовый файл представляет собой последовательность строк разной длины, состоящих из символов. Каждая строка текстового файла оканчивается маркером конца строки (End of Line— EoLn), а завершает текстовый файл, как и любой другой, маркер конца файла (End of File — EoF). К элементам текстового файла возможен только последовательный (оступ, начиная с первого.
Глава 5. Файлы
143
Для того чтобы файл открыть как текстовый, его необходимо ассс циировать с файловой переменной, имеющий тип Техт.
Для манипулирования текстовыми файлами подходят только те и: рассматриваемых процедур, в описании которых это указывается пря мо. Необходимо заметить, что использование процедур Read и Write с текстовыми файлами имеет особенности, которые мы выясним в бли жайших разделах. Кроме того, к текстовым файлам (и только к тексто вым) применимы процедуры ReadLn и WriteLn, которые также буду, здесь рассмотрены. Специально для использования с текстовыми фай лами предназначены процедура Append и функция EoLn, которым посвящены отдельные разделы. Однако прежде поговорим о так называе мых стандартных текстовых файлах.
Стандартные текстовые файлы
Вероятно, читатели помнят, что в предыдущих главах мы использс вали операторы ввода-вывода, которые выглядели так:
Read(a,b,c);
или
Write(x,y,'Вывод на экран')
Первый оператор позволяет ввести с клавиатуры значения, которые будут присвоены переменным А, В и С. Второй оператор выводит на эк ран значения переменных X и Y, а также строку текста.
Возникает вопрос, не имеют ли эти операторы какого-либо отноше ния к процедурам ввода-вывода, применимым к файлам? Оказываются, имеют, и самое непосредственное. Дело в том, что в Turbo Pascal существует два стандартных идентификатора, играющие роль текстовых фай ловых переменных, ассоциируемых вместо файлов с конкретными физическими устройствами компьютера. Речь идет об идентификаторах INPUT и OUTPUT, которые ассоциируются соответственно с клавиатурой и экраном компьютера. Указанные файлы считаются постоянно открытыми (т.е. для них не нужно использовать процедуры Rewrite и Reset) и эти идентификаторы можно использовать в программах. Так. операторы ввода-вывода, о которых шла речь выше, можно представить и иначе:
Read (Input, a ,'b, с);
Write(Output,x,y,'Вывод на экран')
Первый оператор считывает из файла INPUT значения (т.е. позволяет ввести их с клавиатуры), которые будут присвоены переменным А, В и С. Второй оператор записывает в файл OUTPUT (т.е. выводит на экран) значения переменных X и Y , а также строку текста. Первая и вторая пары операторов эквивалентны.
Иными словами, в процедурах Read и Write, когда требуется осуществить ввод с клавиатуры или вывод на экран, указывать файл (INPUT или
144
Turbo Pascal: учитесь программировать
OUTPUT) необязательно. Если в процедуре Read или Write файл не указан, по умолчанию подразумевается файл INPUT или OUTPUT, в зависимости от того, ввод или вывод инициируется.
Упомянутые стандартные файлы можно “переассоциировать”. Для этого достаточно воспользоваться процедурой Assign, например:
AssignfOutput,'text.txt')
Если после этого в данной программе вызвать процедуру Write без указания файла, соответствующая информация окажется записана в файл TEXT.TXT.
Процедура Read
Использование процедуры Read для текстовых файлов заключается в считывании одного или нескольких значений файла и присвоении считанного значения (значений) переменной (переменным), указанной при вызове процедуры. Значения, о которых идет речь, могут принадлежать типам Char, STRING, а также любым целочисленным или вещественным типам.
Вот как выглядит заголовок процедуры Read для текстового файла:
Procedure Read([Var f : Text; ] VI[, V2r VnJ);
Здесь F — файловая переменная, имеющая тип Техт.
VI—Vп — одна или несколько переменных, принадлежащих типу Char, STRING, а также любому целочисленному или вещественному типу.
Для того чтобы лучше понять, как функционирует процедура Read, будучи применена к текстовым файлам, целесообразно воспользоваться файлом INPUT. (Мы помним из предыдущего раздела, что файл INPUT — это такой же текстовый файл, как и любой другой, только его не нужно открывать. И, кроме того, считывание из файла INPUT— это ничто иное, как ввод с клавиатуры.)
Вот как происходит считывание из текстового файла.
Считывание значений типа Char
Если это переменная (переменные) типа Char, из файла считывается символ и присваивается переменной, затем считывается следующий символ и присваивается следующей переменной — и так до тех пор, пока всем переменным типа Char, указанным при вызове процедуры Read, не будут присвоены считанные из файла значения. (При вводе с клавиатуры между вводимыми значениями требуется вводить некоторый разделитель — пробел, символ табуляции (клавиша <ТаЬ>) или конец строки (клавиша <Enter>).) Если очередной считанный символ окажется маркером конца строки EoLn (при вводе с клавиатуры для этого достаточно нажать клавишу <Enter>), считывание будет продолжено из новой строки. Если очередной считанный символ окажется маркером
Глава 5. Файлы
145
конца файла EoF (при вводе с клавиатуры для этого достаточно восполь зоваться комбинацией клавиш <Ctrl+Z>), выполнение процедуры Reac будет прекращено и программа перейдет к следующему оператору.
Считывание значений типа STRING
Если это строковая переменная (переменные), из файла будут счита ны все символы до ближайшего маркера конца строки. Если длина счи тайной строки превзойдет допустимую для значений типа STRING ве личину (255 символов), все оставшиеся до конца строки байты отбрасы ваются. Затем при каждом новом обращении к процедуре Read будс считываться маркер конца строки, т.е. строка нулевой длины. Иным! словами, с помощью процедуры Read не удастся считать нескольк* строк подряд. Для того чтобы считать несколько строковых значений следует несколько раз обратиться к процедуре ReadLn (об этой процеду ре речь пойдет в разделе “Процедура ReadLn” дальше в этой главе).
Считывание числовых значений
Если это значение типа Integer или Real, процедура Read будет пропус кать любые пробелы, символы табуляции или маркеры конца строки предшествующие числовой строке. Когда будет обнаружена первая зна чащая цифра, процедура Read начнет формировать числовое значение пока не встретится один из перечисленных символов (пробел, символ та буляции или маркер конца строки). Считанная таким образом последова тельность цифр рассматривается как символьное представление соответствующего числа и полученное значение присваивается соответствующей переменной. Если числовая строка не соответствует ожидаемому форма ту, имеет место ошибка ввода-вывода. Следующая процедура Read начнет считывание с пробела, символа табуляции или маркера конца строки, которым была завершена предыдущая числовая строка.
Процедура ReadLn
От Read процедура ReadLn отличается только тем, что после выполнения действий, присущих процедуре Read, осуществляется переход к следующей строке файла. Собственно с этой процедурой мы уже встречались в главе 3, только там ввод производился не из файла, а с клавиатуры.
Процедура Write
Использование процедуры Write для текстовых файлов сводится к записи значения (значений) одной или нескольких переменных, указанных при вызове процедуры, в файл. Значения, о которых идет речь, могут принадлежать типам Char, STRING, Boolean, а также любым целочисленным или вещественным типам. Кроме того, это могут быть
146
Turbo Pascal: учитесь программировать
значения перечислимых типов, созданных на основе Char или одного из целочисленных типов. При этом файл непременно должен быть открыт для записи.
Если указатель текущей позиции расположен в начале файла, новая информация записывается поверх старой. Если же указатель находится в конце файла, то новая информация дополняет содержимое файла.
Запишем заголовок процедуры Write для текстового файла:
Procedure Write((Var f : Text;] VI [,V2, VnJ);
Здесь f— файловая переменная, имеющая тип Техт;
VI—Vn одна или несколько переменных или выражений, принадлежащих типу Char, STRING, Boolean а также любому целочисленному или вещественному типу.
Каждая из переменных или выражений VI—Vn имеет следующий формат:
v[:a[:b]J
где V— переменная (или выражение), значение которой записывается в файл.
А— спецификатор ширины поля (необязательный параметр). Если записываемое значение не заполнит всю ширину поля, оно будет слева дополнено пробелами. Если ширины поля для записываемого значения не хватит, данный параметр игнорируется.
В— спецификатор количества знаков после десятичной точки. Данный параметр присутствует только в паре с параметром А и только в том случае, если значение V принадлежит одному из вещественных типов.
Указанные спецификаторы при вызове процедуры предваряются двоеточиями. Как это выглядит, позволяет судить пример 5.4 (рис. 5.12). Для наглядности запись происходит в файл OUTPUT (т.е. имеет место вывод на экран). Кроме того, вместо Write здесь использована процедура WriteLn, которая отличается только тем, что после выполнения действий, присущих Write, осуществляет запись маркера конца строки (при выводе на экран— переход к следующей строке). (Подробнее о процедуре WriteLn будет идти речь в разделе "Процедура WriteLn”.)
На рисунке представлена программа ParamWrite. В этой программе переменным I и К, принадлежащим соответственно типам Integer и Real, присваиваются некоторые произвольные значения, которые затем выводятся на экран при различных значениях спецификаторов ширины поля и количества знаков после десятичной точки. Окно Output расположено на этом рисунке таким образом, чтобы вывод, инициируемый каждым из операторов, располагался против соответствующего оператора. Читатели сами могут судить по этому рисунку о функционировании упомянутых выше спецификаторов. Кроме того, при желании.
Глава 5. Файлы
147
можно поэкспериментировать с этой программой, задавая иные значе ния спецификаторов и, может быть, вводя в нее новые переменные.
Ю Пример 5.4
Internet
Рис. 5.12. Процедура Write (собственно, WriteLn) в действии
Процедура WriteLn
Как указывалось выше, от Write процедура WriteLn отличается тем что после выполнения действий, присущих процедуре Write, осуществляется запись в файл маркера конца строки. При этом файл, к которому применяется процедура WriteLn, должен быть открыт для записи. Так же, как и с ReadLn, с процедурой WriteLn мы уже встречались в главе 1, только там вывод производился не в файл, а на экран.
Процедура SetTextBuf
Создает буфер для операций ввода-вывода с текстовым файлом.
Заголовок:
Procedure SetTextBuf(Var f : Text; Var Buf [ ; Size : Word ] );
где F — файловая переменная типа Техт:
Buf — переменная любого типа;
Size— необязательная переменная типа Word, определяющая объег буфера.
Процедуру SetTextBuf нельзя применять к открытому файлу, хотя е< и можно вызывать сразу после обращения к процедуре Reset, Rewrite или Append.
148
Turbo Pascal: учитесь программировать
Процедура Append
Для открытия файлов, помимо Reset и Rewrite, можно воспользоваться процедурой Append, однако с ее помощью можно открыть только текстовый файл. Заголовок процедуры Append выглядит следующим образом:
Procedure Append(Var f : Text);
где F— файловая переменная (типа Техт), с которой ассоциирован файл, который требуется открыть как текстовый.
Данная процедура предназначена для добавления информации в уже существующий файл — она открывает файл и позиционирует указатель в его конец. Если файла с указанным именем не существует, то имеет место ошибка ввода-вывода. Ес-
Рос. 5.13. Процедура Append открыла файл и позиционировала указатель в его конец
ли процедуру Append применить к открытому (с помощью процедуры Reset или Rewrite) файлу, файл будет закрыт, а затем вновь открыт (только для записи) с указателем, позиционированным в его конец.
Файл, к которому была применена процедура Append, изображен на рис. 5.13.
Процедура Flush
Данная процедура очищает буфер текстового файла. Это делается для того, чтобы гарантировать перенос последних символов из буфера в файл. Вот как выглядит заголовок процедуры Flush:
Procedure Flush(Var f : Text);
где F — файловая переменная, принадлежащая типу Техт.
Если текстовый файл был открыт для записи (с использованием процедур Rewrite или Append), то процедура Flush, в случае обращения к ней, очистит буфер файла. В результате последние символы, отправленные для записи в файл (и, возможно, каким-то образом “застрявшие” в буфере), будут принудительно записаны на диск. На файлы, открытые для чтения, процедура Flush никакого действия не оказывает.
В принципе, без процедуры Flush можно обойтись и используют ее редко, поскольку процедура Close (см. выше) при закрытии файла автоматически делает то же самое.
Функция EoLn
Данная функция возвращает значение TRUE, если указатель текущей позиции файла находится на маркере конца строки или на маркере
Глава 5. Файлы
149
конца файла. В противном случае функция EoLn возвращает значени FALSE.
Заголовок функции EoLn:
Function Eoln [(Var f : Text)] : Boolean;
где F— файловая переменная, имеющая тип Техт. Если функции EoLn вызвана без параметра, то подразумевается стандартный файл INPUT.
Функция SeekEoln
Возвращает значение TRUE, если указатель текущей позиции находится на маркере конца строки или на маркере конца файла. В противном случае возвращается значение FALSE.
Заголовок:
Function SeekEoln [ (Var f : Text) ] : Boolean;
где F— файловая переменная, имеющая тип Техт.
Функция SeekEoln, в отличие от функции EoLn. пропускает все про белы и знаки табуляции. (Функция EoLn рассматривается в предыду щем разделе.)
Функция SeekEof
Данная функция возвращает значение TRUE, если указатель теку щей позиции находится за последним элементом файла, либо если файл пустой. В противном случае функция возвращает значение FALSE. Вот как выглядит заголовок этой функции:
Function SeekEof[(Var f : Text)] : Boolean;
где F — файловая переменная типа Техт;
Функция SeekEof отличается от функции EoF следующим:
	функция SeekEof применима только к текстовым файлам (Ео1 подходит для любых файлов);
	функция SeekEof, в отличие от функции EoF, пропускает все про белы и знаки табуляции.
(Функция EoF рассматривается в разделе “Функция EoF” в этой главе выше.)
Нетипизированные файлы
Нетипизированные файлы отличаются тем, что для них при объявлении не определяется тип компонентов. Это позволяет получать доступ к файлам с любой структурой. При открытии файла (процедурами Reset или
150
Turbo Pascal: учитесь программировав
(Rewrite) необходимо только указать размер элементов (записей16), которыми будет проводиться обмен с файлом. При этом файл трактуется как последовательность этих записей (т.е. элементов произвольного типа).
Вот как может выглядеть обращение к процедурам Reset и Rewrite 1ЛЯ открытия нетипизированного файла:
Reset(f,512)
Rewrite(f,256)
Здесь F— файловая переменная, имеющая тип FILE (что соответству-г нетипизированным файлам). А в качестве второго параметра процедур Reset и Rewrite указаны размеры записей (в байтах), которыми будет производиться считывание из файла или запись в файл данных. Поскольку ото значение представляет собой выражение типа Word, его максимальная величина равна 65535 байт (предельное значение для этого целочисленного типа). Если второй параметр процедур Reset и Rewrite не задан, по умолчанию длина записи считается равной 128 байт.
При определении длины записи следует принять во внимание, что длина файла может оказаться не кратна этой величине. В этом случае последняя запись окажется неполной и несколько последних байтов файла, могут быть не считаны. Чтобы этого не случилось, можно установить длину записи равной единице.
Для манипулирования нетипизированными файлами подходят те же процедуры, что и для типизированных, за исключением Read и Write. Для обмена данными с нетипизированными файлами применяются специальные процедуры: BlockRead и BlockWrite. Познакомимся с ними подробнее.
Процедура BlockRead
Данная процедура считывает из файла указанное количество записей. При этом количество считываемых байтов равно числу считываемых записей, умноженному на размер записи, определенный при открытии файла процедурой Reset или Rewrite (если размер записи определен не был, по умолчанию он принимается равным 128 байтам). В случае, если это значение окажется больше 64К (или 65535 байт — пре-юл для значений типа Word), будет зафиксирована ошибка. Иными словами, если при открытии файла длина записи была определена максимальной (65535 байт), то считывание возможно только по одной записи.
Записи (blocks), о которых здесь идет речь, не имеют ничего общего со структурированным типом, с которым мы познакомились в глазе 4. Те записи (records) 1 подставляют собой совокупность полей, принадлежащих разным типам. Загш-сч. применительно к нетипизированным файлам, — это некоторые условные элементы, из которых якобы состоит файл. Этот условный элемент определяется при открытии файла процедурой Reset или Rewrite.
Глава 5. Файлы	Л 5 Л
Файл, из которого происходит считывание, предварительно должс [ быть открыт. Вот как выглядит заголовок процедуры BlockRead:
Procedure BlockRead (Var f : File; Var Buf; Count : Word [; Var Result : Word]);
Здесь F— нетипизированная файловая переменная (имеющая ти. FILE), ассоциированная с файлом, из которого требуется осуществит считывание;
Buf— переменная, ранее объявленная в программе и используемая г качестве рабочего буфера. Размер этого буфера, который предназначе! для обменов, не должен быть меньше длины записи, определенной пр г открытии файла процедурой Reset или Rewrite. Имя этой переменной i качестве параметра указывается при вызове процедуры BlockRead.
Count— выражение или значение (имеющее тип Word), соответст вующее количеству записей, которые следует считать из файла;
Result — значение (имеющее тип Word), возвращаемое процедурой г, соответствующее количеству считанных записей. (Необязательный параметр.)
Количество считанных записей (параметр Result) может быть мень ше или равно значению параметра Count. Если при вызове процедур! параметр Result не определен, то в случае, если количество считанны записей окажется не равно значению параметра Count, будет зафикси рована ошибка ввода-вывода. По завершении действия процедурь BlockRead указатель текущей позиции файла оказывается перемеще! на количество записей, соответствующее значению параметра Result.
Пример программы, в которой используется процедура BlockRead имеется в следующем разделе.
Процедура BlockWrite
Данная процедура добавляет в файл одну или несколько записей При этом, как и для процедуры BlockRead, количество записываем! байтов равно числу добавляемых записей, умноженному на размер за писи, определенный при открытии файла процедурой Reset или Rewrite В случае, если это значение окажется больше 64 Кбайт (или 65535 байт будет зафиксирована ошибка. Иными словами, если при открытии фа ла длина записи была определена максимальной (65535 байт), то доба лять можно только по одной записи.
Файл, в который проводится запись, предварительно должен быт’ открыт. Вот как выглядит заголовок процедуры BlockWrite:
Procedure BlockWrite (Var f : File; Var Buf; Count : Word (; Var Result : Word]);
Здесь F— нетипизированная файловая переменная (имеющая ти* FILE), ассоциированная с файлом, в который требуется осуществить за пись;
152
Turbo Pascal: учитесь программировать
Buf— переменная, ранее объявленная в программе и используемая в качестве рабочего буфера. Размер этого буфера, который предназначен для обменов, не должен быть меньше длины записи, определенной при открытии файла процедурой Reset или Rewrite. Имя этой переменной в качестве параметра указывается при вызове процедуры BlockWrite.
Count— выражение или значение (имеющее тип Word), соответствующее количеству записей, которые следует добавить в файл;
Result — значение (имеющее тип Word), возвращаемое процедурой и соответствующее количеству добавленных записей. (Необязательный параметр.)
Количество добавленных записей (параметр Result) может быть меньше или равно значению параметра Count. Если при вызове процедуры параметр Result не определен, то в случае, если количество добавленных записей окажется не равно значению параметра Count, будет зафиксирована ошибка ввода-вывода.
Программа, в которой используется процедура BlockWrite (а также BlockRead, как было обещано в предыдущем разделе), содержится в примере 5.5 (рис. 5.14).
13
ternet
Пример 5.5

\МСИДОК-1 \PASC AL \П р—1
pptions.wjndow не]р.
Program CopyFile;
Var F, Fl : File;
BytesR, BytesWr : Word;
1,j,buf:i nteger; b:cha r;
begin
Assi gnfF,'a.pas'J;
ResetCF, 1);
AssiqnCFl, a2.pas ), Rewrite (Fl, 1);
j:=lj
for i:=l to Files! ze(F) do begi n
BlockReadCF, Buf,l,i);
BlockWriteCF1, Buf,l,j3;
wri te(chr(buf j) end;
CloseCF);
CloseCFlj;
end.
'	'	........... Output —
version 7.0 Copyright v-5 1981
end. _
F1

Puc. 5.14. Программа копирования файла
В этой программе создается новый файл Al.PAS, в который копируется (побайтно) содержимое файла A.PAS (с файлом A.PAS мы уже имели Дело в этой главе и знаем, что это за файл). Считывание очередного байта из A.PAS и копирование его в Al.PAS осуществляется с помощью процедур BlockRead и BlockWrite. Это считывание-запись организовано Циклически с помощью оператора цикла с параметром FOR.-ТО..DO. В
Глава 5. Файлы
Л 53
составной оператор, являющийся телом цикла, помимо проце, BlockRead и BlockWrite, добавлен также оператор Write(chr(buf)), кот рый выводит на экран каждый копируемый байт (для контроля за п~ исходящим). Это позволяет видеть нам в окне Output содержимое скоп рованного файла (см. рис. 5 14).
Для того чтобы убедиться, что копирование выполнено должным < разом, по завершении работы программы можно открыть каталог BIT проверить, появился ли там файл A1.PAS (обратив при этом особое вн мание на время и дату его создания). Можно также открыть этот файл сравнить его содержимое с тем, что отображает окно Output.
Еще процедуры и функции для работы с файлами
Процедуры и функции, которые мы рассмотрели выше, содержатс модуле SYSTEM (о модулях речь пойдет в главе 8). Однако подпрогра мы для работы с файлами имеются не только здесь. Например, соотр ствующие подпрограммы есть и в модуле DOS. В этом модуле можно наружить следующие процедуры и функции, предназначенные для у боты с файлами: FindFirst, FindNext, GetFAttr, SetFAttr, FSplit, FExpar FSearch. Подробнее об этих подпрограммах речь пойдет в главе 9.
154
Turbo Pascal: учитесь программиров
ва 6
намическая память
и указатели
В этой главе...
	Статические и динамические переменные
	Указатели
	Два вида динамических данных
	Процедуры и функции для работы с динамической памятью
Переменные, с которыми мы до сих пор имели дело, создаются пр запуске программы (занимая при этом соответствующий объем намял и существуют вплоть до конца работы программы — это так назыв мые статические переменные. Легко прийти к выводу (дальше об этс еще будет идти речь), что это не самый рациональный способ исполь вания памяти ПК. В данной главе мы познакомимся с возможной ал тернативой — динамическими переменными, которые создаются неп средственно перед началом их использования и ликвидируют (освобождая при этом занимаемую память) сразу, как только это и-пользование завершено.
Типичная проблема
Предположим, нам необходимо создать программу, обрабатывал щую массив из 15 тысяч элементов, который содержит целочисленны значения типа Longlnt. Как может выглядеть соответствующая пр< грамма, демонстрирует пример 6.1 (рис. 6.1).
iiiMiHHgSHfe Пример 6.1
Affile Edit’ Search -Run	СеЫщ Tool Г cottons WinRbw fioTp
1---------------- \МОИДС*~-1\ЕА5САи\ПРОГРА~1\СН2_б_~1\АРКА¥1. PAS --------— 1-------
program arrayl;
I const number=15000;
i type a=array [0..number] of longint;
• var
s ch:a;
j i:word;
j begin
wri teln;
for i:=1 to 15000 do
if Ci mod 1000=0) or Ci=number) then
! begin
ch[i]:=i;
wri te Ci: 10, ch[i ] : 6) end;
Г []	 -	.—	—   Output t "	"2=[1]
1000 1000	2000	2000	10'00	3000	-1000	4000	5000	50e"<r
6000 6000	7000	7000	8000	8000	j000	9000	10000	i6GG0£
11000 11000	12000	12000	13000	13000	14000	14000	15000	15000
Рис. 6.1. Программа Arrayl, манипулирующая массивом
В этой программе объявлен массив, содержащий 15 тысяч значени типа Longlnt. В теле программы организован цикл (с помощью операто pa FOR...ТО...DO), в котором каждому элементу массива присваиваете значение его индекса. Кроме того, значения элементов массива, а такя значения параметра цикла (совпадающие между собой), кратные 100С выводится на экран для контроля. Какой это имеет вид, позволяет су
156
Turbo Pascal: учитесь программироват
11ть окно Output на рис. 6.1. Для того чтобы сразу же видеть результаты аботы программы, в конце имеется оператор ReadLn. Благодаря этому езультаты можно наблюдать на экране до тех пор, пока вы не введете то-нибудь и не нажмете клавишу <Enter>.
В принципе, в этой программе нет ничего нового для нас. Однако до-устим, что возникла необходимость иметь дело с массивом, содержа-щм не 15, а 20 тысяч элементов. В представленной выше программе зменим значение константы Number с 15000 на 20000 и запустим про->амму на выполнение, чтобы посмотреть, что получится.
При попытке запуска (напомним, что это осуществляется комбина-ией клавиш <Ctrl+F9> или выбором пункта Run в одноименном меню) ia экране появляется сообщение:
Error 22: Structure too large.
Это значит: “Ошибка 22: Структура чересчур объемиста”.
Если теперь в меню Help выбрать пункт Error messages, а затем в полившемся окне дважды щелкнуть на номере этой ошибки (22), появится це одно окно с соответствующей информацией. Информации в этом кне не так уж и много. Сообщается только, что максимальная размер-ость для структурированных типов составляет 65520 байт. Что же это .пачит?
Вспомним, что элементы нашего массива содержат целочисленные начения, принадлежащие типу Longlnt (один из целочисленных типов), тя каждого из которых требуется четыре байта памяти. Кроме того, массив (его первый вариант) включает 15 тысяч элементов, что в целом вставляет 60000 байт. Затем мы попытались перейти к массиву с '0000 элементами. Нетрудно вычислить, что для такого массива, каж-1ый элемент которого занимает в памяти четыре байта, в целом потребуется 80 тысяч байт. А теперь вспомним, что информация об ошибке 22 гласит: максимальная размерность для структурированных типов хтавляет 65520 байт. Это все объясняет! Если в первом случае допустимый предел превзойден не был (60 тысяч— это меньше чем 65520), > второй вариант нашего массива (20 тысяч элементов) оказался недопустимо объемным.
Ну и что же дальше? Что если имеет место настоятельная необходи-ость работать с большими массивами? Неужели Turbo Pascal для этого не подходит? Оказывается, язык программирования Turbo Pascal позволяет справиться и с этой проблемой. К нашему массиву мы в этой 1 лаве еще вернемся и сделаем так, чтобы при обработке массива, состоящего из более чем 15 тысяч элементов типа Longlnt, ошибка 22 перестала появляться, однако прежде нам придется познакомиться с такими понятиями, принятыми в Turbo Pascal, как динамическая память ч указатель.
Глава 6. Динамическая память и указатели
157
Статические
и динамические переменные
До сих пор, как указывалось в начале данной главы, мы имели дело так называемыми статическими данными и статическими переменны ми. Такие переменные объявляются в начале программы (в разделе опи саний) и существуют до завершения ее работы17. Соответственно, память для содержания этих переменных выделяется при запуске про граммы и остается занятой все время, пока программа работает.
Очевидно, что это не самый рациональный способ использования памяти компьютера. Например, некоторая переменная может использоваться только однажды в единственном операторе обширной программы, однако память, выделенная под эту переменную, остается занята все время, пока работает программа. А нельзя ли сделать так, чтобы память для такой переменной выделялась в момент, когда переменная начинает использоваться, и освобождалась сразу же по завершении ее использования? И чтобы эту память тут же можно было выделить для иных данных? Оказывается, это вполне реально и именно для этой цели в Turbo Pascal введено понятие динамической памяти. Динамическая память, известная также как куча, рассматривается в Turbo Pascal как массив байтов.
Кроме того, динамическая память (или куча), имеющая объем при близительно 300000 байт, позволяет обрабатывать более обширные структуры данных. В предыдущем разделе нам не удалось, используя обычную (статическую) память, создать массив из 20000 элементов типа Longlnt. Так вот, с помощью динамической памяти можно обработать гораздо больший массив, что мы и докажем в конце данной главы.
Правда, при динамическом размещении к данным не удастся обра щаться по именам, как к статическим данным, с которыми мы до си> пор имели дело. Кроме того, количество и тип динамически размещав мых данных заранее неизвестны. Динамическая память выделяется для данных (и освобождается) в ходе работы программы. Для управления динамической памятью Turbo Pascal предоставляет гибкое средство, и" вестное как указатели.
17 Что касается локальных переменных. то они “появляются” в момент вызов' подпрограммы, в которой они объявлены, и существуют, пока подпрограмма завершит работу.
158
Turbo Pascal: учитесь программирова
Указатели
Мы уже знаем, что оперативная память компьютера — это множест-ячеек, каждая из которых предназначена для хранения одного байта формации, и каждая имеет собственный адрес, по которому к этой |ейке можно обратиться. Так вот, указатель — это переменная, объ-ленная в разделе описаний программы, значение которой и пред-авляет собой адрес одного байта памяти.
Указатели, используемые в Turbo Pascal, бывают типизированные и пипизированные. Если нетипизированный указатель — это перемен-я, содержащая адрес данных произвольного типа, то типизирован-»1Й указатель содержит адрес данных, тип которых оговаривается при ьявлении данного указателя.
Нетипизированные указатели объявляются следующим образом: var
рр : pointer;
где POINTER18 — стандартный тип данных:
РР — переменная, содержащая адрес памяти, по которому могут аниться данные произвольного типа.
Что касается типизированных указателей, то их объявления в про-гммах на Turbo Pascal выглядят так:
var
рх : Achar;
ру : ’integer;
В этом примере описаны два типизированных указателя: РХ и PY. ачения этих переменных представляют собой адреса в оперативной мяти, по которым содержатся данные типа Char и Integer соответствие. Нетрудно заметить, что описание типизированного указателя личается от описания статической переменной того же типа только м, что в случае указателя перед типом присутствует символ “А”.
Подытожим: когда требуется воспользоваться динамической памя-ью, в разделе описаний объявляется не сама переменная, а указатель (и ссылка) на нее. В этом случае указатель представляет собой обычно переменную, а переменная, на которую он ссылается, — динамиче-кую. При этом, если в выражении должен присутствовать указатель, к пользуется идентификатор, объявленный в разделе описаний. Вот пс РХ. Однако, если в выражении должна фигурировать динамическая ременная, на которую ссылается указатель, идентификатор указателя шолняется символом “л". Такое действие называется разыменованием. "анример, РХЛ. Чтобы научиться пользоваться указателями, абсолютно необходимо усвоить то, о чем шла речь в данном абзаце.
Английское слово pointer переводится как указатель.
ова 6. Динамическая память и указатели
159
Еще пример:
type
DatePointer = ADate;
Date=record
year : 1900..2100;
month : 1..12;
day : 1..31;
next : DatePointer
end;
var
pd : DatePointer;
Здесь объявлен тип DatePointer, представляющий собой указатель тип Date, который описывает запись. Внимательный читатель обрате внимание, что тип DatePointer описан до типа Date, на который он ссь лается. В то же время одно из полей записи Date принадлежит ти DatePointer. В целом, в Turbo Pascal не допускается ссылаться на еще н< описанные типы, однако в данном случае (достаточно частом, когдг приходится иметь дело с указателями19) как ни располагай описания все равно ссылки на еще не описанный тип не избежать. Поэтому едш ственное исключение сделано для указателей: тип указателя на дш мические данные может быть объявлен до описания самих данных.
Необходимо заметить, что применительно к типизированным указа телям операция присваивания допустима только для указателей, ссы дающихся на данные одного типа. Предположим, в программе объявле ны указатели:
var
рх, ру : Achar;
pz : Аinteger;
В этом случае операция присваивания допустима для указателей иРУ:
рх : =ру;
Однако совершенно недопустимыми окажутся операторы:
рх : =pz;
или
pz : =ру;
В то же время нетипизированный указатель может присутствоват операторе присваивания в паре с любым типизированным указателе Например, в программе объявлены указатели:
var
19 Случай, когда указатель ссылается на запись, одно из полей которой в се очередь представляет собой указатель, характерен для списков. О списках р< пойдет в разделе “Динамические данные с внутренними ссылками”
/|	Т urbo Pascal: учитесь программировс
рх : Achar;
ру : лinteger;
pz : pointer;
Для этих переменных допустимы операторы присваивания:
рх : pz; ру : pz; pz :ру; pz : рх;
Нетрудно прийти к выводу, что нетипизированные указатели — >чень удобное средство преобразования типов данных.
Состояния указателя
Для указателя, после того как он объявлен в разделе описания переменных, возможны три состояния. Указатель может содержать адрес некоторой переменной, “пустой” адрес NIL или иметь неопределенное состояние. Первый случай в объяснениях не нуждается. Во втором случае, когда требуется, чтобы указатель никуда не указывал, ему присваивается специальное значение NIL. Что же касается неопределенного состояния, то оно имеет место сразу после начала работы программы (до того как указателю будет присвоен какой-нибудь адрес в памяти или значение NIL), либо после освобояодения памяти, на которую данный указатель ссылается.
Если кого-то смущает “указатель, который никуда не указывает”, то это можно представить как ссылку на область памяти, в которой никакая информация никогда не размещается. Значение NIL — это константа, которую можно присвоить любому указателю.
Может возникнуть вопрос, в чем разница между неопределенным состоянием указателя и случаем, когда его значение равно NIL? Поскольку NIL — значение конкретное, хотя и никуда не указывающее, можно сказать. что два указателя, содержащие NIL, имеют равные значения. В то же время значения двух указателей в неопределенном состоянии равными признать нельзя.
Выделение и освобождение динамической памяти
Этот раздел познакомит вас с тем, как выделяется (или резервирует-<я) динамическая память для типизированных и нетипизированных Указателей. Кроме того, читатели узнают как освободить память, которая была выделена ранее.
Для типизированных указателей
Для динамически размещаемых переменных, на которые ссылаются типизированные указатели, память выделяется и освобождается с по
^ава 6. Динамическая память и указатели
161
мощью процедур New и Dispose соответственно. Вот как схематическг может выглядеть программа, в которой используются указатели на переменные, размещаемые в динамической памяти:
var
рх, ру : "char;
pz : Лinteger;
begin
new(px);
new(py);
new(pz);
pxA : = 'A';
pyA : = '7';
pz” : =777;
dispose(px);
dispose(py);
dispose(pz);
end.
В этой программе в разделе описания переменных объявлены tj типизированных указателя. Затем в теле программы под динамические переменные, на которые ссылаются эти указатели, с помощью проце и ры New выделена динамическая память. После этого динамическим переменным можно присваивать подходящие по типу значения (это ест:. в теле программы) и использовать их в разного рода выражен ix (операторы с этими выражениями в теле программы заменены тре мя точками). Что можно делать с типизированными указателями и динамическими переменными, на которые они ссылаются, вы узнаете из раздела “Действия над указателями и динамическими переменными дальше в этой главе.
Когда надобность в переменных РХ, PY и PZ отпадает, выделенна для них память освобождается с помощью процедуры Dispose. Поел» этого освободившуюся память можно резервировать для других перс менных, объявленных в программе и использующихся в оставшихся операторах. Подробнее о процедурах New и Dispose вы узнаете из разд лов “Процедура New” и “Процедура Dispose” дальше в этой главе.
Для нетипизированных указателей
Для динамически размещаемых переменных, на которые ссылают» нетипизированные указатели, память выделяется и освобождается помощью процедур GetMem и FreeMem соответственно. Вот как схема тически может выглядеть программа, в которой используются нетипи зированные указатели:
162
Turbo Pascal: учитесь программирова
var
px,py : pointer;
begin
GetMem(px,SizeOf(char));
GetMem(py,SizeOf(integer));
pxA : ='A';
pyA : =7;
FreeMem(px,SizeOf(char));
FreeMem(py,SizeOf(integer));
end.
В этой программе в разделе описания переменных объявлены два не-ипизированных указателя. Затем в теле программы под динамические переменные, на которые ссылаются эти указатели, с помощью процедуры GetMem выделена динамическая память. Эта процедура имеет два параметра, один из которых представляет собой переменную указательного гипа, а второй — целочисленное выражение, определяющее объем выделяемой памяти в байтах. Часто для определения второго параметра процедуры GetMem используется функция SizeOf, возвращающая длину в байтах внутреннего представления указанного объекта. В нашем случае функция SizeOf помогает определить, сколько байт памяти потребуется для данных типа Char и Integer. Подробнее о функции SizeOf вы узнаете из раздела “Функция SizeOf’ дальше в этой главе.
После выделения памяти, динамическим переменным можно притаивать значения подходящего типа (для которых подходит объем заре-рвированной памяти — это есть в теле программы) и использовать их в азного рода выражениях (операторы с этими выражениями в теле про-раммы заменены тремя точками). Действиям, которые допустимо произ-юдить над легализированными указателями и динамическими переменными, на которые они ссылаются, будет посвящен следующий раздел.
Когда надобность в переменных РХ и PY отпадает, выделенная для них память освобождается с помощью процедуры FreeMem. Эта процедура имеет те же параметры, что и процедура GetMem. После этого освободившуюся память можно выделять для других переменных, использующихся в оставшихся операторах. Подробнее о процедурах FreeMem и GetMem речь пойдет в разделах “Процедура FreeMem” и “Процедура GetMem” дальше в этой главе.
Действия над указателями и динамическими переменными
После того как указатель объявлен (в разделе описаний программы) и "од динамическую переменную, на которую он ссылается, выделена па
лова 6. Динамическая память и указатели
163
мять (с помощью процедуры New или GetMem), над указателем и дина-мической переменной обычно производятся какие-то манипуляции, (иначе зачем же их объявлять и выделять память). К динамическим переменным применимы все действия, допустимые для данных этого типа. Иными словами, динамической переменной можно манипулировать так же, как и аналогичной статической переменной. Некоторые из этих действий иллюстрирует рис. 6.2.
var а: =Л integer begin аЛ:=5;
а1_d—HZEZR
var Ь:Лгеа1;
begin ЬЛ : =3.14
bEZZ3—Ч^]ь
var с:ЛсЬаг; begin сЛ:='А';
с |	-|---1 А' | сЛ
Рис. 6.2. Действия над динамическими переменными
На рис. 6.2(a) представлена операция присваивания. Здесь трем ди намическим переменным А, В и С, принадлежащим разным типам, присваиваются некоторые значения.
На рис. 6.2(6) представлена операция сложения. Здесь значения двух динамических переменных X и Y складываются и присваиваются третьей переменной — Z.
На рис. 6.2(b) представлены операции ввода с клавиатуры и вывода на экран. Здесь значение динамической строковой переменной сначала вводится с клавиатуры, а затем выводится на экран.
Разумеется, это не единственные действия которые допустимо про изводить над динамическими переменными. Для того чтобы выяснить что можно делать с данными того или иного типа, читателю достаточна заглянуть в главу 4.
Что же касается указателей (а не данных, на которые они указывают), то для них допустимо только следующее:
1.	Проверка равенства. Например: if рх = ру then ...
2.	где РХи PY — указатели. Этот оператор проверяет, ссылаются ли указатели на один и тот же адрес памяти.
164
Turbo Pascal: учитесь программировав
3.	(Однако если бы здесь вместо рх=ру присутствовало рх<ру или рх>ру, то была бы зафиксирована ошибка.)
4.	Значение одного указателя можно присвоить другому указателю, если оба указателя ссылаются на динамическую переменную одного типа. Например:
рх := ру;
где РХ и PY — указатели.
(Это ограничение распространяется только на типизированные указатели. Нетипизированному указателю можно присвоить значение любого указателя. Точно так же, любому указателю можно присвоить значение нетипизированного указателя.)
5.	Значения указателям (представляющие собой адреса памяти) присваиваются процедурой New или GetMem при выделении памяти для динамических переменных. Поэтому присваивать (с помопцло оператора присваивания) указателям какие-либо явно заданные значения нельзя — за исключением NIL. Как мы уже знаем, указатель со значением NIL указывает “в никуда”.
римечание
После завершения использования в программе динамической переменной не забывайте освободить выделенную для нее память. Для этого предназначены процедуры Dispose и FreeMem. Подробнее с этими процедурами мы познакомимся в разделах “Процедура Dispose” и “Процедура FreeMem” дальше в этой главе.	
Два вида динамических данных
Динамические данные, на которые ссылаются указатели, можно разделить на две категории: данные без внутренних ссылок и данные с внутренними ссылками. Особенностям данных этих двух видов и будут посвящены ближайшие разделы.
Динамические данные без внутренних ссылок
Эти данные отличаются от статических данных только тем, что в Разделе описания переменных объявляются не переменные, а указатели на них. Сами же переменные создаются и ликвидируются в ходе работы Программы, когда под них выделяется память (процедурой New или
Глава 6. Динамическая память и указатели
165
GetMem) или эта память освобождается (процедурой Dis FreeMem).
Целесообразно ли использовать такие данные? В чем их преиг по сравнению с аналогичными статическими данными? Во-перш, }оке отмечалось, для статических данных память выделяется при .-программы, и эта память остается занята, пока программа не заве работу. А для динамических данных (с внут ренними ссылками и бе память выделяется в момент начала использования той или иной ; мической переменной и освобождается сразу же но завершении ее пользования. Иными словами, применяя динамичен кие нереме. можно обойтись меньшим объемом оперативной памяти.
Во-вторых, динамическая память предоставляет возможност тать с данными структурированных типов гораздо большего объе Помните, массив, содержащий 15000 элементов типа Longlnt, мы смс<; обработать, а 20000 — уже нет? Так вот, в разделе “Работа с обшир! массивом” в конце главы мы попробуем справиться с этой проблемой.
Примеры использования статических и аналогичных динамичес (без внутренних ссылок) структур данных можно видеть в табл, б 1
Таблица 6.1. Использование статических и динамических данных
Статические переменные	Динамические переменные
	type v=array[1..10] of integer; var
var a:boolean; b:integer; x:array[l..10] of integer; j:1..10; begin	pa:"boolean; pb:"integer; px:"v; j:l..10; begin New(pa); New(pb); New(pb);
a:=true; b:=44; for j:=l to 10 do read(x[j]);	pa":=true; pb":=44; for j:=l to 10 do read(px"[j]); Dispose(pa); Dispose(pb); Dispose(px);
end.	end.		
В этой таблице можно видеть два фрагмента программ, в од которых иснолыуются статические переменные (две из них прШ жат типам Boolean, Integer, а третья является массивом), а в ДРУ 1 аналогичные динамические переменные. Исходные тексты прФ'
166
Turbo Pascal: учитесь программ^
л.....„,14пы каким образом, чтобы подобные операторы в двух нро--рзммзх размещались один против другого (мы знаем, что наличие пус-гых строк в исходном тексте не влияет на работу программы).
Как указывалось, основная особенность при использовании динамических переменных состоит в необходимости выделять для этих пере-, [енных память (в данной случае с помощью процедуры New. поскольку мы имеет дело с типизированными указателями), а затем освобождать зыделенную память (процедура Dispose). Это и демонстрируют представленные примеры.
И еще нюанс. Читатель, наверное, обратил внимание, что в первой программе в разделе описания переменных массив объявлен так:
х : array[1..10] of integer;
Дво второй программе в разделе описания типов объявлен тип V:
v = array[1..10] of integer;
затем в разделе описания переменных объявлен указатель РХ на данные типа V:
рх : Av;
А почему бы во второй программе не поступить, как в первой — объявить указатель на массив? Вот так:
рх : ‘array[1..10] of integer;
К сожалению, если так сделать, а затем запустить программу, появится сообщение об ошибке, гласящее, что в этой точке программы (т.е. после знака ожидается идентификатор. (ARRAY — это, как известно, не идентификатор, а зарезервированное слово, об этом, в частности, свидетельствует цвет, которым выделено данное слово в окне редактора.-) Иными словами, объявить указатель непосредственно на массив нельзя. Чтобы обойти это препятствие, пришлось сначала объявить пользовательский тип V:
V = array[1..10] of integer;
а затем — указатель на данные типа V.
РХ : ‘v;-----------------------------------------------_----.
|То, о чем здесь шла речь применительно к массивам, от-?
щи———»—— 9 (носится также к записям и множествам, поскольку' • RECORD и SET—также зарезервированные слова.
Динамические данные с внутренними ссылками
Помимо простых (т.е. без внутренних ссылок) динамических данных, возможно rviчествование динамических структур в которых элементы
гапрп а Лмнлмии^ская память и указатели
4А7
ссылаются один на другой. Как это реализуется? Очевидно, что элемен подобной структуры должен представлять собой запись с не менее чек двумя полями. Одно поле такой записи предназначено для информации, а второе — для ссылки на следующий элемент этой же структуры. Вот ка4 упомянутая структура может быть объявлена в разделе описания типов.
type
p=Aitem;
item=record
data:integer; reference:p end;
Как эту структуру представить графически, демонстрирует рис. 6.3.
Item	Item	Item	Item
Рис. 6.3. Простейшая структура данных с внутренними ссылками (здесь Item — элемент: Data — данные: Reference — ссылка)
Мы уже знаем, что при описании указателя на запись, одно из поле i которого ссылается на этот указатель, первым должно следовать описание указателя (в нашем случае Р). Запись объявленного нами типа Item состо ит из полей Data и Reference. Первое поле предназначено для данных, а второе — для указателя, ссылающегося на следующую запись типа Item.
На рис. 6.3 изображена цепочка элементов нашей структуры с внутренними ссылками. Каждый элемент здесь — это запись, принадлежащая типу Item. Кстати, указатель, содержащийся в поле Reference каждого элемента, ссылается не на одно из полей следующего элемента структуры (как это можно понять по изображению), а на элемент (запись) в целом. Структура, о которой идет речь, называется связным списком.
Нетрудно прийти к выводу, что связный список с точки зрения экономии памяти — не самый удачный метод организации данных, поскольку каждый элемент списка, помимо байтов памяти для информации, нуждается в памяти для указателя, ссылающегося на следующий элемент списка. Однако при большем расходе памяти списки обеспечивают и большую гибкость. Действительно, если аналогичные данные ор ганизовать в виде массива, для того чтобы включить в структуру новыг элемент или исключить один из элементов, потребуется преобразовы вать весь массив. В то же время для того чтобы добавить в список новый элемент, достаточно сделать так, чтобы указатель предыдущего элемен та ссылался на новый элемент, а указатель нового элемента — на слс дующии элемент списка. Аналогично, при исключении одного из эле ментов списка достаточно только изменить значение указателя преды
168
Turbo Pascal: учитесь программировать
ущего элемента так, чтобы он указывал на элемент, следующий за исключаемым. Как это выглядит на практике, демонстрирует рис. 6.4.
Включение нового элемента в список
Исключение одного из элементов списка
Было	РЛ.Reference=Q;
РЛ.Reference=Q;
Стало
РЛ.Referenced;
LA . Reference=Q;
Рис. 6.4. Включение и исключение элемента списка
Существует несколько разновидностей связного списка, о котором шла речь выше.
	Кольцевой список. В этом списке указатель последнего элемента ссылается на первый.
	Очередь. Эта разновидность связного списка допускает только добавление нового элемен-
та в конец очереди и исключение элемента в начале очереди.
	Стек. Для этой разновидности связного списка можно только добавлять или исключать элементы с одного его конца.
Помимо линейных связных списков существуют иерархические структуры произвольной конфигурации, известные как деревья. Как может выглядеть такое дерево, позволяет судить рис. 6.5.
Здесь изображено дерево, ка
Рис. 6.5. Иерархическое дерево
ждый элемент (или узел) которого содержит два поля-указателя.
Поскольку каждый из этих указателей может иметь значение NIL, у ка-
глава 6. Динамическая память и указатели
169
ждого из узлов может быть ни одного, один или два последующих узла При этом число полей-указателей в узле двоичного дерева явно не огра ничивается. Чем больше таких полей, тем потен ци ал ьн-. “разветвленней” может быть дерево.
Процедуры и функции для работы с динамической
памятью
В этом разделе вы найдете краткие сведения о процедурах и функци ях, которые могут пригодиться при использовании динамической памяти.
Функция Addr
Возвращает адрес переменной, процедуры или функции, указанной в качестве параметра. Заголовок функции:
Function Addr(x) : Pointer;
Здесь X — идентификатор переменной, процедуры или функции Функция возвращает нетипизированный указатель, ссылающийся на X. Поскольку он принадлежит типу Pointer, результат, возвращаемыг функцией Addr, совместим со всеми типами указателей.
Вот пример программы, в которой используется функция Addr:
program PAddr;
type
b=char;
var
vb:b;
pvb:Pointer;
begin
pvb:=addr'(’Vb);
if pvb=addr(vb) then WriteLn('равно') else Write ('не равно’)
end.
Примечание
Вместо функции Addr возможно использование оператора Так, вместо оператора pvb:=addr(vb) в программе выше можно использовать его эквивалент pvb:=?vb.
170
Turbo Pascal: учитесь программирова
Процедура Dispose
Освобождает место, занятое в памяти динамической переменной, на которую ссылается типизированный указатель. Вот как выглядит заголовок этой процедуры:
Procedure Dispose(Var Р : Pointer[r Destructor ]);
где Р — типизированный указатель.
Возможности процедуры Dispose были расширены, и теперь она мо-зкет также освобождать память, занятую объектом, если деструктор этого объекта указать в качестве второго параметра процедуры. Например:
Dispose(P, Done);
Подробнее об объектах речь пойдет в главе 12.
После обращения к процедуре Dispose, значение указателя Р становится неопределенным. Поэтому повторное обращение к этой процедуре с Р в качестве параметра приведет к ошибке периода исполнения.
Пример программы, в которой используется процедура Dispose, вы найдете в разделе “ПроцедураNew”.
Процедура FreeMem
Освобождает память, занятую динамической переменной данного размера, зарезервированную за нетипизированным указателем (с помощью процедуры GetMem). Вот как выглядит заголовок этой процедуры:
Procedure FreeMem(Var р : Pointer; Size : Word);
Здесь P — нетипизированный указатель, для которого раньше была выделена память (процедурой GetMem);
Size — выражение, определяющее размер освобождаемой динамической переменной в байтах. Это значение должно совпадать с числом байтов, выделенных для этой переменной процедурой GetMem.
Процедура FreeMem ликвидирует переменную, на которую ссылается указатель Р, и освобождает память, занимаемую этой переменной. После обращения к FreeMem. значение указателя Р становится неопределенным и при повторном обращении к FreeMem имеет место ошибка времени исполнения. Ошибка также будет иметь место при попытке сослаться на РЛ.
Пример программы, в которой используется процедура FreeMem, вы найдете в разделе “Процедура GetMem”.
Процедура GetMem
Создает динамическую переменную определенного размера, на которую ссылается нетипизированный указатель. Вот как выглядит заголовок этой процедуры:
Procedure GetMem(Var Р : Pointer; Size : Word);
Глава 6. Динамическая память и указатели
171
Самый большой блок, который может быть зарезервирован за одщ раз, равен 65520 байт. Если в куче для размещения динамической переменной недостаточно свободного пространства, имеет место ошибка времени исполнения.
Вот пример программы (собственно, это только схема программы), в которой используются процедуры FreeMem и GetMem, а также функция SizeOf:
program GetFreeMem;
type
ar=array[1..10] of integer; var
P : Pointer;
begin
GetMem(p, SizeOf(ar)); (Выделение памяти}
{...}
{Использование памяти}
{ ..}
FreeMem(P, SizeOf(ar)); {Освобождение памяти} end.
Использованная здесь функция SizeOf возвращает число байтов, нимаемых объектом, указанным в качестве параметра функции. Да! ная функция рассматривается дальше в этой главе в разделе “Функци, SizeOf’.
Процедура Mark
Присваивает динамической переменной, на которую ссылается ука затель-аргумент процедуры, текущий адрес начала свободного участь динамической памяти. Вот как выглядит заголовок этой процедуры:
Procedure Mark(Var р : Pointer);
где Р — нетипизированный указатель.
Процедура Mark часто используется совместно с процедурой Rele
и не должна использоваться с процедурой FreeMem или Dispose.
Пример программы, в которой используется процедура Mark, bi найдете в разделе “Процедура Release”.
Функция MaxAvail
Возвращает размер самого большого непрерывного свободного уча стка в куче. Возвращаемый функцией результат представляет co6oi значение, принадлежащее типу Longlnt. Заголовок функции:
Function MaxAvail : Longint;
Пример программы, в которой используется функция MaxAvail, bi найдете в разделе “Функция MemAvail”.
И72
Turbo Pascal: учитесь программирова
Функция MemAvail
Возвращает количество всей свободной памяти в куче. Свободная амять обычно представляет собой не единый блок, а множество раз-озненных участков, что объясняется фрагментацией кучи. Возвращаемый функцией результат представляет собой значение типа >nglnt. Заголовок функции:
Function MemAvail : Longint;
Программа, в которой используются функции MemAvail и MaxAvail, а > акже функция SizeOf, содержится в примере 6.2.
nternet
^0^- Пример 6.2
program Mem_Max_Avail;
type
ar=array[l..10] of integer;
var
p : Pointer;
begin
writein('Свободная память= ',memavail,'; наибольший участок= maxavail);
GetMem(p, SizeOf(ar));
writeln('Свободная память= memavail,'; наибольший участок= maxavail); end.
Здесь на экран выводятся сведения об общем объеме свободной динамической памяти и наибольшем свободном участке. Соответствующие значения возвращаются функциями MemAvail и MaxAvail до и после выделения памяти (процедурой GetMem). Читатель может поэкспериментировать — попробовать изменять количество элементов в массиве AR (ar=array[ 1.. 10 ] of integer) или тип элементов (Integer на иной), чтобы выяснить, как это влияет на объем свободной памяти.
Использованная здесь функция SizeOf возвращает число байтов, занимаемых, объектом, указанным в качестве параметра функции. Данная функция рассматривается дальше в этой главе в разделе “Функция SizeOf”.
Процедура New
Создает новую динамическую переменную, на которую ссылается типизированный указатель. Вот как выглядит заголовок этой процедуры:
Procedure New(Var Р : Pointer [, Init : Constructor ]);
где P — типизированный указатель.
Возможности процедуры New были расширены и теперь она также Может резервировать память для объекта, если конструктор этого объ-(;кта указать в качестве второго параметра процедуры. Например:
New(p, Init(420, 252));
г лава 6. Динамическая память и указатели
173
где Init(420, 252) — метод-конструктор, задающий для объекта н. торые начальные значения (т.е. выполняющий его инициализацию).
Подробнее об объектах речь пойдет в главе 12.
Процедура New может также вызываться как функция, возвра щая значение указателя. При этом параметр функции представляет бой не указатель, а тип указателя на объект. Например:
type
PChar=AChar; {объявление типа указателя} var
p:PChar; {объявление указателя}
begin
p:=New(PChar);{вызов New как функции}
end.
При использовании New в виде функции, как и при традиционнс использовании этой процедуры, можно указывать второй парамет] представляющий собой конструктор объектного типа.
Программа, в которой используются процедуры New и Dispose, также функция MemAvail, содержится в примере 6.3.
Пример 6.3
Program New_Disp;
type
ar = array[1..10] of integer;
var
P : Aar;
begin
writein;
writein('Свободно (до выделения памяти)	memavail,' байт');
New(p);
writein('Свободно (после выделения памяти)	',memavail,' байт');
Dispose(р);
writein('Свободно (после освобождения памяти) ',memavail,' байт'); end.
Здесь на экран выводятся сведения об общем объеме свободной ди намической памяти, возвращаемые функцией MemAvail до и после вы деления памятй (процедурой New), а также после освобождения памя" (процедурой Dispose).
Процедура Release
Освобождает часть кучи. Заголовок процедуры:
Procedure Release(Var р : Pointer);
где Р—указатель любого типа, ранее определенный процедурой Mark.
174
Turbo Pascal: учитесь программирован
1 Три обращении к процедуре Release освобождается часть кучи от адреса, на который указывает Р, до конца кучи.
Программа, в которой используются процедуры Mark, Release, New, а также функция MemAvail, содержится в примере 6.4.
”	Пример 6.4
program MarkRelease;
var
pl, p2 : 'Real;
РЗ, P4 : 'Integer;
begin
WriteLn;
WriteLn('Свободно (до выделения памяти)	'.MemAvail,'
байт');
New(pl); {Выделяем память для pl}
New(p2); {Выделяем память для р2}
Mark(p2);{Сохраняем состояние кучи}
WriteLn('Свободно (после первого выделения памяти)'.MemAvail,' байт');
New(p3); {Выделяем память для рЗ}
New(p4); {Выделяем память для р4}
WriteLn('Свободно (после второго выделения памяти)'.MemAvail,' байт');
Release(p2);
WriteLn('Свободно (после освобождения памяти)	'.MemAvail,'
байт');
end.
В этой программе сначала выделяется память для двух переменных типа Real; затем запоминается текущий адрес начала свободного участка динамической памяти (с помощью процедуры Mark); после этого снова выделяется память — на этот раз для двух переменных типа Integer; наконец память освобождается (с помощью процедуры Release) от адреса, запомненного с помощью процедуры Mark, и до конца кучи. Во всех ключевых точках программы на экран выводится информация о количестве свободной динамической памяти. Программа демонстрирует, что память, занятая переменными РЗ и Р4 при этом освобождается, а переменные Р1 и Р2 по-прежнему могут использоваться.
Функция SizeOf
Возвращает число байтов, занимаемых объектом, указанным в качестве параметра функции. Заголовок функции:
Function SizeOf(х) : Integer;
где X — идентификатор типа или переменной.
Глава 6. Динамическая память и указатели
175
Например, выражение SizeOf (Integer) имеет значение 2. Это же зц чение имеет выражение SizeOf(х), если X — переменная (но не выраг ние) типа Integer.
Примеры программ, в которых используется функция SizeOf, прив дены в разделах “Процедура GetMem” и “Функция MemAvail”.
Работа с обширным массивом
Кажется, сейчас самое подходящее время вернуться к массиву, с к< торым мы пытались работать в начале данной главы. (Собственно, от кладывать уже некуда, — до конца главы рукой подать.) Помните, мае сив, содержащий 15 тысяч элементов типа Longlnt, мы смогли обрабо тать, а 20 тысяч — уже нет? Поскольку максимальная размерность дл1 структурированных типов составляет всего 65520 байт, а объем дин мической памяти (или кучи) приблизительно 300000 байт, почему бы не воспользоваться этой памятью для обработки обширных массивов? Од нако и при использовании динамической памяти сохраняется ограни чение на максимальную размерность для структурированных типот (65520 байт). Поэтому не удастся, выделив предварительно динамич скую память (с помощью процедуры NEW), просто объявить наш масст в разделе описания переменных. Однако, для того чтобы преодолет барьер в 65520 байт, можно создать массив из 9 элементов, представ ляющих собой нетипизированые указатели на участки в памяти (или н блоки). При этом каждый из таких блоков предназначен для 8000 эле ментов типа Longlnt. (Другими словами, мы попытаемся работать с мае сивом из 72 тысяч элементов — это приблизительно соответствует во можностям динамической памяти.) Почему для ссылок на участки п мяти, ь которых будут храниться блоки (по 8000 элементов) наше! обширного массива, используются именно нетипизированные указате ли? Дело в гом, что для резервирования памяти под динамическую пе ременную, на которую ссылается нетипизированный указатель, ис пользуется процедура GetMem. А эта процедура, в отличие от процедурь New, ис пользуемой для типизированных указателей, имеет параметр позволяющий указать объем резервируемой памяти. Иными словамi данный прием позволяет определить указатель на первый элемент бло ка из 8000 элементов и одновременно зарезервировать память для ос тальных 7999 элементов блока.
Как может выглядеть соответствующая программа, демонстрируеч пример 6.5.
176
Turbo Pascal: учитесь программирове
internet
program array2;
const number=8000;	{число элементов в одном блоке}
type
ab=array[0..0] of longint;
pab=Aab;
var
ch:array[0..8] of pointer;
total,i:longint;
begin
total:=number*9;	{число элементов в 9-ти блоках}
writein('Свободная память=	memavail,'; наибольший участок= ',maxavail);
for i:=0 to 8 do getmem(ch[i], number*sizeof(longint)); {резервир.
памяти}
for i:=0 to total-1 do
pab(ch[i div number])A[i mod number]:=i; {Присвоение порядкового номера}
for i:=0 to total-1 do
if (i mod 1000=0) or (i=total) then
write(i:10, pab(ch[i div number])A[i mod number]:6);
writein;
writein('Свободная память= ',memavail,'; наибольший участок= ',maxavail); readln
end.
Здесь константа Number задает количество элементов в блоке. Переменная CH (ch:array[0. .8] of pointer) описывает массив нетипизиро-ванных указателей на первые элементы в каждом блоке. Переменная Total содержит общее число элементов во всех блоках (total: =number *9).
До начала выделения динамической памяти и после (в конце программы) на экран выводятся значения общего свободного пространства кучи и ее наибольшего непрерывного свободного участка (функции MemAvail и MaxAvail соответственно). Наконец, для обрабатываемого нами массива выделяется динамическая память:
for i:=0 to 8 do getmem(ch[i], number*sizeof(longint))
Здесь значение переменной I соответствует номеру очередного блока, под который выделяется память. Процедура GetMem (резервирующая за нетипизированным указателем фрагмент динамической памяти) имеет два параметра. Первый из них (ch[ i ]) — нетипизированный указатель, ссылающийся на область в динамической памяти, предназначенную для первого элемента блока. Второй элемент процедуры (^umber*SizeOf (longint)) определяет размер динамической переменной в байтах. В нашем случае Number — это число элементов в блоке (8000). Функция SizeOf возвращает длину внутреннего представления указанного объекта (для типа Longlnt — 4 байта). Теперь можно вычислить.
г лава 6. Динамическая память и указатели
177
сколько всего байт памяти резервируется — 9 блоков умножить на 80 элементов в блоке, умножить на 4 байта для каждого элемента — ито 288 тыс. байт. Именно такой должна быть разница между значениям возвращаемыми функцией MemAvail вначале и в конце программы.
Далее программа заносит некоторые значения (собственно, значенв параметра цикла) по адресам памяти, выделенным для каждого из эле ментов нашего обширного массива:
for i:=0 to total-1 do
pab(ch[i div number])'[i mod number]:=i
Этот оператор, собственно вторая его половина, требует более npi стального внимания. С первой половиной все ясно — оператор цикла параметром for i:=0 to total-1 do организует обращение к каждому и элементов, содержавшихся в девяти блоках, созданных нами в динами ческой памяти. Но каким образом совершается само обращение? Дл того чтобы это понять лучше, взглянем на рис. 6.6.
Массив из девяти указателей на первые элементы девяти блоков
I	I
pab(ch[i div number])
“1 --------'
Номер блока и номер первого элемента в блоке
[i mod number] := i;
1 г 1
Индекс элемента массива РаЬ (номер элемента в блоке)
Приведение переменной Ch к типу РаЬ и разыменование
Рис. 6.6. Обращение к каждому из элементов обширного массива
Очевидно, что в строке программы, представленной на рис. 6 выражение i div number определяет номер блока, а выражение i mo number — номер каждого элемента в блоке. (Результат операции дел< ния DIV — целое число без остатка. Результат операции MOD — оста ток от деления двух целых чисел.) Вспомним, что СН — это массив и девяти указателей на первые элементы блоков, поэтому выражени ch[i div number] представляет собой обращение к первым элемента' девяти блоков.
Но каким образом можно обратиться к каждому элементу в каждо блоке? Для этрго массив СН (массив нетипизированных указателе! приводится к типу Pab (pab(ch[i div number]). Мы помним, что РаЬ — эт< указатель на массив элементов Longlnt. Затем этот указатель разымепх ется (т.е. преобразуется в обращение к самому массиву) и к выражени!' представляющему идентификатор массива (pab(ch[i div number]'), д< бавляется индекс ([i mod number]). Таким образом, выражение pab(ch[
178
Turbo Pascal: учитесь программироват
div number])А(1 mod number] обеспечивает обращение к каждому из элементов массива из 72000 (8000x9) элементов Longlnt.
Затем на экран выводятся значения каждого тысячного, а также последнего элементов нашего массива:
for i:=l to total do
if (i mod 1000=0) or (i=total-l) then
write(i:10, pab(ch[i div number])A[i mod number]:6);
Причем, как и в программе из начала главы, значение каждого элемента выводится (для контроля) в паре со значением параметра цикла I — эти значения должны совпадать.
Наконец, снова на экран выводится информация об общем свободном пространстве кучи и ее наибольшем непрерывном свободном участке (функции MemAvail и MaxAvail соответственно).
Последний оператор программы (функция ReadLn) присутствует здесь для того, чтобы приостановить работу программы и предоставить возможность спокойно рассмотреть экран вывода. Теперь, чтобы завершить программу, достаточно нажать клавишу <Enter>. Как выглядит экран вывода программы Аггау2, демонстрирует рис. 6.7. Обязательно сравните этот экран с рис. 6.1 в начале данной главы. Такое сравнение демонстрирует возможности, предоставляемые динамической памятью. Используя только статическую память, мы смогли обработать массив всего из 15000 элементов Longlnt, однако, воспользовавшись динамической памятью, нам удалось справиться с массивом, включающим 72000 таких же элементов.
би6одная	память»	233624: наибольший		участо».я 238624					
1000	1006	2000	2000	3000	3000	4000	4000	5000	5000
6000	6000	7000	7000	8000	8000	3000	3000	10009	10090
11000	11000	12000	12000	13000	13000	14 000	14000	15000	15006
16000	16000	17000	17000	18000	18000	19000	13000	20009	20090
21000	21000	22000	22000	2 3000	2 3009	24000	24000	2 5000	25009
26000	26000	27000	27000	28-000	28000	2'3000	29000	30000	30000
31000	31000	32000	32000	ЗЗООО	ЗЗООО	34000	34000	35000	35000
36000	36000	3 7000	37000	38000	38000	31000	39000	40000	40000
41000	41000	42000	42000	43000	4 3000	44000	44000	4 5000	45009
46000	46000	4 7000	47000	48000	48000	41000	49000	50000	50090
51000	51000	52009	52000	5 3000	5 3000	54000	54000	5 5000	55000
56000	56000	5 7000	5 7000	5 8009	58000	51000	59000	50000	60090
61000	61000	62000	62000	63000	53000	54000	6-40П0	65000	55000
66000	66000	67000	57000	68000	68000	6'3000	69000	70000	• 0090
71000	71000	72000	72000						
l: -)6<«дная	*13ДОТЪ»	6-24 наиг-с.“.ыипй участок^			624				
Рис. 6.7. Экран вывода программы Array2
Внимательный читатель обратит внимание, что в программе Аггау2 Динамическая память выделяется (с помощью процедуры GetMem), од-Пако затем не освобождается. Не противоречит ли это тому, о чем шла
Глава 6. Динамическая память и указатели
179
речь в данной главе (что зарезервированную ранее динамическую г мять всегда непременно следует освобождать)?
Дело в том, что освобождение памяти — не самоцель. Память следу освобождать тогда, когда ее затем требуется использовать для друп переменных. В нашем случае в момент, когда динамическую памя . ь можно было бы освободить, программа уже завершается. Иными слов~ ми, бессмысленно освобождать память, которую затем не предполагает ся использовать. А при повторном запуске программы Аггау2 экран вы вода засвидетельствует, что динамическая память снова имеет исходный объем — 288624 байта. Для того чтобы убедиться в этом, достаточно еще раз запустить программу.
180
Turbo Pascal: учитесь программировать
Глава 7
Типизированные константы
В этой главе...
	О типизированных константах
	Константы простых типов
	Константы-строки
	Константы-массивы
	Константы-записи
	Константы-множества
	Константы-указатели
Из главы 1 мы уже знаем, что константа очень похожа на переме, ную, только значение ее задается при объявлении и не изменяется в х де работы программы. Так вот, в Turbo Pascal (в стандартном Pascal кого не было), помимо обычных констант (что это такое— мы тол. что вспомнили), введено понятие типизированных констант. Им и священа данная глава.
Знакомство с типизированными константами
Объявление типизированной константы (С2) в разделе описани констант выглядит так: const cl = value;
с2 : type = value;
(Здесь для сравнения даны описания обычной (С1) и типизированной (С2) констант.) Вот какой смысл имеют различные элементы в эти описаниях:
С1 и С2 — идентификаторы обычной и типизированной констант;
Туре — тип константы; нетрудно заметить, что данный элемент при сутствует в описании только типизированной константы — это и явля ется ее основной внешней отличительной особенностью;
Value— значение, присваиваемое константе (как типизированной так и нетипизированной) при объявлении.
Типизированная константа— это нечто среднее между обычно константой и переменной, поскольку она обладает свойствами и кон стант, и переменных. Свойства, о которых идет речь, перечислены i табл. 7.1.
Таблица 7.1. Два вида свойств типизированных констант
Свойства констант	Свойства переменных
Типизированная константа, как и обычная константа, объявляется в разделе описаний констант Подобно обычным константам, типизированным константам присваивается при объявлении некоторое значение	Подобно переменным при объявлении типизированных констант указывается тип данных Как и переменной, типизированной константе можно присвоить новое значение (т.е. идентификатор типизированной константы может присутствовать в операторе присваивания слева)
182
Turbo Pascal: учитесь программировав
Из сказанного видно, что название типизированная константа невольно условно. По сути, поскольку ей допускается присваивать новые значения, типизированная константа мало чем отличается от переменной. Для чего же тогда понадобилось вводить в Turbo Pascal это новое понятие? Неужели нельзя было обойтись традиционными константами п привычными переменными? Дело в том, что привычные переменные между началом работы программы и моментом, когда им присваиваются значения (т.е. когда они инициализируются), имеют неопределенное состояние. А обращение к переменной в неопределенном состоянии может привести к непредсказуемым последствиям, в том числе и зависанию компьютера. Типизированные же константы инициализируются уже в момент объявления.
В таком случае чем плохи традиционные константы? Им тоже присваиваются значения в момент объявления! А традиционным константам нельзя присваивать новые значения. Итак, те, кто создавал Turbo Pascal, сочли, что в этом языке программирования необходим объект, который инициализируется в момент объявления (подобно константе), но которому в процессе работы программы можно присваивать новые значения (подобно переменной).
Типизированные константы, поскольку они мало чем отличаются от переменных (т.е. заранее невозможно предсказать, какое они примут значение в ходе работы программы), не могут использоваться в описании других констант или типов.
Типизированная константа может принадлежать любому типу— простому или структурированному. Иными словами, типизированная константа может быть объявлена с любым целочисленным или вещественным типом, типом Boolean или Char, типом STRING; кроме того, значение типизированной константы может представлять собой массив, запись, множество или указатель. В то же время типизированная константа не может быть файлом. Также не удастся объявить типизированную кон-•танту-запись, одно из полей которой представляет собой файл. Как объ-1<?лять типизированные константы различных типов и присваивать им гужные значения, мы узнаем из соответствующих разделов.
Константы простых типов
Здесь все просто. Указывается идентификатор константы, ее тип и ’качение:
const
al	:	real	- 6.566;
symb	:	char	= 'H';
Start	:	integer	= 10;
Finish	:	integer	= 20;
^ава 7. Типизированные константы
183
Как уже отмечалось, идентификаторы типизированных кони нельзя использовать в описаниях других констант, типов и перем ных. Например, если, используя объявленные выше константы Start Finish, попробовать объявить переменную:
var
a:array [Start..Finish] of char;
то будет зафиксирована ошибка.
Также не допускается в разделе описания констант объявлять тип зированные (а также и обычные) константы списком:
const
symbl,symb2,symb3 : char = 'R'; {Неправильное объявление}
Константы-строки
Это также просто. Помимо идентификатора, типа и начального с держимого строки, указывается только ее максимальная длина. Ес максимальная длина не указана, по умолчанию эта величина принт ется равной 255 символов. Вот пара примеров:
const
Headline : string[10] = 'Глава';
АВ	: string[26] = 'abcdefghijklmnopqrstuvwxyz';
Константы-массивы
Описания типизированных констант-массивов выглядят так: const
num : array [1..8] of char = ('O','1','2','3','4','5','6','7');
row : array [1..10] of integer = (0,1,2,3,4,5,6,7,8,9);
Другими словами, как и при описании констант простых типов, тр буется указать идентификатор константы, ее тип и начальное значеш Начальное значение для массива представляет собой перечень зна1 ний его элементов, разделенный запятыми и заключенный в скобь Причем, поскольку в Turbo Pascal как строки, так и массивы содержа' в упакованном формате, при указании содержимого символьного м сива, можно задать строку, содержащую соответствующее число ну ных символов. Например, массив Num из предыдущего примера моя объявить и так:
num : array [1..8] of char = '01234567';
Здесь следует обратить внимание читателей на удобство присвоен* элементам массива нужных значений, когда этот массив объявляется качестве типизированной константы. Это можно сделать прямо пр
184
Turbo Pascal: учитесь программирова
явлении. Когда мы имели дело с массивом-переменной, то, для того бы присвоить его элементам нужные значения, приходилось исполь-ать оператор цикла с параметром: var
i:integer;
al:array [1..8] of char;
a2:array [1..8] of integer;
jegin
for i:=l to 8 do
begin
read (al[i]);
a2[i]:=i
end end.
Здесь значения элементов массива Al вводятся с клавиатуры, а эле-там массива А2 присваиваются значения параметра I.
Что касается типизированных констант, представляющих собой огомерные массивы, то значения каждого измерения заключаются в 1ельные скобки и разделяются запятыми. Глубина вложенности соот-с гвует числу измерений массива, а самые вложенные значения — юму правому индексу в его описании. Например, вот как можно объ-ть двумерный массив:
st
square : array [1..3, 1..4] of integer ((1,2,3,4),(5,6,7,8),(9,10,11,12));
)бъявленный здесь в качестве типизированной константы двумерный ив целых чисел имеет размерность 3x4. Поскольку массив двумер-I, значения его элементов представлены с использованием двухуров-вложенности. Причем самый глубокий уровень вложенности (по че-je значения) соответствует правому индексу в описании массива (1-4).
Константы-записи
При объявлении типизированной константы-записи следует указать идентификатор, тип, а также имя и значение каждого поля. Причем ры имя-значение разделяются внутри двоеточиями, между собой — мволом “точка с запятой" и заключаются в круглые скобки. Для приза воспользуемся описанием типа Employee из главы 4: type
Employee=record
ID:word; {Идентификатор (личный номер)}
FirstName,SecondName,SurName:string(20); {Имя, фамилия, отчество} Standing:byte; {Стаж}
Salary:real	{Зарплата}
end;
ibq 7. Типизированные константы
185
const
Assistant : Employee =
(ID	:14873;
SurName	:Петров;
FirstName :Иван ;
SecondName:Кузьмич;
Standing	:15;
Salary	:1000);
Поля в описании константы должны быть представлены в той же . следовательности. что и в описании соответствующего типа. Если запись с вариантами, при объявлении константы можно указать полз их значения) только одного из вариантов (на ваш выбор). Как уже уъ зывалось, типизированную константу-запись, одно из полей котор. представляет собой файл, объявить не удастся.
Константы-множества
Описание типизированной константы-множества, помимо идент фикатора константы и идентификатора типа, должно содержать пер чень начальных значений, разделенных запятыми и заключенных квадратные скобки. Если группа начальных значений образует нера рывную последовательность, она может быть представлена в виде ди. пазона. Вот примеры объявлений констант-множеств:
type
al : set of 1.,15;
a2 : set of char;
const
Ы : al = [1, 2, 3..5, 8, 12..15];
b2 : a2 = ['a', 'd', 'f..i', '1'];
b3 : set of 'O'..'9' = ('1', '3', '5'..'8'];
В этом примере в описаниях первых двух констант [В1 и В2) испол? зованы ранее объявленные типы (AI и А2). В описании третьей кон станты (ВЗ) использован анонимный тип (set of ' 0'..' 9').
Константы-указатели
При объявлении константы-указателя для определения ее значени обычно используется константное адресное выражение. Значением этой выражения (и константы) является адрес глобальной переменной, тит зированной константы, процедуры или функции. Константное адресно' выражение не может ссылаться на локальные или динамические пер менные, поскольку их адреса не могут быть вычислены при компиляции
И 86	Turbo Pascal: учитесь программировав
Рассмотрим примеры:
type
р = "byte;
const
РР : р = nil;
pb : byte = 0;
pa : p = gpb;
Здесь объявлен тип P, являющийся указателем на адрес в памяти, по которому содержатся данные типа Byte. Кроме того, объявлены три константы-указателя — РР, РА и РВ. Первая константа (РР) имеет тип Р и ей присвоено значение NIL. Вторая константа (РВ) объявлена с типом Byte, и наконец, третья константа (РА) имеет тип Р (как и РР) и ей присвоено значение @РВ. Иными словами, РА— это указатель на адрес в памяти, по которому содержится константа РВ. Здесь NIL и @РВ— контактные адресные выражения. (@ — оператор, позволяющий создавать указатели). Подробно об указателях речь шла в главе 6.
187
Глава 7. Типизированные константы
В этой главе.,.
	Стандартные модули
	Структура модуля
	Компиляция модулей
	Использование модулей
	Библиотеки модулей.
	Утилиты Turbo Pascal
Модули, о которых пойдет речь в данной главе, развивают концепцию структурирования программ, начало которой положили подпрс граммы. В этой главе мы выясним, какие стандартные модули имеютсг в составе Turbo Pascal 7.0, познакомимся со структурой модуля, узнаем о библиотеках модулей, а также откроем для себя несколько утилит имеющихся в составе Turbo Pascal, которые предназначены для работы с модулями и не только.
Кое-что о модулях
Мы уже имели дело с подпрограммами и знаем, что подпрограммы, помимо прочего, — это еще и средство структурирования программ Идея в том, чтобы программа состояла не из огромного числа операторов, а из относительно самостоятельных частей (подпрограмм), каждой из которых назначена отдельная, сравнительно узкая роль. Такие самостоятельные части можно было бы затем использовать в отдельной программе единожды или многократно, — каждый раз, когда потребуется выполнить соответствующее действие. Вот перечень преимуществ, которые предоставляет этот подход.
 Программа получается понятнее и ее легче совершенствовать в дальнейшем.
 При этом программы можно создавать не в одиночку, а коллекти вом. Каждый член коллектива разработчиков создает определенный набор подпрограмм, из которых затем собирается большая программа.
 Если действие, выполняемое подпрограммой, встречается доста точно часто, ничто не мешает сколько угодно использовать эту удачную подпрограмму и в других программах.
Однако, как осуществить это практически? Как использовать подпрограммы в разных программах? И как созданные разными разработ чиками подпрограммы объединить в единую программу? И в каком виде хранить все эти подпрограммы?
Можно, конечно, содержать исходные тексты полезных подпрограмм-в текстовых файлах и по мере необходимости вручную копировать их в программы. Однако трудно отделаться от мысли, что такое решение — не самое йзящное из возможных. Видимо так же рассуждали создатели языка программирования Turbo Pascal, когда вводили в него понять модулей (в стандартном Pascal этого не было).
Модуль— это самостоятельно компилируемый файл Turbo Pascal-который может содержать описания констант, переменных и типов, а также процедур и функций. После того как модуль создан и откомпилИ рован, его ресурсы можно использовать в любой программе на Turb' Pascal, просто указав имя этого модуля. Нетрудно придти к выводу, чтс
190
Turbo Pascal: учитесь программироват
модули, являясь мощным инструментом структурного программирования, еще и очень удобное средство создания и хранения библиотек часто используемых процедур и функций.
Из каких составных частей состоит модуль, как его создать и откомпилировать — эти вопросы мы выясним дальше в этой главе. Сейчас же познакомимся со стандартными модулями и узнаем, как ресурсы имеющегося модуля можно использовать в программе.
Стандартные модули
В состав Turbo Pascal 7.0 входит набор стандартных модулей (всего восемь). содержащих множество предопределенных типов, констант, переменных, процедур и функций, которые без ограничений можно использовать в пользовательских программах. Речь идет о модулях SYSTEM, DOS, CR1', PRINTER, GRAPH, OVERLAY, TURBO3 и GRAPH3. Краткая характеристика каждого из них содержится в этом разделе дальше. Помимо стандартных (входящих в состав Turbo Pascal 7.0), существует множество специализированных модулей, которые можно найти в Internet на Web-узлах, посвященных программированию на Turbo Pascal. Перечень таких Web-узлов (с адресами) имеется в Приложении Д.
Итак, всем понятно, что имеется несколько готовых модулей. Но как их ресурсы (в частности, содержащиеся в них процедуры и функции) можно использовать в своей программе? Для того чтобы такое использование стало возможно, следует к этой программе подключить нужный модуль. Как это делается?
Прежде всего, модуль SYSTEM подключается к любой программе на Turbo Pascal автоматически. Иными словами, его ресурсы (те же процедуры и функции) можно использовать сразу без каких-либо дополнительных действий. Например, мы часто пользовались процедурами Read. ReadLn. Write, WriteLn. Это процедуры из модуля SYSTEM. Кроме того, в предыдущих главах нам приходилось иметь дело со множеством процедур и функций, предназначенных для арифметических расчетов. Для работы с файлами, с памятью и пр. Все они также содержатся в модуле SYSTEM.
Для того чтобы использовать в программе средства иного модуля (не SYSTEM), как уже отмечалось, этот модуль необходимо к программе подключить. Для этого достаточно указать имя этого модуля после слова USES:
uses dos;
begin
WriteLn('Свободно	DiskFree(3) Div 1024, 'Кбайт.');
end.
•лава 8. Модули
191
USES это зарезервированное слово, имеющее смысл “использует Иными словами, после этого слова в тексте программы следует перечещ модулей, которые используетданная программа.
В примере программы выше использована функция DiskFree из модуля DOS, возвращающая объем свободного пространства на опреде ленном диске. (Значение параметра функции (3) соответствует диску с* а для того чтобы пространство было представлено в килобайтах, воз вращаемый функцией результат делится на 1024.)
Аналогично можно подключить к программе и любой другой модуль стандартный или созданный пользователями. Более того, модули к программе можно подключать Списком:
uses dos, graph, crt;
В заключение, опишем все стандартные модули:
Модуль SYSTEM. Это основное хранилище Turbo Pascal, в которог_ содержатся подпрограммы поддержки всех встроенных возможностей языка программирования, таких как файловый ввод-вывод, обработка строк, целочисленная арифметика, арифметика с плавающей точкой и динамическое распределение памяти. Поскольку со многими из этих подпрограмм мы уже познакомились при изучении различных тем, в этой книге не будет главы, специально посвященной ресурсам модуля SYSTEM. Описания подпрограмм модуля SYSTEM, которые не были рассмотрены в главах, можно найти в Приложении Б.
Как уже отмечалось, модуль SYSTEM не требуется указывать в разделе USES программы.
Модуль DOS. Здесь собраны процедуры и функции (а также переменные и константы), позволяющие из программ получать доступ к средствам MS DOS и управлять файлами. Подробно ресурсы модуля DOS рассматриваются в главе 9.
Модуль CRT. Подпрограммы этого модуля позволяют управлять текстовыми режимами экрана, его цветами и окнами, яркостью свече ния символов, а также расширенными кодами клавиатуры и звуком Подробно ресурсы модуля CRT рассматриваются в главе 10.
Модуль PRINTER. В этом модуле объявляется файловая переменная LST (только}, имеющая тип TEXT, которая ассоциируется с системным устройством LPT1:
var
1st : text;
begin
assign(lst,'LPT1');
После этого, когда потребуется из программы инициировать печаг на принтере, от вас не потребуется объявлять, назначать, открыват! закрывать текстовый файл. Достаточно будет только указать LSL в ) честве первого параметра процедуры Write:
192
Turbo Pascal: учитесь программировс.
write(1st,'Печать на принтере');
(Файл LST при печати на принтере играет приблизительно ту же 1Ь, что и файл OUTPUT при выводе на экран. Только OUTPUT не нуж-указывать в качестве параметра процедуры Write.)
Естественно, для того чтобы иметь возможность использовать в про-амме файловую переменную LST, следует не забыть подключить к >й программе модуль PRINTER.
Модуль GRAPH. Содержит множество подпрограмм, а также кон-iHT, типов и переменных, предназначенных для управления графиче-им режимом экрана. Ресурсы модуля позволяют обратиться к любому жселю экрана и управлять его свечением.
Запустить программу, использующую модуль GRAPH, без графиче-ого драйвера (одного или нескольких— это файлы с расширением GI) не удастся. Указанные драйверы не входят в состав модуля, но по-авляются с Turbo Pascal 7.0 (они содержатся в каталоге BGI). А если в юграмме используются векторные шрифты, в дополнение к драйве-iM, потребуются также файлы шрифтов (файлы с расширением .CHR).
>дробно ресурсы модуля GRAPH рассматриваются в главе 11.
Модуль OVERLAY. При разработке крупных программ возможна си-ация, когда памяти компьютера не хватает для загрузки в нее всей юграммы. Turbo Pascal предоставляет выход, позволяя разбить про->амму на отдельные сегменты (оверлейные сегменты или оверлеи). При ом в память в каждый момент загружен тот из оверлеев, который не->ходим для выполнения текущих действий. Средства, позволяющие азбить программу на оверлеи, содержатся в стандартном модуле VERLAY. Поскольку на сегодняшний день Turbo Pascal как средство азработки крупных программ утратил свое значение и используется в новном в учебных целях, в этой книге не будет специальной главы, i «священной средствам модуля OVERLAY.
Модули TURBO3 и GRAPH3. Они предназначены для поддержания овместимости с Turbo Pascal 3.0. Поскольку эта старая версия Turbo 'ascal сегодйя практически не используется, ресурсы данных модулей 1Ы рассматривать не будем.
Все эти модули, за исключением GRAPH, TURBO3 и GRAPH3, содер-катся в библиотечном файле TURBO .TPL. Что касается упомянутых ‘рех модулей, то для каждого из них предусмотрен отдельный файл с именем, соответствующим имени модуля, и расширением .TPU.
Структура модуля
Поскольку модуль в Turbo Pascal— самостоятельная, отдельно компи-лируемая единица, структура модуля чем-то напоминает структуру обыч-
' лава 8. Модули 7-2016
193
ной программы20. Чем именно? Ну, хотя бы тем, что модуль, как и пр грамма, начинается заголовком и завершается зарезервированным сл< вом END с точкой. Вот как схематически выглядит структура модуля:
| unit Заголовок модуля |
interface
Интерфейсный раздел
implementation
Раздел реализации
begin
Инициирующий раздел
end.
Встречающиеся здесь зарезервированные слова имеют следуют смысл:
UNIT — модуль; после этого слова следует заголовок модуля;
INTERFACE — интерфейс, начинает интерфейсный раздел модуля IMPLEMENTATION — реализация; начинает раздел реализации.
С зарезервированными словами BEGIN и END мы уже встречали) В модуле они имеют тот же смысл, что и в обычной программе, одна в модуле слово BEGIN служит признаком начала инициирующего р; дела. (Существование в модуле инициирующего раздела и соответс венно наличие слова BEGIN необязательно.) Что касается слова EN1 то оно здесь служит признаком конца модуля, а не конца инициируг щего раздела. Иными словами, здесь слово END — пара слову UNIT, не слову BEGIN.
Здесь же следует упомянуть, что каждый из разделов модуля мож быть пустым. В этом случае после заголовка пустого раздела сразу сг дует заголовок следующего раздела.
А теперь подробно рассмотрим каждый раздел модуля.
Заголовок модуля
Заголовок начинается зарезервированным словом UNIT, за которы следует идентификатор, являющийся именем модуля, например,
unit АВС;
20
Чтобы убедиться в этом, достаточно заглянуть в приложение Г.
194
Turbo Pascal: учитесь программирова
Имя модуля следует указать в разделе USES программы, в которой еобходим доступ к данному модулю. Заголовок модуля должен завер-1аться символом “точка с запятой”.
Исходный текст модуля, как и обычной программы, содержится в айле с расширением .PAS. При компиляции модуля на диске создается >айл с объектным кодом (файл с расширением .TPU).
Интерфейсный раздел
Этот раздел обеспечивает взаимодействие модуля с другими модуля-tn (стандартными и пользовательскими), а также с основной программой. В интерфейсной части объявляются глобальные (т.е. доступные юльзователям модуля) константы, типы, переменные, процедуры и функции. В этом разделе возможны несколько подразделов, которые перечислены в табл. 8.1.
аблица 8.1. Структура интерфейсного раздела модуля
Подраздел	Содержимое подраздела
USES	Содержит список импорта. Здесь представлены имена других модулей, ресурсы которых используются в разделе INRERFACE. (В разделе IMPLEMENTATION может быть свой подраздел USES)
CONST TYPE VAR	Содержат списки экспорта. Здесь представлены описания глобальных констант, типов и переменных модуля, которые становятся доступны в программе при подключении к ней данного модуля
Кроме того, в интерфейсном разделе должны быть представлены заголовки глобальных (т.е. видимых программам и другим модулям) подпрограмм данного модуля. Заголовок подпрограммы включает зарезервированное слово PROCEDURE или FUNCTION, имя подпрограммы и перечень параметров. Глобальные объекты модуля (константы, типы, переменные и подпрограммы) становятся доступны в основной программе (или в другом модуле) после подключения к ней (к нему) данного Модуля. Например, интерфейсный раздел модуля (с заголовком) может выглядеть так:
unit АВС;
{-----------------------------------------}
interface
type
symbols = array ['a'..'z') of char;
procedure AA (al, a2 : symbols; var a3 : symbols);
function AB (al, a2 : symbols) : char;
В модуле Abe объявлены тип Symbols, процедура AA и функция АВ. Невидно, что. как и в обычной программе, описания в интерфейсном Ра4Целе модуля следует размещать так, чтобы константы, типы, переменные и подпрограммы, используемые в описании данного объекта,
Гл°ва 8. Модули
195
располагались выше. Например, тип Symbols в нашем примере обы лен до описаний процедуры АА и функции АВ, где он используете Применение опережающих описаний (с ними мы познакомились nj изучении рекурсии — это когда используется зарезервированное слс FORWARD) в интерфейсном разделе модуля не допускается.
Раздел реализации
В этом разделе содержатся описания процедур и функций, заголовк которых представлены в интерфейсном разделе модуля. Кроме toi здесь мохут быть объявлены локальные (т.е. доступные только в пред» лах данного модуля) константы, типы, метки (если они применяются инициирующем разделе) и переменные. Все описания, содержащиеся разделе IMPLEMENTATION, недоступны для программ и других модулег
В этом разделе, как и в предыдущем, возможны несколько подразг лов, которые перечислены в табл. 8.2.
Таблица 8.2. Структура раздела реализации модуля	
Подраздел	Содержимое подраздела
USES	Так же, как и в разделе INTERFACE, этот подраздел содержит список импорта. Здесь представлены имена других модулей, ресурсы которых используется в разделе IMPLEMENTATION
LABEL	Содержат описания локальных для данного модуля меток, констант,
CONST	типов и переменных. Перечисленные объекты недоступны ни про
TYPE	граммам, ни другим модулям
VAR
Кроме того, в разделе реализации должны быть представлены ош сания подпрограмм, заголовки которых содержатся в предыдущем ра-деле. Причем в этих описаниях допустимы заголовки процедур и функ ций без списка формальных параметров (поскольку они уже указаны интерфейсном разделе). Однако, если в разделе IMPLEMENTATION заго ловок подпрограммы все же содержит параметры, их перечень должен совпадать с параметрами, указанными в разделе INTERFACE.
Читатель вправе задать вопрос, в чем разница между подразделам USES в интерфейсном разделе и разделе реализации? И для чего пои добилось иметь два таких подраздела — неужели нельзя было обойти» одним?
Дело в том, что подраздел USES в разделе реализации, в отличие интерфейсного раздела, позволяет сделать недоступным (или невь мым) для пользователей перечень указанных здесь модулей, к котор. обращается данный модуль. Еще важнее то, что это позволяет создават модули со взаимными обращениями (об этом речь пойдет дальше).
В заключение приведем пример раздела реализации (вместе с заг< ловком и интерфейсным разделом из предыдущего примера):
196
Turbo Pascal: учитесь программиров'
unit ABC;
{-----------------------------------------}
interface
type
symbols = array ['a'..'z') of char;
procedure AA (al, a2 : symbols; var a3 : symbols);
function AB (al, a2 : symbols) : char;
{-----------------------------------------}
implementation
procedure AA;
begin
end;
function AB;
begin
end;
В разделе реализации содержатся описания процедуры АЛ и функции АВ, заголовки которых представлены в интерфейсном разделе. Операторы, образующие тела процедуры и функции, представлены в □тих описаниях тремя точками.
Инициирующий раздел
В этом разделе мохут содержаться операторы, которые до передачи управления основной программе выполняют некоторые подготовительные действия. Например, здесь может быть инициализирована переменная (чтобы при обращении к этой переменной из программы она уже имела некоторое начальное значение), или могут открываться файлы (чтобы не делать этого в каждой программе, к которой данный модуль будет подключен).
Инициирующий раздел в модуле может быть опущен. В этом случае зарезервированное слово BEGIN отсутствует, а слово END., завершающее модуль, следует сразу за разделом IMPLEMENTATION. Инициирующий раздел (как и любой другой раздел модуля) может также быть пустым. В этом случае завершающее модуль слово END. следует за словом BEGIN.
Компиляция модулей
Если в результате компиляции программы получается исполняемый файл с расширением .EXE, то результатом компиляции модуля будет файл с расширением .TPU (Turbo Pascal Unit). Возможны три режима
Глава 8. Модули
197
компиляции: COMPILE, МАКЕ21 и BUILD. О том, как инициировать т< или иной режим, вы узнаете из Приложения А, в котором содержат^ сведения об интегрированной среде разработчика. А особенности ка до го из режимов мы сейчас выясним.
В режиме COMPILE система ищет модули (перечисленные в поду, делах USES компилируемого модуля) сначала в файле TURBO.T' (TPL— Turbo Pascal Library— библиотека (модулей) Turbo Pascal). Ес какой-либо модуль (модули) здесь не обнаружится, соответствуюгц TPU-файл ищется в текущем каталоге. Если и здесь нужный файл найден, поиск продолжается в каталоге, указанном в поле Unit Directori диалогового окна, которое можно вызвать, выбрав пункт Directories м ню Options (рис. 8.1 — подробности о среде разработчика вы найдете Приложении А). В случае, если и здесь нужного TPU-файла не окажете на экране отобразитей сообщение об ошибке.
Рис. 8.1. Здесь можно сообщить интегрированной среде разработчика, где содержатся модули
При компиляции в режиме МАКЕ, система сначала проверяет naj чие нужных TPU-файлов (в тех же местах, которые перечислены выи для режима COMPILE). Если какой-либо из файлов не будет обнаружег предпринимается попытка отыскать там же одноименный файл с ис ходным кодом (файл с расширением .PAS). Если и этот файл не обнару жится, на экране отобразится сообщение об ошибке.
При этом система сравнивает даты последних изменений PAS-файл и созданщз.Д'Ри-файла. Если PAS-файл окажется более “свежим”, неза висимо от того, на месте или нет TPU-файл, система осуществляет ком пиляцию PAS-файла. Иными словами, если после предыдущей компи ляции в исходный код модуля были внесены какие-либо изменения, этом случае автоматически создается новый TPU-файл, который зам1 няет предыдущую версию этого файла.
21 Не путать режим компиляции МАКЕ с одноименной утилитой, о которой р пойдет в конце главы.
198
Turbo Pascal: учитесь программировс
Более того, если имели место изменения в интерфейсном разделе мо-(уля, будет заново осуществлена компиляция всех модулей, которые обращаются к компилируемому модулю. Иными словами, режим МАКЕ избавляет разработчиков от множества хлопот. При этом нет необходимости следить за изменениями в файлах с исходным кодом и заботиться ;> том, чтобы эти изменения вовремя отражались в TPU-файлах.
В режиме BUILD система, не обращая внимание на TPU-файлы, стремится найти файлы с исходным кодом (PAS-файлы) и откомпилировать каждый из модулей, к которым обращается компилируемый модуль.
Читатель может спросить, должно ли имя модуля, указанное после (арезервированного слова UNIT в заголовке, совпадать с именем TPU-файла? Собственно, при компиляции модуля TPU-файлу автоматически присваивается имя PAS-файла, в котором содержится исходный код. И □то имя может отличаться от указанного после слова UNIT. Однако хорошим правилом считается, чтобы имя в заголовке модуля и имя TPU-файла совпадали.
Использование модулей
В этом разделе мы рассмотрим некоторые типичные случаи и проблемы, возникающие при использовании модулей.
Порядок действия имен
Мы уже знаем, для того, чтобы в модуле (или программе) сделать доступными ресурсы другого модуля, достаточно имя этого модуля указать в подразделе USES. Вот так:
uses аа, ЬЬ, сс;
Но что если какой-либо из идентификаторов, описанных в интерфейсной части данного модуля (или в программе), совпадет с идентификатором вызываемого модуля? Или совпадут идентификаторы в двух вызываемых модулях? В этом случае начинает играть роль порядок, в котором имена модулей перечислены в разделе USES, и вступает в действие правило действия имен.
Помните, в главе 3, посвященной подпрограммам, мы выясняли, можно ли манипулировать в теле программы именами, объявленными в >дной из подпрограмм. И наоборот, можно ли имена, объявленные в разделе описаний программы, использовать в одной из подпрограмм. И 1то произойдет, если имена совпадут. Мы тогда пришли к выводу, что груктуру программы (т.е. схему вложения в нее подпрограмм), а также феры действия имен лучше всего изобразить графически. И что удобнее для этого использовать прямоугольники, вложенные один в другой.
лава 8. Модули	199
Так вот, этот же подход с некоторыми поправками применим и к моду лям. Если идентификаторы в программе и в подключаемом модуле сов падут, будет действовать описание для данного идентификатора имеющееся в программе. Если совпадут идентификаторы в модулях подключенных к программе, будет действовать описание для данной идентификатора, имеющееся в модуле, имя которого в подразделе USES указано последним. Рассмотрим пример:
program dd;	•
uses аа, bb, сс;
Здесь представлен заголовок программы DD и раздел USES этой про граммы, к которой подключаются модули АА, ВВ и СС. Правило види мости имен для указанных здесь модулей графически можно предел; вить так (рис. 8.2):
unit АА	var	х	:	boolean;
unit ВВ_____________var	х	:	real ;
unit CC	var	x	:	integer;
program DD	var x : char;
Puc. 8.2. Это поможет понять, какие имена
“видны” в том или ином модуле
Здесь в программе и трех подключаемых модулях объявлена пере менная X, однако в программе “видна” будет переменная, объявленная в разделе описаний программы (т.е. xtchar). Если это описание из пр< граммы удалить (или, допустим, переименовать переменную X), пре грамма начнет “видеть” описание, содержащееся в модуле СС (х: integer и так далее “изнутри наружу” (если смотреть на рис. 8.2).
Но что если в программе необходим доступ ко всем идентификаторам (в том числе и одноименным) из интерфейсов всех используемых моду лей? Для этого достаточно указать составное имя, похожее на составные имена, с которыми мы имели дело при изучении записей. Такое состав ное имя образуют имя модуля и нужный идентификатор. Например, дл того чтобы получить доступ к переменным X, которые объявлены в пр< грамме и •В’каждом подключаемом модуле рассмотренного выше прим» ра (см. рис. 8.2) и которые принадлежат разным типам, достаточно в те
ле программы использовать следующие операторы:
х :=	'Н'; {х - переменная типа Char из основной программы}
аа.х	:=	false;	{х	-	переменная	типа	Boolean	из модуля АА}
bb.x	:=	2.34;	{х	-	переменная	типа	Real из	модуля ВВ}
сс.х	:=	222;	{х	-	переменная	типа	Integer	из модуля СС}
200
Turbo Pascal: учитесь программироват
Косвенное использование модулей
Допустим, имеются модули А и В:
unit a;	unit b;
interface	interface
uses b;
...	end.
end.
Затем, предположим, создается программа, к которой необходимо юдключить модуль А. В этой ситуации говорят, что программа исполь-ует модуль А. Однако программа (косвенно) использует и модуль В, ко-орый подключается к модулю А.
Так вот, в фирменной документации по Turbo Pascal можно встре-ить указание о необходимости перечислять в подразделе USES про->аммы все модули — используемые явно и косвенно. Однако практика называет, что для правильной работы всех модулей, в программе юсле зарезервированного слова USES) достаточно указать имена толь-о модулей, в подключении которых к программе имеется непосредст-юнная необходимость. Если какой-либо из подключаемых к программе юдулей в свою очередь использует другие модули, указывать их в про-эамме вовсе необязательно.
Взаимное использование модулей
Предположим, имеются модули А и В, взаимно обращающиеся один одному:
unit a;	unit b;
interface	interface
uses b;	uses a;
end.	end.
Если какой-либо из этих модулей попытаться подключить к про-рамме, будет зафиксирована ошибка. Иными словами, взаимное ис-ользование модулей в продемонстрированном виде (т.е. когда модули т щключаются один к другому из интерфейсного раздела) недопустимо.
Однако взаимное использование все же возможно, если модули подключить из раздела реализации:
unit a;	unit Ь;
'юва 8. Модули
201
interface
interface
implementation uses b;
end.
implementation uses a;
end.
Порядок выполнения
инициирующих разделов
Мы уже знаем (об этом шла речь выше), что если в модуле имеете* инициирующий раздел, операторы этого раздела выполняются до выполнения операторов программы, к которой данный модуль подключен Но что если к программе подключены несколько модулей, в которых имеются инициирующие разделы? Инициирующий раздел какого модуля выполнится первым?
Предположим, автор не знает ответ на этот вопрос, но не беда. — в принципе, любой вопрос, связанный с Turbo Pascal, можно выяснить экспериментальным путем. Поэтому поэкспериментируем. Пусть име-
ются три модуля:		
unit аа;	unit bb;	unit cc;
interface	interface	interface
const	const	const
x:integer=l;	x:integer=2;	x:integer=3;
implementation	implementation	implementation
begin	begin	begin
writeln(x)	writeln(x)	writeln(x)
end.	end.	end.
Попробуем подключить их к программе. В инициирующем разделе ка ждого из модулей имеется оператор WriteLn(x), который выводит на экран значение типизированной константы X, соответствующее последователь ности, в которой имена модулей указаны после зарезервированного слова USES программы. Таким образом, порядок, в котором значения этих констант будут выведены на экран, позволит судить, в какой последователь-ностц выполняются инициирующие разделы подключаемых модулей. Соответствующая программа содержится в примере 8.1 (рис. 8.3). Здесь же (в окне Output) можно видеть результаты ее работы.
Таким образом, рис. 8.3 позволяет сделать вывод, что первым выполняется инициирующий раздел модуля, который указан первым в программе после зарезервированного слова USES.
202
Turbo Pascal: учитесь программировав
Пример 8.1
Библиотеки модулей.
Файл TURBO.TPL
Помимо создания модулей. Turbo Pascal предоставляет возможность объединять готовые модули в библиотеки. Файл библиотеки модулей имеет расширение .TPL (Turbo Pascal Library— библиотека Turbo Pascal). В этой главе уже шла речь об одном таком файле — TURBO.TPL, и нам известно, что в этой библиотеке содержатся пять стандартных модулей: SYSTEM, DOS, CRT. PRINTER и OVERLAY. Однако мы пока не знаем, что модули этой библиотеки автоматически загружаются в память компьютера и это значительно ускоряет к ним доступ22. Иными словами, если в каком-то модуле содержатся подпрограммы, к которым вам часто приходится обращаться, имеет смысл поместить этот модуль в библиотеку TURBO.TPL, чтобы облегчить к нему доступ. Почему бы не поместить сюда все имеющиеся модули? Дело в том, что память компьютера ограничена и поэтому в TURBO.TPL следует содержать только те модули, к ресурсам которых вам часто приходится обращаться.
22 Не следует путать автоматическое подключение модуля к программе и автоматическую загрузку модулей в память. К программе автоматически подключа-етпся единственный модуль — SYSTEM. В память автоматически загружаются все модули, содержащиеся в библиотеке TURBO.TPL.
Глава 8. Модули	203
У внимательного читателя к этому моменту неизбежно должны были возникнуть два вопроса.
1. Как добавлять модули в TURBO.TPL и удалять их оттуда? (Этот же вопрос можно отнести и к любой другой библиотеке модулей.)
2. Как создать новую библиотеку модулей?
Ответить на эти вопросы поможет входящая в состав Turbo Pascal 7.Q утилита TPUMOVER23, с которой мы познакомимся в следующем разделе.
Утилита TPUMOVER
Итак, мы уже выяснили, для чего эта утилита: для добавления модулей в библиотеки и изъятия их оттуда. Содержится TPUMOVER (файл TPUMOVER.EXE) в каталоге BIN — одном из каталогов, которые создаются на диске при инсталляции Turbo Pascal 7.0. Если запустить этот файл, появится окно сеанса MS DOS (рис. 8.4).
TTPU Mover Version ?.fl Copyright (c) 4992 Borland International
Syntax: TPUMOVER filename operations
(Where filename is a library file nene (default extension -TPL) and lopcrations is an optional list one or more of the following cnr-mands:
; •<unitname	fidd a unit to the library.	j i
-unitname Delete a unit from the library.
»unitname Extract a unit from the library.
If no operations are specified, TPUMOVER outputs a list of the units |in the library file.
Puc. 8.4. Утилита TPUMOVER
Что значат все эти сообщения? Верхняя строка — информация о номере версйи утилиты, авторских правах и фирме-изготовителе. А остальное имеет следующий смысл:
Синтаксис: TPUMOVER имя_файла операция
Где имя_файла - файловое имя библиотеки (расширение .TPL), а операция - необязательный перечень, включающий одну или несколько следующих команд:
+unitname - добавление модуля в библиотеку24
-unitname - удаление модуля из библиотеки
23 Слово TPUMOVER составное. Его образуют аббревиатура TPU (расширение файла с модулем) и слово MOVER (оно здесь имеет смысл средство перемещения j-
24 UNITNAME здесь — имя файла с модулем.
204
Turbo Pascal: учитесь программировать
*unitname - извлечение модуля из библиотеки
Если операция не указана, TPUMOVER выводит на экран перечень модулей, содержащихся в указанном файле библиотеки.
Все это в особых объяснениях не нуждается. Только необходимо выяснить, в чем разница между удалением и извлечением модуля из библиотеки. Так вот. при извлечении модуля этот модуль изымается из библиотеки и одновременно воссоздается в качестве самостоятельного TPU-файла. А при удалении модуля модуль изымается из библиотеки без оздания самостоятельного TPU-файла.
Выше указывалось, что в TURBO.TPL содержатся пять стандартных модулей. Теперь мы имеем возможность проверить, так ли это. Для этого (перейдя предварительно в каталог BIN) достаточно задать следую-,пую командную строку:
tpumover turbo
Как выглядит соответствующая информация, выведенная на экран, демонстрирует рис. 8.5.
TI'U Номер
Un it System Overlay Crt Dos
:Pr inter
Uersion 7.0 Copyright (cl 1923 Borland International
Code	Data	Uses
22794	702
1B59	26	Systen
1S67	2D	System
1591	6	Systen
S4	256	Systen
Puc. 8.5. Все так. как и ожидалось
Действительно, на экран выводится таблица, в первом столбце кото-ой содержатся имена пяти модулей: SYSTEM, OVERLAY, CRT, DOS и RINTER. Цифры во втором и третьем столбцах таблицы тоже что-то начат (нам сейчас не важно, что именно), а в четвертом столбце содержится информация о том, к каким модулям обращается данный модуль, аблица на экране информирует, что модуль SYSTEM обходится своими шами (т.е. не обращается ни к одному другому модулю), а остальные 1етыре модуля обращаются к модулю SYSTEM.
О TPUMOVER осталось еще только выяснить, как с ее помощью можно создать новую библиотеку модулей. Это просто— достаточно в командной строке ввести название утилиты (TPUMOVER), имя создаваемой библиотеки (которой в данный момент на диске еще нет) и команду, инициирующую добавление в новую библиотеку нужного модуля
лава 8. Модули	205
(например, +GRAPH). Для того чтобы упростить задачу, предваритель-следует перейти в каталог BIN. Поскольку утилита TPUMOVER находи ся в этом каталоге, ее имя в этом случае можно задать без указания п\ ти. Если нужно, чтобы новая библиотека была создана не в BIN, а в ипо каталоге, вместе с ее именем следует задать и путь. Аналогично, имя д< бавляемого модуля также должен дополнять путь (файлы модуле обычно содержатся в каталоге UNITS).
В заключение разговора о библиотеках модулей, осталось сказат! что в Turbo Pascal, к сожалению, не предусмотрено подключение к пр грамме библиотек. Вам не удастся после зарезервированного слов USES указать имя файла библиотеки модулей (у которого расширение .TPL) с тем, чтобы все содержащиеся в нем модули одним махом оказа лись подключены к программе.
Другие утилиты
Помимо TPUMOVER. в составе Turbo Pascal имеются утилить TOUCH, GREP. BINOBJ и МАКЕ. Правда, не все они предназначены дл: работы с модулями, однако более удобного места, чтобы рассказать с них, пожалуй, не будет. Вот краткая информация об этих утилитах.
TOUCH. Бывают случаи, когда TPU-файл модуля необходимо пере компилировать, даже если в исходный код не были внесены никаки изменения. Один из способов сделать это — воспользоваться утилите TOUCH. Эта утилита перекомпилирует модуль и присвоит ему новук дату создания, делая его более “свежим”.
GREP. Эта утилита (файл GREEP.EXE) позволяет осуществить поис-строки текста (например, заголовка какой-нибудь функции или имею процедуры) сразу в группе файлов (с исходным кодом).
BINOBJ. Эта утилита (файл BINOBJ.EXE) позволяет конвертировав любой файл в файл .OBJ. Это предоставляет возможность использоват. такой файл в программе на Turbo Pascal в качестве “процедуры”.
МАКЕ (файл MAKE.EXE). Предназначена для работы с формируя щи ми файлами (makefile).
Все .ЕХЕ-файлы упомянутых утилит находятся в каталоге BIN. Более подробную информацию об утилитах Turbo Pascal (к сожалению, на анг лийском языке) вы найдете в файле UTILS.DOC, который содержится в каталоге DOC.
Описани- (гю-русски) утилит, поставляемых с Turbc Pascal 7.0 (TPUMOVER- MAKE, TOUCH, CREP и BINOBJ] вы найдете в Internet по адресу http://study.tsu.tirn.г /homepages/invorobyeva/Pascal/Utilits.htm.
Примечание
206
Turbo Pascal: учитесь программировс
глава 9
Использование ресурсов модуля DOS
В этой главе...
	Обслуживание прерываний
	Дата и время
	Статус диска
	Обработка файлов
	Обработка процессов
	Управление средой
	Дополнительные средства
Средства модуля DOS предоставляют доступ к возможностям опер; ционной системы. Иными словами, такое имя для данного модуля вы брано не случайно. Содержащиеся здесь процедуры и функции значи тельно расширяют возможности стандартного Pascal.
Обслуживание прерываний
Прерывание — это некоторое событие, в результате которого приостанавливается вычислительный процесс и управление передается спе циальному средству MS DOS, известному как процедура обработки пре рывания. Действия, вызывающие прерывания, могут исходить как от внешних устройств компьютера, так и программ, нуждающихся вс “внимании” процессора.
Средства работы с прерываниями, имеющиеся в модуле DOS, можн разделить на две категории:
	процедуры (Intr и MsDos), позволяющие инициировать из программы определенное прерывание (если в создаваемую програм му включить одну из этих процедур, будет инициировано преры вание, указанное как параметр процедуры):
	процедуры (SetlntVec и GetlntVec), предоставляющие воэмож ность задать свою процедуру обработки, которая бы нужным об разом реагировала на указанное прерывание.
Вызов прерывания
Читатель уже обратил внимание на огромное количество процедур г функций, содержащихся в нескольких модулях, прилагаемых к Turb< Pascal 7.0. В действительности существует множество других модулег не входящих в комплект поставки Turbo Pascal 7.0, но вполне пригод пых к использованию, найти которые можно, например, в Internet. Е этих “неофициальных” модулях также содержатся множество процедур и функций. Тем не менее для каиодого случая невозможно предусмотрет специальную црдпрограмму. Конечно, при необходимости можно по пробовать создать свою процедуру или функцию, однако не всегда уда стся ее реализовать исключительно средствами Turbo Pascal. Предпо ложим, в программе необходимо использовать текущие дату и время, соответствующих процедур (GetDate и GetTime из модуля DOS) не суще ствует. Используя же операторы Turbo Pascal или другие процедуры функции, этой задачи не решишь. Где же выход? Выход— в использо
208
Turbo Pascal: учитесь программироват
зании прерываний MS DOS (в частности, прерывания $2125 26, позволяющего обратиться к функциям операционной системы). Кстати, две упомянутые выше процедуры, а также множество других реализованы как раз таким образом.
Итак, с помощью процедуры Intr или MsDos вызывается определенное прерывание, процедура обработки которого инициирует нужное действие или предоставляет нужную информацию. Найти информацию по тому или иному прерыванию MS DOS или BIOS можно в соответст-ующей литературе, либо в Internet, например, по адресу http://codenet.al.ru/progr/dos/int_0026.htm(рис. 9.1).
Рис. 9.1. Перечень прерываний (здесь h26— от “hexadecimal”
( шестнадцатеричный))
Наиболее “популярным” из прерываний MS DOS является $21, предоставляющее доступ ко множеству функций операционной системы.
25Так л<ы будем обозначать шестнадцатеричные числа (чтобы отличать их от десятичных). Кстати, именно в этом виде номер прерывания или функции задается в тексте программы
26 Здесь таким образом указываются прерывания (и функции — на следующем рис.). Так, если в тексте главы речь идет о прерывании $21, на этой Web-транице (и, возможно, в некоторых иных источниках) соответствующая ссылка обозначена как 21 Л.
лава 9. Использование ресурсов модуля DOS	209
Если здесь щелкнуть на ссылке одного из прерываний, отобразит страница с перечнем функций этого прерывания (рис. 9.2).
Рис. 9.2. Перечень всех функций прерывания $21 (всего85)
Теперь, для того чтобы получить информацию по той иль иног функции, достаточно щелкнуть на ссылке с ее номером.
При вызове программного прерывания обычно требуется передатт процедуре его обработки некоторые конкретизирующие данные. Кром< того, часто результатом прерывания является некоторая выходная ин формация. Двусторонний обмен информацией между программой и процедурой обработки прерывания осуществляется через регистры центрального процессора. Регистр— это внутреннее запоминающее устройство процессора, предназначенное для временного хранения управляющей или обрабатываемой информации. Для того чтобы облегчить этот обмен, в модуле DOS определен специальный тип Registers Вот как выглядит описание этого типа:
type
Registers = record
case Integer of
0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Word);
1: (AL, AH, BL, BH, CL, CH, DL, DH: Byte);
end;
210
Turbo Pascal: учитесь программирован
ке упоминалось, что для организации программных прерываний в urbo Pascal предусмотрены процедуры Intr и MsDos. Рассмотрим их о дробнее.
Процедура Intr
Инициирует определенное (любое) программное прерывание.
Заголовок процедуры:
Procedure Intr(IntNo : Byte; Var Regs : Registers);
где IntNo — номер программного прерывания (О..255);
Regs— значение, принадлежащее типу Registers, определенному в 'Дуле DOS (см. выше).
Программа, в которой используется процедура Intr, содержится в римере 9.1 (рис. 9.3).
rnet
Пример 9.1
rile’ Edit Eesrov. TurCercile Tebug TocIf	Wir.dow-' 4*1p-	“
: —------------\MOH£CK~l\PASCAL\nPOrpA-.l\CH2_6A~l\INlR.PAS--------1-----.
Program In_tr,
Uses Dos;	i
var rime, Hrjr, Min, Sec	: String;	I
Regs : Registers;	i
Begin
Regs.AH:=I2C, {Задание функции DOS 2C {Выдача нр-’мени)]	i
Tntr(S21, RegsJ;	i
i Wi th Reg^ Do	i
Begin
Str (CH, Hou-),
Str (CL, Min);	!
Str(DH, Sec);	j
El id;
Time: =Ночг+': -+Min+‘: ‘+'>c;
Wr1teLn('Время : ', Time), End.	।
f—[]	Output	.......—-"2-П)-ч
: 16:33:19	{
iБоеия : 16:33:7'
Cl Heap Scroll F1Q йеплаИМИИИИИИИИИИИИШИИМИИИ»ИИИИВ|
Рис. 9.3. Так можно выяснить у операционной системы текущее время
В этой программе для получения данных о времени используется > OS-функция $2С прерывания $21. (Для того чтобы выполнить то или иное действие, запрограммированное в операционной системе, необхо-(имо обратиться к данному прерыванию, задав при этом номер требуе-лой функции в регистре АН.) Обращение к нужным прерыванию и зункции, а также выборка нужной информации осуществляются с помощью процедуры Intr. Результат работы программы демонстрирует кио Output, (см. рис. 9.3). Здесь видно, что программа запускалась дважды — с интервалом в 4 с.
лава 9. Использование ресурсов модуля DOS
211
Текст программы свидетельствует, что при обращении к функцщ $2С прерывания $21 информация о часах (Hour), минутах (Min) и секут дах (Sec) заносится соответственно в регистры CH, CL и DH. Но откуда автор программы может знать, из каких регистров следует брать ну» ную информацию при обращении к той или иной функции определенного прерывания? Хороший вопрос! Ответ можно, конечно, поискать в литературе, однако проще всего получить его экспериментальным пу тем — как ответы на многие другие вопросы, связанные с Turbo Pascal Для этого в нашей программе после строк
With Regs Do
Begin
достаточно вставить (временно) два дополнительных оператора:
WriteLn(AX, ' ВХ, ' СХ, ' DX, ' ', ВР, ' SI, ' DI, ' DS, ' ’, ES, ' ', Flags);
WriteLn(AL, ' АН, ' BL, ' ', ВН, ' ', CL, ' ', CH, ' ', DL, ' DH);
Эти операторы выводят на экран содержимое переменной Regs (т содержимое регистров процессора — см. выше) с пробелами в качест: разделителей. Для нашей программы (которая выясняет у операции. ной системы текущее время) то, что выведут на экран эти два оператор может выглядеть так:
11264 0 2610 9269 00000 29318
0 44 0 0 33 16 53 21
Теперь, зная текущее время (если вы используете Windows, оно ото бражается в правом нижнем углу экрана; если вы используете MS DOS. чтобы получить нужную информацию, достаточно ввести команду Time), нетрудно определить, в каких регистрах содержатся часы минуты и секунды. (Читатель может сравнить данные о времени на рис. 9.3 с представленным выше содержимым регистров.) Кроме того, этот прием позволяет составить впечатление о разрядности того или иного регистра.
Следует подчеркнуть, что два оператора WriteLn добавляются в текст программы временно. После того как выяснится, какие регистры нас интересуют, эти операторы несложно будет удалить.
И еще одна возможность получить нужную информацию. Те, кто не любит экспериментировать, но у кого есть доступ к Internet, могут обратиться по аДресу, о котором шла речь выше (см. рис. 9.2). Если на этой Web-странице щелкнуть на ссылке, соответствующей нужной функции (пусть это будет все та же функция $2С), на экране отобразится страница с информацией о данной функции (рис. 9.4).
Здесь представлена информация, которую мы только что выяснили экспериментальным путем, только более полная. Например, оказывается, можно было бы задать вывод на экран даже сотых долей секунды!
212
Turbo Pascal: учитесь программирова
Рис. 9.4. Знакомая нам информация
Процедура MsDos
Выполняет вызов одной из функций MS DOS прерывания $21. Об-ащение к процедуре MsDos эквивалентно обращению к процедуре Intr с ираметром IntNo, равным $21.
Заголовок процедуры:
Procedure MsDos(Var Regs : Registers);
Факт, что для этого прерывания предусмотрена специальная проце-iypa, объясняется важностью и частотой обращения к функциям прерывания $21. Программа, в которой используется процедура MsDos. редставлена в примере 9.2 (рис. 9.5).
В этой программе для получения данных о версии операционной системы используется DOS-функция $30 прерывания $21. Номер >ункции передается через регистр АН. Результат работы программы д монстрирует окно Output (см. рис. 9.5).
Как и с информацией о текущем времени, для того чтобы выяснить, из каких регистров следует осуществлять выборку данных о версии опе-ационной системы, в текст программы можно добавить два оператора WriteLn. Затем, зная версию MS DOS, под управлением которой работа-г ваш компьютер (т.е. компьютер, на котором создается программа).
лава 9. Использование ресурсов модуля DOS
213
несложно выяснить регистры процессора, в которые при обращении DOS-функции $30 прерывания $21 заносится информация о номе версии операционной системы и о номере ее модификации. Впоследс вии при использовании данной программы (той, которая сейчас созд ется) на различных компьютерах, независимо от версии операционно системы, эта программа получит (и выдаст на экран) соответствую!!-достоверную информацию.
? Пример 9.2
Рис. 9.5. Выяснить номер версии операционной системы не сложнее, чем узнать время
Как задать иную процедуру обработки прерывания
Как уже отмечалось, компьютер в значительной степени управляется прерываниями, генерируемыми аппаратурой или программны!, обеспечением. Когда имеет место прерывание, управление передаете! процедуре его, обработки, которая вызывается с помощью ее сегментного адреса. Сегментные адреса, определяющие местоположение процедур обработки прерываний, называются векторами прерываний.
Для каждого прерывания имеется своя процедура обработки (стандартная), для вызова которой используется соответствующий вектор прерывания. Однако ничто не мешает для какого-либо прерывания создать оригинальную (или “нестандартную”) процедуру обработки, которая бы нужным вам образом реагировала на данное прерывание. I
214
Turbo Pascal: учитесь программировав
ЭТОМ случае сначала создается соответствующая подпрограмма, которая записывается в память, а затем вектор прерывания, указывающий {1а стандартную процедуру обработки данного прерывания, изменяется таким образом, чтобы указывать на новую процедуру, созданную пользователем. Указать иную процедуру обработки позволяет процедура SetlntVec (первым параметром которой является номер прерывания, а вторым — адрес процедуры обработки прерывания, т.е. вектор).
Однако при выходе из программы старый вектор прерывания, естественно. необходимо восстановить, чтобы освободить память, предоставленную для процедуры обработки прерывания. Для решения этой проблемы перед установкой нового вектора прерывания необходимо сохранить старый вектор, присвоив его в качестве значения некоторой заранее зарезервированной переменной. Для этого в Turbo Pascal существует процедура GetlntVec.
Процедура SetlntVec
Устанавливает для данного прерывания указанный вектор.
Заголовок процедуры:
Procedure SetlntVec(IntNo : Byte; Vector : Pointer);
где IntNo — номер прерывания (О..255);
Vector — новый вектор.
Параметр Vector обычно создается с помощью оператора @ и указывает на процедуру обработки прерывания. Пусть IntlBOld— переменная указательного типа, a IntlBNew— идентификатор процедуры обработки прерывания. Тогда первые два оператора задают новую процедуру обработки, а третий — восстанавливает первоначальную процедуру:
GetlntVec ($1В, IntlBOld);
SetlntVec ($1В, glntlBNew);
SetlntVec ($1В, IntlBOld);
Процедура GetlntVec
Вектор заданного прерывания присваивается в качестве значения переменной указательного типа.
Заголовок процедуры:
Procedure GetlntVec(IntNo : Byte; Var Vector : Pointer);
где IntNo — параметр, определяющий номер прерывания (О..255);
Vector— переменная, которой в качестве значения присваивается Вектор прерывания.
Программа, в которой используются процедуры GetlntVec и S. t lntVec, содержится в примере 9.3 (рис. 9.6).
>ава 9. Использование ресурсов модуля DOS
215
Internet
Пример 9.3
Run Cowpile Qebuti too:.1s.,/ opt!ons window. HeIp '
|—[] '	------- \MOHflOK~l\PASCAL\nPOrPA^l\CH2_BA~l\GSINVEC.PAS	-1-1 I.
program GetSetlntVec;
uses dos;
procedure NewIntlC; interrupt;
begi n
Sound £1000};	•
Delay£50};
NoSound
end;
var SvIntlC: pointer;
begi n
GetIntVec($lC,SvIntlC}; £ соханение старого вектора ]
SetlntVecC11C,©NewIntlC}; [ новый вектор для прерывания 1С} readln;
£ звук продолжается пока не будет ввода с клавиатуры!
SetlntVecС$1С,SvIntlC} Г восстановление старого вектора 1
end.
I Г- -- 18:57   £*"*. ГЛ Г'Л'ТЛ'ЛЛГЛТ Л'Л J	ТЛ'Л'ЛТ,!гГТ'“я?ЛХ:^*Г
Я'^неШ' .: г save- > Э open Alit+FV.comprie ,'
Рис. 9.6. Задать для одного из прерываний оригинальную процедуру обрабо ки совсем несложно
В этой программе объявлена процедура NewIntlC, которая иниц рует подачу прерывистого сигнала на динамик компьютера. Поскол это процедура обработки прерывания, она начинается стандартной рективой INTERRUPT. Первый оператор в теле основной програм (GetIntVec($lC,SvIntlC);) обеспечивает сохранение старого векто) (чтобы его впоследствии можно было восстановить). Второй операт< (SetIntVec($lC,6NewIntlC);) устанавливает новый вектор, указывают* на процедуру обработки прерывания NewIntlC, которая инициируй звуковой сигнал. Далее следует процедура ReadLn, за ней — последш оператор программы (SetlntVec(§1С,SvIntlC);), восстанавливающий ст рый вектор.
Иными словами, после начала звукового сигнала и передачи упра ления оператору ReadLn звук продолжается до тех пор, пока что-нибу не будет введено с клавиатуры (для этого достаточно просто нажать к. вишу <Ctrl>). Только после этого управление передается последне оператору; который восстанавливает старый вектор и тем самым пр кращает звуковой сигнал.
Дата и время
Компьютер автоматически ведет календарь и отсчитывает время эта информация чрезвычайно полезна— например, в MS DOS дата со Дания и дата последнего изменения фиксируется для каждого файл
216
Turbo Pascal: учитесь программировг
касается Turbo Pascal, то этот язык программирования предлагает лодуле DOS) восемь процедур, предназначенных для работы с датой и менем. Эти средства можно условно разделить на две категории:  предназначенные для работы с системными датой и временем
(т.е. временной информацией, поддерживаемой операционной системой);
 предназначенные для установки и получения сведений о дате и времени последнего изменения определенного файла.
Системные дата и время
ассматриваемые здесь процедуры позволяют манипулировать сче-дней и времени, производимых компьютером автоматически (даже яключенном состоянии).
Процедура GetDate
Возвращает текущую дату, которая поддерживается операционной темой. Заголовок процедуры:
Procedure GetDate(var Year, Month, Day, DayOfWeek: Word);
где Year — год (допустимые значения 1980..2099);
Month — месяц (1.. 12);
Day — день (1..31);
DayOfWeek — день недели (0..6); неделя начинается с воскресенья.
Пример использования процедуры GetDate имеется в разделе ооцедура SetTime”.
Процедура GetTime
Возвращает текущее время, поддерживаемое операционной систе-й. Заголовок процедуры:
Procedure GetTime(var Hour, Minute, Second, SeclOO: Word);
где Hour — часы (0..23);
Minute — минуты (0..59);
Second — секунды (0.. 59);
SeclOO — сотые доли секунды (0..99).
11ример использования процедуры GetTime имеется в разделе цедура SetTime”.
Процедура SetDate
Останавливает для операционной системы текущую дату. Заголовок цедуры:
’rocedure SetDate (Year, Montn, Day,: Word);
ia 9. Использование ресурсов модуля DOS
217
где Year — год (1980..2099);
Month — месяц (1.. 12);
Day — день (1..31).
Пример использования процедуры SetDate приведен в раздел “Процедура SetTime”.
Процедура SetTime
Устанавливает для операционной системы текущее время. Заголовс процедуры:
Procedure SetTime(Hour, Minute, Second, Seel00: word);
где Hour — часы (0..23);
Minute — минуты (0..59);
Second — секунды (0..59);
SeclOO — сотые доли секунды (О..99).
В заключение приведем пример программы, в которой используют^ все четыре процедуры, о которых шла речь выше. Программа содержит ся в примере 9.4 (рис. 9.7).
nternet
Пример 9.4
-——------------- \МОИДОК-J \PASCAL\ПРОГРA~1 \CM2_8A-1 \DAYTIME.PAS
program DayAndTime; Uses Dos;
Const Days : Array [0..6] Of Strina[ll] =
С* Воскресенье', °Понедельник',г6торнии', ’Среда “
"Четверг', 'Пятница ','Суббота’);
Var Y, М, Dj DoW : Word;
Hour, Minute, Second, SeclOO: Word; Begi n { Устанавливаем системную дату на 13-0 SetDate[2001, 2, 13);
{ Устанавливаем системное время на 11: SetTime(11, 01, 0, 0);
GetDate(Y, М, Dj DoW);
GetTime(Hour, Minute, Second, SeclOO);
Wri teLnCСегодня :	Days [Dow]
Wri teLn(* Сейчас : '.Hour.':', Minute End.
горник, 2-13-2001 59:99
Second
Y); SeclOO).
Рис. 9.7. Устанавливаем и получаем системные дату и время
В этой программе сначала (с помощью процедур SetDate и SetTii устанавливаются определенные дата и время (соответствующая инфо^ мация задается прямо в тексте программы). Затем осуществляется i борка (только что установленных) системных даты и времени (с пом< гцью процедур GetDate и GetTime). Наконец, полученная информация удобном формате выводится на экран. Как выглядит вывод на экр? демонстрирует окно Output.
218
Turbo Pascal: учитесь программировс
Ничто не мешает читателю здесь поэкспериментировать, задавая , обственные дату и время.
Дата и время изменения файла
Представленные здесь процедуры предназначены для манипулиро-апия датой и временем последнего изменения файла. Эта информация чксируется операционной системой для всех файлов.
Процедура GetFTime
Возвращает дату и время последнего изменения файла. Заголовок роцедуры:
Procedure GetFTime(var f; var time: longint);
где F— файловая переменная любого типа (типизированная, нети-изированная, текстовая);
Time — дата и время в упакованном формате.
Для распаковки значения Time может использоваться процедура г ipackTime.
Пример использования процедуры GetFTime имеется в разделе Троцедура PackTime”.
Процедура UnpackTime
Преобразует упакованные дату и время, представленные в виде зна-кт1ия Longlnt (возвращенное процедурами GetFTime, FindFirst или indNext), в неупакованную запись типа DateTime. (О процедурах ndFirst и FindNext речь пойдет в разделе “Обработка файлов”.)
Заголовок процедуры:
Procedure UnpackTime(Time : Longint; Var T : DateTime);
где T — переменная типа DateTime;
Time — переменная типа Longlnt.
Пример использования процедуры UnpackTime смотри в разделе ' 1роцедура PackTime”.
Процедура SetFTime
Устанавливает для файла дату и время его последнего изменения, тыми словами, любой файл таким образом можно искусственно сде-тть более “свежим”, не внося при этом в него никаких изменений.
Заголовок процедуры:
Procedure GetFTime(var f; var time: longint);
где F— файловая переменная любого типа;
Time — дата и время в упакованном формате.
ава 9. Использование ресурсов модуля DOS
219
Для формирования значения Time может использовался процедура PackTime.
Пример использования процедуры SetFTime имеется в разделе “Процедура PackTime”.
Процедура PackTime
Преобразует запись типа DateTime в 4-байтовое значение типа Longlnt. содержащее дату и время. Заголовок процедуры.
Procedure PackTime(var t : DateTime; var time : longint);
где T — переменная типа DateTime;
Time — переменная типа Longlnt.
Тип DateTime (объявленный в модуле DOS) имеет вид:
type
DateTime = record
Year, Month, Day, Hour, Min, Sec : integer;
end;
Поля в записи DateTime не проверяются на принадлежность допустимому диапазону значений.
Процедура PackTime используется процедурами SetbTime и GetFTime.
В заключение приведем пример программы, в которой используются процедуры SetFTime, GetFTime, PackTime и UnPackTime. 11рограмма содержится в примере 9.5 (рис. 9.8).
L
nternet
Пример 9.5
pi le Edit—Search^Rum-compile DebuqTools______options, .window Help
---------------- .МОКДОЛ"!	ПР1;Г	F ' -1 Program SetGetFTime;  Us es Dos i 1 Var
F : Text
Longi nt;
( Dt : Dat Begin
I A : s i gn (F
i	Dt.rear:=2002;
1 Dt.Month:=02;
'	Dt.Oay:=23;
1 PackTimeCot, Prime};
; SetFTimeCr, FTirne};
! WriteLnC'Установлена дата:', Dt Day '/' with ot do begin Year:=0; Month: =0-’ Dav writeLnf'Дата сброшена:	', Dt Dav ' /'
, GetFTirnefF, FTirne}; f	'
UnpackTimeCFTime, Dt};
WriteLnf'Файл изменен ' end.
, Dt.Month,'/', Dt.Yearl;
•:-0 end;
, Dt.Month,'/1, Dt.Year}; ния J
, Dt Day,'/', Dt.Month,'/', Dt.Year);
Meip ll ’< scroll f 1 j Menu

присвоить	его
220
Turbo Pascal: учитесь прогроммиг *
В згой upoi рамме создается фаил TEST тхт о	v
thIIi>ay .описи DataTime ПРиХ “ [гST TXT- Зат™ полям Yea р11Пя года, месяца и дня. а затем ™ некоторые произвола iinonenvDw Set кт- i м эти Данные в качестве атрибутов [с поМ01111’1 ..Лкотопым бвтп 1те пРисваиваются файлу TEST.TXT. Поел fOfO ,,<и • „ то	и пРисв°ены значения, обнуляются (чтобы
geciK’ч,7’’У1иествляетест1е₽ИМеНТа	11аконеЧ. с помощью процедуры
BetF'l*nl< * У	. „ получение даты последнего изменения файл.
.jara. ПР»‘ воеш файлу, и полученная дата выводятся на экран дла рапне1”1Я )ги Данные можно видеть в окне Output (см. рис. 9.8).
д.чя краткости программа манипулирует только датой. Однако ничт не мешает таким же образом трансформировать и время последнего из ненения файла.
Статус диска
Здесь мы рассмотрим две функции, возвращающие такую полезную информацию, как общий объем и объем свободного пространства на за щнпом диске.
Функция DiskFree
Возвращает число байтов, свободных на заданном диске.
Заголовок функции:
Function DiskFree(Drive : Byte) : Longint;
r te Drive— диск, информацию о котором возвращает функция. Вот а кой смысл имеет числовое значение этого параметра:
О — текущий диск
1	—дискА
2	— диск В
3	— диск С
ЕсдГи фикцию вызвать с недопустимым значением Drive, будет воз ращено значение —1 -
Пример использования функции DbkFree имеется в следующем раз
Функция DiskSize
Возвращает общее число байтов на заданном ди< ке. Запыовок функции
Function DiskSize(Drive: Byte): Longint;
Парамелр Drive здесь имеет те ясе смысл и значения, чгч и для пре 'Идущей функции
глава 9- Использовапйо ресурсов модуля DOS
221
Как и с DiskFree, если для параметра Drive задать некорректное зн чение, функция вернет значение, равное -1.
Рассмотрим пример программы, в которой используются функц DiskSize и DiskFree. Программа содержится в примере 9.6 (рис. 9.9).
Пример 9.6
Program DiskSizeFree;
Uses Dos;
var a,b:)ongint;
Begi n
a:=DiskSize<l) Div 1024;
b:=DiskFreeCl) Div 1024;
WriteLn(/Общий объем диска: ', a, ' кбайт. '!;
WriteLnС Свободно на диске:	Ь, ’ кбайт.');
WriteLnC Занято на диске:	а-b, ' кбайт.');
Wri teLn
End.
—[]-------------------------------- Output-------------------------------
Общий ?6ъем диска: 1423 кбайт.
Свободно на диске: 1018 кбайт.
Занято на диске: 405 кбайт.
Рис. 9.9. Информация о диске
Данная программа выясняет и выводит на экран информацию о дис ке А (дискете).
Обработка файлов
Процедуры и функции этой категории (пять и две соответственн< предназначены для поиска файлов, а также для работы с файловым! именами и атрибутами.
Процедура FindFirst
Ищет в указанном (по умолчанию— текущем) каталоге первый встречный файл, имя и набор атрибутов которого соответствуют заданным.
Заголовок процедуры:
Procedure FindFirst(Path : string; Attr : Word; Var F : SearchRec);
где Path — путь и имя файла; если путь не задан, поиск осуществляет ся в текущем каталоге; имя файла может быть указано в виде шаблона;
Attr— константа атрибута файла; перечень констант приведен I табл. 9.1.
222
Turbo Pascal: учитесь программировать
аблица 9.1. Перечень констант атрибута файла
Имя константы	Код	Смысл
Readonly	$01	Только для чтения
Hidden	$02	Скрытый файл
SysFile	$04	Системный файл
VolumelD	$08	Заголовок тома
Directory	$10	Каталог
Archive	$20	Архивный файл
AnyFile	$3F	Любой файл
F— значение, возвращаемое функцией (информация по найденному >айлу) и принадлежащее типу SearchRec. Описание типа SearchRec который объявлен в модуле DOS) выглядит так:
Туре
SearchRec = Record
Fill	:	Array (1..21)	Of	Byte;
Attr	:	Byte;
Time	:	Longint;
Size	:	Longint;
Name	:	Array [0..12]	Of	Char;
End;
Здесь Fill— параметр, зарезервированный за MS DOS, который не шжен изменяться;
Attr— содержит атрибут файла (см. табл. 9.1 выше); это значение овторяет одноименный параметр, заданный при обращении к проце-уре;
Time — содержит (в упакованном виде) дату и время последнего изменения (для распаковки можно воспользоваться процедурой npackTime);
Size — размер файла в байтах;
Name — имя файла.
Пример использования процедуры FindFirst имеется в следующем >азделе.
Процедура FindNext
Находит следующий файл, имя и набор атрибутов которого совпадает с соответствующими характеристикам первого файла, найденного до > того с помощью процедуры FindFirst.
Заголовок процедуры:
Procedure FindNext(Var F : TSearchRec);
где F — значение, сообщаемое функции в виде параметра, и принад-1(>кащее типу SearchRec.
лава 9, Использование ресурсов модуля DOS
223
Когда в указанном каталоге найден последний файл, переменно] DosError, определенной в модуле DOS, присваивается значение 18. Этс обстоятельство можно использовать как условие прекращения поиска.
В заключение приведем пример программы, в которой используются процедуры FindFirst и FindNext, а также переменная DosError. Про грамма содержится в примере 9.7 (рис. 9.10).
Пример 9.7
Internet
Рис. 9.10. Нужные файлы найдены
В этой программе осуществляется поиск файлов с именем TURBO (и с любым расширением) в текущем каталоге (т.е. в BIN). Первый файл ищется с помощью процедуры FindFirst, а затем для поиска остальных файлов организуется цикл, в котором, помимо прочего, вызываете], процедура FindNext. Тело цикла выполняется, пока переменная DosError не принимает значение 18, т.е., пока не будет найден последний файл, отвечающий условиям поиска.
Процедура GetFAttr
Возвращает атрибуты файла.
Заголовок процедуры:
Procedure GetFAttr(Var F; Var Attr : Word);
где F файловая переменная, представляющая типизированный, не-типизированныи или текстовый файл, который не должен быть открыт,
Attr возвращаемое процедурой значение, имеющее тот же смысл, что и для процедуры FindFirst (см. табл. 9.1).
Пример использования процедуры GetFAttr имеется в следующем разделе.
224
Turbo Pascal: учитесь программировать
Процедура SetFAttr
Устанавливает атрибуты файла. Файл, к которому применяется про-(едура SetFAttr, не должен быть открыт.
Заголовок процедуры:
Procedure SetFAttr(Var F; Attr : Word);
где F и Attr — параметры, смысл которых тот же, что и у предыдущей процедуры.
Если при вызове процедуры задан некорректный путь к файлу, пе-«еменной DosError присваивается значение 3. Если доступ к указанно-iy файлу закрыт, переменной DosError присваивается значение 5.
Программу, в которой используются процедуры SetFAttr и GetFAttr, а акже переменная DosError, можно видеть в примере 9.8 (рис. 9.11).
Пример 9.8
1	'Tompile ’ .Debug Tests;- ,cpti4>ns ' window,	"
...... ——— \МОИДOK-1 \P A5CAL \ЯРОГР A~1\CH2_8 A~1 \GSATTR . P AS ------2•------
program GetSetAttr;
Uses Dos;
Var F : File;
Attr : Word;
Begi n.
i AssignCF, 'a.pas'};
i SetFAttr(F, Hidden); {.УстаноБКа атрибута}
I GetFAttr(F, Attr); (Получение атрибута}
t If DosError <> 0 Then WriteLnC Код ошибки DOS = DosError) Else
! Begin
|	WriteС Значение атибута: *, Attr);
case Attr of
1: WriteLnC Столько для чтения)');
2 : wri tei_n С' Сскытый) ' );
4: Wri teLnC (Системный)‘;
8: WriteLnC (ID тома)');
10: WriteLnC’ (Имя каталога)');
32: WriteLnC' (Ахивный)'); end	р^[и]-,гтг-,	,	.	Output =
End;	IЗначение атибута; 2 (Сбытый)
! End.	______________
.. A,. „	„ 	... ,
Puc. 9.11. Установка и получение атрибута файла
В этой программе для файла A.PAS (файл с программой, которая выводит на экран слово “Hello”) с помощью процедуры SetFAttr устанавливается атрибут Hidden (скрытый). Затем с помощью процедуры GetFAttr осуществляется выборка атрибута этого файла, чтобы убедиться, что он < овпадает с атрибутом, установленным только что. Читатели могут поэкспериментировать, задавая в программе разные файлы (не обязательно из текущего каталога) и присваивая им различные атрибуты.
Процедура FSplit
Разделяет имя файла на три компонента. Процедуре предоставляется гуть к файлу с указанием диска, цепочки каталогов и имени файла.
глава 9. Использование ресурсов модуля DOS	225
*-2016
Процедура возвращает каталог (т.е. путь без имени файла), имя файла и расширение имени.
Заголовок процедуры:
Procedure Fsplit (Path : PathStr; Var Dir : DirStr;
Var Name : NameStr; Var Ext : ExtStr);
где Path — путь (значение, принадлежащее типу PathStr);
Dir — каталог (значение, принадлежащее типу DirStr);
Name — имя файла (значение, принадлежащее типу NameStr);
Ext — расширение (значение, принадлежащее типу ExtStr).
Типы PathStr, DirStr, NameStr и ExtStr определены в модуле DOS: type
PathStr	=	string[79];
DirStr	=	string[67];
NameStr	=	string[8];
ExtStr	=	string[4J;
Примечание
Расширение имени файла возвращается с предшествующей точкой.
Пример программы, в которой используются процедура FSplit, имеется в разделе "Функция FSearch”.
Функция FExpand
Расширяет имя файла, переданное функции как параметр Name, до полного. Возникающее в результате имя представляется символами верхнего регистра и состоит из символа дисковода с двоеточием, пути к каталогу и имени файла. При этом все ссылки '.' и '..' удаляются и все компоненты имен и расширений сокращаются до 8-и и 3-х символов соответственно. Полученное полное имя файла возвращается функцией.
Заголовок функции:
Function FExpand (Name : PathStr) : PathStr;	,
Тип PathStr определен в модуле DOS.
Пусть текущим будет каталог C:\TP7\BIN. тогда следующие обращения к FExpand вернут такие значения:
FExpand('a,pas') = ' C:\TP7\BIN\A.PAS'
FExpand('..\*.TPU') = ' C:\TP7\*.TPU'
FExpand('с:\autoexec.bat') = 'С:\AUTOEXEC.BAT'
Иными словами, если в качестве параметра функции FExpand не задан полный путь, к указанному имени файла добавляется путь к текущему катало1у и результат представляется символами верхнего регистра. Если в качестве параметра задан полный путь, этот путь функция возвращает символами верхнего регистра. Во втором примере заданный путь предварен двумя точками. По правилам MS DOS это обязыва-
226
Turbo Pascal: учитесь программироваг
т перейти в родительский каталог (т.е. на один уровень выше). Результат соответствует этому.
Для того чтобы разделить результат функции FExpand на обозначе-'ие диска, цепочку каталогов и имя файла, можно воспользоваться функцией FSplit.
Пример программы, в которой используется функция FExpand, име-тся в следующем разделе.
Функция FSearch
Ищет файл в списке каталогов DirList. Каталоги в DirList должны ыть разделены точками с запятой. Однако можно указать старший каталог, так чтобы все каталоги, в которых требуется осуществить поиск, жазались в него вложенными. Проще всего вместо перечня каталогов казать корневой каталог диска, на котором находится искомый файл. Гапример: 'С:'. Однако при этом нужно быть готовым, что при запуске оздаваемой программы на медленных компьютерах поиск займет некоторое время. Кроме того, если имя файла тривиально, при таком под-.оде перечень найденных файлов может оказаться чересчур обширным.
Заголовок функции:
Function FSearch(Name : PathStr, DirList : String) : PathStr;
где Name — имя файла (значение, принадлежащее типу PathStr);
DirList— перечень каталогов.
Программа, в которой используется процедура FSplit, а также функции FExpand и FSearch, содержится в примере 9.9 (рис. 9.12).
Пример 9.9
.. t
Pur 9.12. Полное имя файла и его составные части
лава 9. Использование ресурсов модуля DOS
227
В этой программе (с помощью функции FSearch) осуществляется цо_ иск файла TURBO.TPL (библиотека модулей) во всех каталогах диска О Файл обнаруживается в каталоге C:\Program Files\TP7\BIN (где ему и полагается быть). Затем (с помощью функции FExpand) переданное функции имя файла расширяется до полного. Наконец (с помощью про, цедуры FSplit) это полное имя разделяется на каталог (с указанием диска и цепочки каталогов), имя файла и расширение (с предшествующей точкой). Результаты работы программы представлены в окне Output.
Обработка процессов
Подпрограммы модуля DOS, относящиеся к этой категории (три процедуры и одна функция), позволяют манипулировать из программы на Turbo Pascal “посторонними” программами (или процессами).
Процедура Ехес
Инициирует запуск указанной (в качестве параметра) программы с заданной командной строкой.
Заголовок процедуры:
Procedure Exec(Path, CmLine : String);
где Path — полное имя файла запускаемой программы (с указанием диска, цепочки каталогов, имени и расширения файла);
CmLine — командная строка.
Если произойдет ошибка, о ее характере сообщит переменная DosError. При компилировании программы, в которой используется вызов Ехес, не следует задавать для динамически распределяемой памяти (кучи) максимальный размер: в противном случае не исключено, что для запускаемой программы памяти окажется недостаточно. (В этом случае переменная DosError вернет значение 8.)
Пример использования процедуры Ехес имеется в разделе “Функция DosExitCode”.
Процедура Keep
Завершает программу и оставляет ее в памяти. Программы, остающиеся после завершения в памяти компьютера, называют резидентными и обозначают аббревиатурой TSR (Terminate Stay Resident остаться резидентной по завершении).
Заголовок процедуры:
Procedure Keep(ExitCode : Word);
где ExitCode— параметр, который определяет код завершения вашей программы.
228
Turbo Pascal: учитесь программировать
Параметр ExitCode соответствует параметру, передаваемому стан-артной процедуре Halt (из модуля SYSTEM).
Процедура SwapVectors
Меняет содержимое указателей SavelntXX, определенных в модуле 3YSTEM, на текущее содержимое векторов прерываний.
Заголовок процедуры:
Procedure SwapVectors;
Обращение к SwapVectors обычно имеет место непосредственно пе->ед и после обращения к процедуре Ехес. Это гарантирует, что вызы-.аемый процесс не будет использовать никаких подпрограмм обработки прерываний, установленных текущим процессом, и наоборот.
Пример использования процедуры SwapVectors имеется в разделе Функция DosExitCode”.
Функция DosExitCode
Возвращает код завершения процесса.
Заголовок функции:
Function DosExitCode : Word;
При этом собственно код завершения процесса содержит младший Найт. Что касается старшего байта, то он устанавливается особым обра-;ом. Значения старшего байта можно видеть в табл. 9.2.
блица 9.2. Значение старшего байтая, возвращаемого функцией DosExitCode
Тил завершения	Старший байт
Нормальное	О
По нажатию <Ctrl+C>	1
Из-за ошибки устройства	2
Г |роцедурой Keep 3
Программа, в которой используется функция DosExitCode, а также роцедуры Ехес и SwapVectors содержится в примере 9.10 (рис. 9.13).
В тексте этой программы имеется строка
Ехес('c:\unzip.exe', ");
которая инициирует запуск указанной здесь программы. В данном гучае это программа распаковки UNZIP.EXE. Командная строка торой параметр процедуры Ехес) в этом случае не указывается. Перед после обращения к процедуре Ехес имеются вызовы процедуры wapVectors. В случае успешного запуска вызывается функция DosExitCode, которая возвращает код завершения процесса. Этот код, а
\ава 9. Использование ресурсов модуля DOS
229
также сообщения, свидетельствующие об успешном запуске UNZIP.EXb можно видеть в окне Output (см. рис. 9.13). При желании вмес-UNZIP.EXE в качестве параметра процедуры Ехес можно указать любу другую программу.
СУ’ ’ Пример 9.10
Internet
Рис. 9.13. Запуск “посторонней” программы из программы Turbo Pascal
Для успешного запуска нашей программы с помощью директивы компилятора $М задается минимальный размер динамически распределяемой памяти (кучи).
Примечание
3 отличие от командной строки MS DOS, где имя файла загускаемой программы можно зад: ть без расширения, перзый параметр процедуры Ехес должен представлять собой полно? имя файл-, ai-лючэтощее 1 оасширение.
Работа с переменными среды
Данная категория включает три функции, позволяющие получить информацию об установленных переменных среды. Переменные среды управляют работой некоторых пакетных файлов, программ и драйверов устройств, а также самой системы MS DOS.
230
Turbo Pascal: учитесь программировоть
Функция EnvCount
Возвращает число установленных переменных среды MS DOS.
Заголовок функции:
Function EnvCount : Integer;
Пример использования функции EnvCount в программе имеется в следующем разделе.
Функция EnvStr
Возвращает значение определенной переменной среды.
Заголовок функции:
Function EnvStr(Index : Integer) : String;
где Index — числовое значение переменной (Index= 1..EnvCount).
Если значение Index задать меньше 1 или больше EnvCount, функция EnvStr вернет пустую строку. Программа, в которой используются функции EnvCount и EnvStr, содержится в примере 9.11 (рис. 9.14).
t	Пример 9.11
Рис. 9.14. Переменные среды и их значения
Данная программа начинается с вызова процедуры ClrScr из модуля CRT, которая очищает экран вывода (о модуле CRT речь пойдет в следующей главе). Второй оператор программы представляет собой оператор цикла с параметром, который организует количество циклов, равное числу, возвращенному функцией EnvCount (т.е. числу переменных среды). В теле цикла вызывается функция WriteLn, которая выводит на экран значения, возвращаемые функцией EnvStr. При этом в качестве
Глава 9. Использование ресурсов модуля DOS
231
параметра функции EnvStr передается параметр цикла. 1аким на экран выводя гея значения всех < у1”'есТПХ^1»ппГ '«-ременных р Результаты можно видеть на рис. 9.14 в окне Output.
Функция GetEnv
Возвращает значение заданной переменной среды MS DOS.
Заголовок функции:
Function GetEnv(EnvVar : String) : String;
В качестве параметра функции GetEnv
них среды (ТМР. TEMP. PROMPT и т.д. — ем. рис^-ЭЛ4). ут ция GetEn возвращает значение заданной переменной MS DOS. Е и аданная nt ременная среды не существует, то GetEnv вернет пустую строку. Им, переменной может быть представлено символами верхнего или нижнеп регист ра, но не должно содержать знак равенства.
Дополнительные средства
Сюда попали подпрограммы, которые не удалось отнести ни к одно! другой категории процедур и функций модуля DOS.
Обработка <Ctrl+Break>
Прерывание исполнения программы (прерывание $2327) можно вы звать нажатием комбинации клавиш <Ctrl+Break> на клавиатуре ком пьютера. В каких случаях системе следует осуществлять проверку на жатия данной комбинации — это можно задать с помощью процедур) SetCBreak. А процедура GetCBreak проинформирует вас о том, как это функционирование определено в системе в данный момент. О процеду pax SetCBreak и GetCBreak пойдет речь ниже.
Процедура GetCBreak
Возвращает состояние флага проверки на <Ctrl+Break> в MS DOS. Заголовок процедуры:
Procedure GetCBreak(Var Break : Boolean);
где Break - .учение типа Boolean, возвращаемое процедурой.
Если Break - FALSE, MS DOS проверяет нажатие <Ctrl+Break> ТОЛЬК' при операциях ввода-вывода с консолью, принтером или коммунИКаД*
27Обычная системная обработка Ctrl Break программы.
вызывает немедленное завейте^
232
Turbo Pascal: учитесь програкльлиооп
(Ными портами. А если Break = TRUE, проверка осуществляется при ждом обращении к системе.
Процедура SetCBreak
Устанавливает состояние проверки на нажатие <Ctrl+Break> в 3 DOS.
Заголовок процедуры:
Procedure SetCBreak(Break : Boolean);
где Break — значение типа Boolean, возвращаемое процедурой.
Если Break = FALSE, MS DOS будет проверять нажатие <Ctrl+Break> гько при операциях ввода-вывода с консолью, принтером или коммутационными портами. Если Break = TRUE, проверка будет осуществ-гься при каждом обращении к системе.
Состояние верификации в
MS DOS
В MS DOS можно определить, должна ли операционная система ве-[фицировать28 (т.е. считывать для проверки) информацию каждого iCTopa, записываемого на диск. Такая проверка замедляет операцию писи, но гарантирует ее максимальную надежность.
Включить или отключить верификацию можно с помощью процеду-I SetVerify. А процедура GetVerify проинформирует вас о том, включе-। или выключена верификация в данный момент. О процедурах Set-т ify и GetVerify речь пойдет ниже.
1роцедура GetVerify
Возвращает состояние флага верификации в MS DOS.
Заголовок процедуры:
Procedure GetVerify(Var Verify : Boolean);
где Verify— переменная типа Boolean, возврахцаемая процедурой и видетельствующая о состоянии флага верификации. Если Verify = FALSE, запись на диск не сопровождается проверкой. Если Verify = I RUE, запись на диск проверяется, чтобы гарантировать ее достоверность.
Английское слово verify в данном случае имеет смысл проверять, контролировать. удостоверять подлинность.
~'ава 9. Использование ресурсов модуля DOS	233
Примечание
Той же цели можно достичь с помощью функции прерывания $21 MS DOS.__t
Процедура SetVerify
Устанавливает состояние флага верификации в MS DOS.
Заголовок процедуры:
Procedure SetVerify(Verify : Boolean);
где Verify— переменная типа Boolean, определяющая, установку флага верификации. Если Verify = FALSE, запись на диск не будет сопровождаться проверкой. Если Verify = TRUE, запись на диск будет проверяться, чтобы гарантировать ее достоверность.
Примечание
Той же дели можно достичь с помощью функции $21 прерывания $21 MS DOS. 	; I
Версия MS DOS
Данная категория включает единственную функцию, позволяющую выяснить из программы номер версии операционной системы, под управлением которой работает компьютер.
Функция DosVersion
Возвращает номер версии MS DOS.
Заголовок функции:
Function DosVersion : Word;
При этом младший байт возвращенного функцией значения представляет собой номер версии, а старший байт— номер модификации данной версии.
Мы уже определяли версию MS DOS в разделе “Процедура MsDos”, только там это было сделано с помощью процедуры MsDos, позволившей нам обратиться к функции $30 операционной системы, которая доступна через программное прерывание $21. Сейчас мы выяснили, как получить тот же результат, применив специальную функцию DosVersion, определенную в модуле DOS.
Простенькая программа, в которой используется только что рассмотренная функция, содержится в примере 9.12 (рис. 9.15).
В этой программе использованы две еще незнакомые нам функции модуля SYSTEM — Lo и Hi. Первая из них возвращает младший байт ар-
234
Turbo Pascal: учитесь программировать
j-умента, принадлежащего типу WORD, а вторая — старший. Таким образом, выражения Lo(DosVersion) и Hi(DosVersion) возвращают соответственно номер версии и номер модификации данной версии. Окно Output на рис. 9.15 свидетельствует, что компьютер, на котором запускалась данная программа, работает под управлением MSDOS 7.1, иными словами, Windows 98.
ternet
Пример 9.12
ше Edit search jten Compi 1e Debug Tools options	н<ёТр
| -------------- \ M ОИ Д О--1X P ASC AL \ ПР О Г P - -I \ О 4 2 _ if A- < 4 Г C-S V E F . P AS -
program Dosver; uses Dos;
Sega n
writeLn(‘версия DOS :	LoCDosVersion),	Hi(DosVersion));
End.
[]
Output ' "
-----------------3-[’]
Fl Help
Sc-oil FIO Menii :
Puc. 9.15. Выяснить версию операционной системы не составляет труда
Глава 9. Использование ресурсов модуля DOS
235
Глава 10
Использование ресурсов модуля CRT
В этой главе...
Управление клавиатурой
Управление выводом на экран С
Управление звуком
Основная часть ресурсов модуля CRT служит для управления выво/ дом на экран в текстовом режиме. Подпрограммы этой части модуля позволяют выбирать текстовый режим, цвета символов и фона, яркость свечения символов, перемещать курсор в любую позицию экрана, создавать на экране окна и т.п.
Помимо вывода на экран, модуль CRT предоставит вам также возможность управлять клавиатурой и встроенным динамиком.
Управление клавиатурой
В целом управление клавиатурой сводится к двум задачам:
	выявление нажатия любой клавиши;
	выявление нажатия определенной клавиши (клавиш).
Для чего нужно знать, была ли нажата какая-нибудь клавиша? Работая с компьютером вы. вероятно, не раз встречались с сообщением:
Press any key to continue
или
Press any key to stop
Эти сообщения предлагают пользователю нажать любую клавишу на клавиатуре, чтобы продолжить работу с программой или прекратить существующее функционирование. Иными словами, если в данной ситуации нажимается клавиша (любая), производится определенное действие (единственное).
Что касается выявления нажатия определенной клавиши, то это нужно для того, чтобы с помощью разных клавиш (или их комбинг ций), инициировать различные действия. Например, в меню любой программы (взять хотя бы интегрированную среду разработчика Turbo Pascal) против многих пунктов указаны комбинации клавиш. Воспользовавшись одной из них, можно выполнить соответствуюп]ую команду.
Как средствами Turbo Pascal решаются две задачи, упомянутые выше, мы узнаем позже, а сейчас разберемся, какие клавиши имеются на клавиатуре компьютера и какие коды генерируют те или иные клавиши.
Клавиши и коды
При нажатии любой клавиши клавиатура генерирует некоторый код. известный как скэн-код (scan-code). Если клавишу нажать и придер* жать, начинает генерироваться последовательность скэн-кодов.
Далее с помощью BIOS, через прерывание 9, проводится преобразование поступающего скэн-кода в специальный двухбайтовый код-Младший из этих двух байтов для символьных клавиш содержит ASCII'
238	Turbo Pascal: учитесь программировать
код, соответствующий изображенному на клавише знаку, а старший байт содержит скэн-код клавиши.
При нажатии некоторых управляющих клавиш, таких как <F1> — <F10>, <Home>, <Del>, <Ins> и других, а также при нажатии некоторых комбинаций клавиш младший байт двухбайтового кода содержит не ASCII-код, а О (нуль). Это признак того, что нажатая клавиша не является символьной. Старший байт при этом содержит скэн-код нажатой клавиши (если это единственная клавиша) или номер комбинации клавиш (если это комбинация, в которой участвует управляющая клавиша). Двухбайтный код, младший байт которого содержит нуль, называют расширенным ASCII-кодом.
В соответствии с этим клавиши на стандартной клавиатуре компьютера можно разделить на три группы:
	клавиши (и комбинации клавиш), при нажатии которых в буфер заносится простой ASCII-код
(символьные клавиши в обоих регистрах, а также некоторые комбинации с участием клавиш <Ctrl> и <Alt>);
	клавиши (и комбинации клавиш), при нажатии которых в буфер заносится расширенный ASCII-код
(функциональные клавиши и их комбинации с клавишами <Ctrl>. <Shift> и <Alt>; символьные клавиши в сочетании с <Alt> и еще некоторые);
	клавиши (и комбинации клавиш), при нажатии которых никакой код в буфер не заносится
(<Ctrl>, <Alt>, <Shift>, <NumLock>, <CapsLock>, <ScrollLock>, <Pause>, <Print Screen>, а также некоторые комбинации)
Однако, как определить, какой код генерирует та или иная клавиша (или комбинация клавиш)? Что касается символьных клавиш, то их коды представлены в таблице кодов ASCII (приложение Е). А какие коды ассоциированы с различными управляющими клавишами и клавишными комбинациями (и какие клавиши или комбинации не генерируют никакого кода), поможет выяснить программа, представленная в разделе “Программа определения кодов”. (Кстати, эта же программа позволяет определять и коды символьных клавиш, т.е. заглядывать в таблицу ASCII вовсе необязательно.)
Итак, после нажатия клавиши соответствующий код помещается в буфер клавиатуры. Считывание из буфера осуществляется с помощью процедур Read и ReadLn, а также функции ReadKey. Буфер в состоянии вместить до 16 символов. Если клавиши на клавиатуре нажимаются, а коды из буфера не считываются, имеет место переполнение буфера и после этого коды начинают теряться.
Глава 10. Использование ресурсов модуля CRT
239
Вот, собственно, и все, что необходимо знать о функционировании клавиш и буфера клавиатуры. А сейчас, прежде чем перейти к двум задачам управления клавиатурой, познакомимся с двумя функциям модуля CRT, позволяющими решить эти задачи.
Функция KeyPressed
Возвращает значение TRUE (типа Boolean), если в буфере есть хотя бы один символ (т.е, если была нажата клавиша на клавиатуре), и FALSF в противном случае.
Заголовок функции:
Function KeyPressed : Boolean;
Функция ReadKey
Считывает символ из буфера клавиатуры; считанный символ при этом на экране не отображается. Если перед обращением к ReadKey в буфере что-то было, символ считывается немедленно. Если буфер пуст, функция ожидает нажатия клавиши.
Заголовок функции:
Function ReadKey : Char;
Выявление нажатия любой
клавиши
Вот как может выглядеть программа, позволяющая решить эту задачу: uses crt;
var
а:byte;
begin
while KeyPressed do
a:=ReadKey;
repeat
until KeyPressed;
end.
К этой программе подключается модуль CRT, без ресурсов которого указанную задачу решить сложно. В программе организованы два цикла— с помощью операторов WHILE и REPEAT. Первый цикл (while KeyPressed do a:=ReadKey) опорожняет буфер клавиатуры. Здесь используются две функции модуля CRT (KeyPressed и ReadKey), с которыми МЫ только что познакомились. До тех пор, пока функция KeyPressed не вер
240
Turbo Pascal: учитесь программировать
нет значение FALSE, будет выполняться оператор a:=ReadKey. Иными словами, чтобы опорожнить буфер, необходимо считать все содержащиеся в нем коды символов.
Второй цикл в этой программе (repeat ... until KeyPressed) обеспечивает циклическое выполнение набора операторов (представленных здесь тремя точками) до тех пор, пока не будет нажата любая клавиша, после чего некоторый код попадет в буфер. Иными словами, как раз этот цикл решает первую из задач, которой посвящен данный раздел.
Выявление нажатия определенной клавиши
Вот возможное решение этой задачи:
uses crt;
var
a:char;
begin
repeat
... a:=ReadKey;...
until a in ['в', ’Chr(27)'];
end.
В этой программе с помощью оператора REPEAT организован цикл, условие прекращения которого имеет вид until a in ['е', 'Chr(27)’J.
Здесь проверяется вхождение значения переменной А в некоторое множество. В этом множестве перечислены символы, при нажатии на клавиши которых цикл прекращается. Символы мотут быть заданы яв-ю ('е') или с помощью функции Chr в виде кода ASCII ('Chr(27)')- При-тем, если для данного кода соответствующего символа не существует, 'бойтись можно только кодом. Например, во втором случае выше указан код клавиши <Esc>. Набор и количество символов множества в условии прекращения цикла мотут быть любыми.
Очевидно, что в теле цикла REPEAT в этой программе (помимо прочих) должен быть оператор a:=ReadKey, осуществляющий считывание из >уфера.
Программа определения кодов
Обещанная программа, позволяющая определить, какой код генерируется той или иной клавишей (или комбинацией клавиш), а также выявить клавиши и комбинации, не генерирующие никакого кода, содержится в примере 10.1 (рис. 10.1).
лава 10. Использование ресурсов модуля CRT
241
t
Пример '10.1
nternet
Puc. 10.1. Программа определения кодов
В этой программе прежде всего знакомым нам способом опорожня ется буфер клавиатуры:
while KeyPressed do a:=ReadKey
После этого организуется цикл REPEAT, в теле которого определяет ся, что собой представляет данный код — простой он или расширенный (расширенный код начинается с нуля). И в соответствии с типом кода организуется его вывод на экран в удобном формате. В окне Output в первом столбце отображается нуль, если это расширенный код. Во втором столбце отображается символ, соответствующий данному коду (если это простой код). И вот что отображается в третьем столбце:
	если это простой код — ASCII-код данного символа:
	если это расширенный код одиночной клавиши (в случае если данная клавиша генерирует расширенный код) — скэн-код данной клавиши;
	если это расширенный код комбинации клавиш — номер данной комбинации
В программе условием прекращения цикла является нажатие клавиши “1” (единица). Однако, если потребуется определить, какой код соответствует этой клавише, символ в условии можно заменить на любой другой.
242
Turbo Pascal: учитесь программировав
Управление выводом
на экран
Средства, предназначенные управлять выводом информации на экран (в текстовом режиме), составляют значительную часть ресурсов модуля CRT. Эти средства, разбитые по категориям согласно выполняемым ими действиям, и рассматриваются в данном разделе. Вот о каких категориях действий идет речь:
	быстрый вывод на экран
	выбор текстового режима
	управление цветом символов и фона
	управление яркостью
	управление курсором
	управление текстовыми окнами
	очистка окна
	работа со строками
Видеосистема компьютера включает две составные части: видеоадаптер и видеомонитор. Причем, управлению средствами Turbo Pascal поддается прежде всего видеоадаптер. Таким образом, говоря об управлении выводом на экран, мы подразумеваем управление видеоадаптером.
Быстрый вывод на экран
Как выводить информацию на экран, мы уже знаем. Для этого необходимо ассоциировать файловую переменную с экраном:
Assign(f,'con');
Затем указанный “файл” нужно открыть:
Rewrite(f);
И наконец, можно инициировать вывод на экран:
Write(f,'Вывод на экран');
Кроме того, мы знаем, что в Turbo Pascal, в модуле SYSTEM, объявляется файл вывода OUTPUT. Поскольку модуль SYSTEM автоматически подключается к любой программе, этот файл ассоциируется с экраном и открывается автоматически. Иными словами, использовать процедуры Assign и Rewrite в этом случае вовсе необязательно. И указывать файл, в который производится вывод, также необязательно:
Write('Вывод на экран');
Глава ИО. Использование ресурсов модуля CRT
243
Тем не менее создатели Turbo Pascal сочли необходимым ввести в мо дуль CRT процедуру, делающую приблизительно то же самое, что и пр' цедура Assign. Познакомимся с ней подробнее.
Процедура AssignCrt
Ассоциирует текстовую файловую переменную с окном CRT.
Заголовок процедуры:
Procedure AssignCrt(Var f : Text);
где F — текстовая файловая переменная.
При использовании этой процедуры, указывать файл, с которым ассоциируется переменная F, не требуется. Файловая переменная F при исполг зовании процедуры AssignCrt автоматически связывается с окном CRT.
Возникает вопрос, для чего понадобилось создавать эту новую про цедуру? В чем ее преимущество перед старыми средствами, о которых шла речь выше? Дело в том, что AssignCrt, за счет непосредственногс обращения к видеопамяти (которой обладает видеоадаптер и которая используется для создания изображения на экране), обеспечивает более быстрый вывод на экран.
Выбор текстового режима
Текстовый режим видеоадаптера позволяет выбрать процедур TextMode из модуля CRT. Вот ее описание.
Процедура TextMode
Устанавливает определенный текстовый режим.
Заголовок процедуры:
Procedure TextMode(Mode : Integer);
где Mode— константа, которая задает текстовый режим. В Turbc Pascal (точнее, в модуле CRT) определены шесть таких констант, кото рые представлены в табл. 10.1.
Таблица 10.1. Константы, определяющие текстовый режим экрана
Констант	а Код	Режим экрана
BW40	0	Черно-белый 40x25 (25 строк по 40 символов)
СО40	1	 Цветной 40x25
BW80	2	Черно-белый 80x25
СО80 7va	'-уЛхаА.3	Цветной 80x25
Mono	4	7	Черно-белый 80x25 (используется с адаптером MDA)
Font8x8	256 Чо:5о ‘	Используется для загружаемого шрифта в режиме 80x43 или 80x25 с адаптерами EGA или VGA
244
Turbo Pascal: учитесь программироват
В качестве параметра процедуры TextMode можно указать как имя константы (например, TextMode(BW40)), так и ее числовой код (например, TextMode (0)).
Номер текстового режима, использовавшегося до этого, присваивается в качестве значения переменной LastMode, объявленной в модуле CRT. Эта переменная может использоваться, когда потребуется вернуться к предыдущему текстовому режиму. Для этого достаточно задать вызов TextMode (LastMode). Это может быть полезно, если вы, например, после работы в графическом режиме хотите вернуться к предыдущему текстовому режиму.
Примечание
Процедура TextMode определяет режим всего экрана. I Вам не удастся создать на экране несколько окон, а затем 1 определить для каждого свой режим. Окнам посвящен раздел “Текстовые окна” дальше в этой главе.
Цвета символов и фона
При выводе текста на экран выводимым символам можно придать любой из 16 (0-15) цветов. Цвет символов на экране задает процедура extColor. Цвет фона задает процедура TextBackground. Вот их описания.
Процедура TextColor
Устанавливает цвет символов.
Заголовок процедуры:
Procedure TextColor(Color : Byte);
где Color— целое число (или выражение), значение которого не должно выходить за пределы 0.. 15, что соответствует одной из констант цвета текстового режима, определенных в модуле CRT.
Процедура TextBackground
Устанавливает цвет фона.
Заголовок процедуры:
Procedure TextBackground(Color : Byte);
где Color — целое число (или выражение) в диапазоне 0..7, соответствующее одной из первых восьми констант цвета в текстовом режиме.
Константы, объявленные в модуле CRT и использующиеся в качестве параметра Color этих процедур, представлены в табл. 10.2. (Для TextColor — все 17; для TextBackground — только первые 8.)
Глава 10. Использование ресурсов модуля CRT
245
Таблица 10.2. Константы, определяющие цвета текста и фона
Имя константы	Код	Цвет
Black	0	Черный
Blue	1	Темно-синий
Green	2	Темно-зеленый
Cyan	3	Бирюзовый
Red	4	Красный
Magenta	5	Фиолетовый
Brown	6	Коричневый
LightGray	7	Светло-серый
DarkGray	8	Темно-серый
LightBlue	9	Синий
LightGreen	10	Светло-зеленый
LightCyan	11	Светло-бирюзовый
LightRed	12	Розовый
LightMagenta	13	Малиновый
Yellow	14	Желтый
White	15	Белый
Blink	128	Мерцание символа
Примечание
г Фон мерцать не может.
После того как цвет символов или фона задан, он применяется до тех пор, пока не будет задан новый цвет. В качестве параметра процедур TextColor и TextBackground можно использовать как имя константы так и ее числовой код. Например, вызов процедуры TextColor(Black) эк Бивалентен вызову TextColor (0). С помощью единственного обращения i процедуре TextColor можно задать одновременно цвет и мерцание сим волов: TextColor (Black+Blink). При выводе текста на экран необходимс-следить, чтобы цвет символов не совпал с цветом фона, а также, чтобь эти цвета были достаточно контрастны.
Яркость
Управление яркостью свечения символов осуществляется стандартными процедурами LowVideo, NormVideo и HighVideo. При этом режим NormVideo при инициализации модуля CRT устанавливается по умолча-
246
Turbo Pascal: учитесь программировав
пию. Заданная яркость применяется до тех пор, пока не будет установлен иной режим. При обращении к указанным процедурам никаких параметров указывать не требуется. Вот описания упомянутых процедур.
Процедура LowVideo
Включает низкую интенсивность свечения символов.
Заголовок процедуры:
Procedure LowVideo;
Процедура Norm Video
Выбирает интенсивность свечения символов, используемую по умолчанию.
Заголовок процедуры:
Procedure NormVideo;
Процедура HighVideo
Включает высокую интенсивность свечения символов.
Заголовок процедуры:
Procedure HighVideo;
Вот пример использования различных режимов яркости:
uses crt;
begin
LowVideo;
Write('Низкая яркость ');
NormVideo;
Write('Нормальная яркость ');
HighVideo;
Write('Высокая яркость ');
end.
Данная программа выводит на экран слова Низкая яркость, Нормальная яркость и Высокая яркость с яркостью свечения, соответствующей смыслу этих слов.
Перемещение курсора
Для того чтобы выводить на экран информацию нужным образом, пользователь нуждается в средствах, позволяющих переместить курсор на любую позицию экрана. Соответствующие средства Turbo Pascal включают процедуру GoToXY, а также функции WhereX и WhereY.
Глава 10. Использование ресурсов модуля CRT
247
Процедура GoToXY
Процедура GoToXY перемещает курсор в определенную позицию si рана.
Заголовок процедуры:
Procedure GotoXY(X, Y : Integer);
где X и Y—параметры, принадлежащие типу Byte и определяющие со ответственно номер символа в строке и строку, куда следует переместит курсор. При этом левый верхний угол экрана соответствует позиции (1,1)
Например, вот как можно вывести строку текста в нужном месте эк рана:
begin
GoToXY(10,10);
Write('10-H позиция в 10-й строке') end.
Здесь вместо координат экрана 10,10 можно указать любые другие.
Функция WhereX
Возвращает Х-координату текущего положения курсора (т.е. номе позиции в строке).
Заголовок функции:
Function WhereX : Byte;
Функция WhereY
Возвращает Y-координату текущего положения курсора (т.е. номер строки).
Заголовок функции:
Function WhereY : Byte;
Вот пример использования функций WhereX и WhereY:
begin
WriteLn ('Курсор находится в столбце ',WhereX);
WriteLn ('Курсор находился в строке ',WhereY);
end.
Текстовые окна
Turbo Pascal предоставляет возможность выводить информацию в пределах не всего экрана, а только определенной его области. Такая об ласть экрана, которой ограничивается вывод информации, называется окном. В модуле CRT для создания окон предусмотрена процедура Window.
248
Turbo Pascal: учитесь программировав
Процедура Window
Определяет на экране текстовое окно.
Заголовок процедуры:
Procedure Window(Xl, Yl, Х2, Y2 : Byte);
где XI и Y1 — координаты верхнего левого угла окна;
Х2 и Y2 — координаты нижнего правого утла окна;
Все четыре значения принадлежат типу Byte.
Координаты верхнего левого угла экрана— (1, 1). Максимальные размеры окна— весь экран; минимальные— единственная позиция. Если в качестве параметра задана недопустимая координата, в этом случае обращение к процедуре Window игнорируется.
Все экранные координаты, кроме координат самого окна, задаются относительно текущего окна. Так, многие процедуры и функции модуля CRT действуют в пределах не всего экрана, а только текущего окна. Сюда относятся ClrEol, ClrScr, DelLine, GotoXY, InsLine, WhereX, WhereY, Read, Readln, Write и Writein. Например, обращение GotoXY(l, 1) переместит курсор в верхний левый угол текущего окна (но не экрана).
Помимо процедуры Window, для работы с окнами можно также использовать определенные в модуле CRT переменные WindMin и WindMax, принадлежащие типу Word. Значения этих переменных соответствуют координатам соответственно верхнего левого и правого нижнего углов текущего окна. Причем координата X в обоих переменных содержится в младшем байте. Нетрудно догадаться, что при обращении к процедуре Window переменные WindMin и WindMax получают новые значения. По умолчанию (изначально) значения этих переменных соответствуют максимальному размеру окна (т.е. всему экрану).
Пример программы, создающей на экране несколько окон, содержится в примере 10.2 (рис. 10.2).
В этой программе окна создаются с помощью определенной здесь процедуры Wind. Первые четыре параметра этой процедуры— координаты окна, пятый — цвет фона, шестой — текстовая строка, выводимая в окне. Использованная в этой программе процедура очистки экрана ClrScr рассматривается в следующем разделе. Результат работы программы представлен здесь же, в окне Output.
Очистка окна
Для очистки текущего окна в модуле CRT предусмотрена процедура ClrScr, при обращении к которой никакие параметры указывать не требуется. Если на экране окна не создавались (т.е. ранее в программе обращений к процедуре Window не было), процедура ClrScr очищает весь экран.
Глава 10. Использование ресурсов модуля CRT
249
Inn=».t4жСОВ^Пример 10.2
[]
program windows;
uses crt;
var a:byte;
Crocedure windCxi,yl,x2,y2:byte;b:byte;c:string); egin
wi ndowCxl, yl, x2 , y2 ) ;	—r“q---------------
TextBackgroundCb);
ClrScr;
wri te(c);
end;
begi n
TextMcde(3);
wind£5,5,15,10,5 ‘окно 1');
windC2u,§,30,10,5,‘Окно 2')
wi nd £35,5,4 5,10,5, 'Окно 3’) end.
Output -
m Help о- scroll >₽iQ‘ Menu-
Рис. 10.2. Можно создать сколько угодно окон
Процедура ClrScr
Очищает активное окно и устанавливает курсор в его левый верхни угол.
Заголовок процедуры:
Procedure ClrScr;
Работа со строками
Для этого в Turbo Pascal (точнее, в модуле CRT) имеются процедур ClrEol, DelLine и InsLine.
Процедура ClrEol
Процедура ClrEol удаляет все символы от текущей позиции курсора до конца строки.
Заголовок процедуры:
Procedure ClrEol;
При этом удаляемые символы заменяются пробелами, а местополо жение курсора не меняется. Процедура ClrEol действует в пределах ак тивного окна (но не экрана).
250
Turbo Pascal: учитесь программироват
Процедура DelLine
Процедура DelLine удаляет текущую строку (т.е. строку, в которой находится курсор).
Заголовок процедуры:
Procedure DelLine;
При этом все строки, расположенные ниже удаляемой, сдвигаются на одну строку вверх.
Процедура InsLine
Вставляет пустую строку.
Заголовок процедуры:
Procedure InsLine;
При этом все нижние строки, а также строка, в которой до этого был курсор, сдвигаются на одну позицию вниз. Текущее положение курсора при вызове InsLine не меняется. Если нижняя строка при сдвиге выходит за пределы экрана (окна), она теряется.
Управление звуком
Под этим подразумевается управление динамиком, встроенным в системный блок компьютера. Для управления звуком в модуле CRT предназначены три процедуры: Sound, NoSound и Delay. Вот что они собой представляют.
Процедура Sound
Заставляет звучать внутренний динамик.
Заголовок процедуры:
Procedure Sound(Hz : Word);
где Hz— значение, соответствующее частоте звука (выраженной в герцах).
После обращения к Sound, управление передается следующему оператору в программе, а звук продолжается до тех пор, пока не будет вызвана процедура NoSound.
Процедура NoSound
Прекращает подачу звукового сигнала на внутренний динамик компьютера.
Заголовок процедуры:
Procedure NoSound;
Глава 10. Использование ресурсов модуля CRT
251
Процедура Delay
Приостанавливает выполнение программы на заданный интервал времени.
Заголовок процедуры:
Procedure Delay(ms : Word);
где MS — значение, определяющее интервал времени в миллисекундах. Иными словами, управление от Delay к следующему оператору программы передается с задержкой, которую определяет параметр MS.
Так, обращение Delay (5000) задержит программу ровно на 5 с.
Вот образец программы (пример 10.3), в которой осуществляется перебор (вперед и назад) звуковых частот, причем сигнал каждой частоты подается на динамик в течение определенного времени (1000 мс. т.е. 1 с).
Пример 10.3
program sounds; uses crt;
var i:integer;
begin
i:=0;
while i<8000 do begin
i:=i+500;
Sound(i);
Delay(1000);
NoSound end;
while i>l do begin
i:=i-500;
Sound(i);
Delay(1000);
NoSound end end.
252
Turbo Pascal: учитесь программировать
Использование ресурсов модуля GRAPH
В этой главе...____________________________
	Управление, выбор и переход в графический режим
	Цвета, палитры, заполнения
	Координаты и окна
	Точки и линии
	Незаполненные фигуры
	Заполненные фигуры
	Текст в графическом режиме
	Разное
Средства модуля GRAPH, включающие свыше 70-ти процедур и функций, позволяют формировать на экране разного рода цветные изображения. Эти изображения могут выводиться как на весь экран, так и в предварительно созданные графические окна. Поддерживается несколько типов линий и заполнений. Имеется набор поддающихся масштабированию шрифтов. Ряд подпрограмм модуля специально предназначен для отображения на экране различных фигур — заполненных и незаполненных. Все подпрограммы, о которых идет речь в этой главе, для лучшего понимания разделены на категории по функциональному признаку.
Режимы: графический и текстовый
Для того чтобы воспользоваться процедурой или функцией модуля GRAPH, выводящей на экран какое-либо изображение, прежде необходимо инициировать графический режим. В этом разделе мы познакомимся со средствами выбора и управления графическим режимом, узнаем, как перейти в тот или иной графический режим и как вернуться в текстовый.
Процедура InitGraph
Инициирует перевод видеоадаптера в графический режим.
Заголовок процедуры:
Procedure InitGraph (Var Driver, Mode: Integer; Path : String);
где Driver — параметр, определяющий графический драйвер;
Mode — параметр, задающий один из графических режимов, допустимых для указанного драйвера;
Path— имя файла (и путь) графического драйвера: если значение Path соответствует пустой строке, поиск файла драйвера проводится в текущем каталоге.
Значения параметра Driver ограничиваются набором констант, объявленных в модуле GRAPH. Имена констант и их значения представлены в табл. 11.1.
254
Turbo Pascal: учитесь программировать
Таблица 11.1. Константы и коды, определяющие драйвер
Имя константы	Числовой код
Detect	0 (Автоопределение)
CGA	1
MCGA	2
EGA	3
EGA64	4
EGAMono	5
IBM8514	6
HercMono	7
ATT400	8
VGA	9
PC3270	10
Если значение параметра Driver равно Detect (О), система пытается определить тип видеоадаптера автоматически. В этом случае InitGraph вызывает процедуру DetectGraph. Если графическое аппаратное обеспечение обнаружено, инициализируется соответствующий графический драйвер и включается графический режим. При этом параметры-переменные Driver и Mode по завершении работы процедуры возвращают значения, соответствующие коду драйвера и режиму работы видеоадаптера.
Если значение параметра Driver отличается от Detect, драйвер выбирается непосредственно, согласно указанному значению. После этого видеосистема переходит в режим, определенный заданным параметром Mode.
Необходимость задать значение параметра Driver, отличающееся от Detect, возникает только в случае, когда требуемся использовать иной драйвер, — не тот, который рекомендует процедура DetectGraph. Если вы указываете процедуре InitGraph какой-то определенный драйвер (т.е. заданное значение параметра Driver, не равно Detect), то в этом случае также следует указать и допустимый для этого драйвера режим (параметр Mode).
11
1римечание
Необходимо понимать, что основная цель возможности автообнаружения — создание программ, которые будут  работать на компьютере с любым видеоадаптером. Если графический драйвер и режим указать явно, это резко осложнит использование создаваемойпрограммы.
Если вы все же решили не использовать автообнаружение (т.е. значение Driver задали отличным от Detect), вам, как уже отмечалось, при
Глава 11. Использование ресурсов модуля GRAPH
255
дется для выбранного драйвера указать допустимый графический pt жим. Константы, определяющие режимы для различных видела цапте ров, а также их числовые коды, представлены в табл. 11.2.
Таблица 11.2. Константы и коды графических режимов для различных видеоадапгеро^
Имя константы	Код	Разрешение	Палитра	Поддержка страниц
Драйвер CGA				
CGAC0	0	320x200	СО	1
CGAC1	1	320x200	С1	1
CGAC2	2	320x200	С2	1
CGAC3	3	320x200	СЗ	1
CGAHi	4	640x200	2 цвета	1
Драйвер MCGA				
MCGAC0	0	320x200	СО	1
MCGAC1	1	320x200	С1	1
MCGAC2	2	320x200	С2	1
MCGAC3	3	320x200	СЗ	1
MCGAMed	4	640x200	2 цвета	1
MCGAHi	5	640x480	2 цвета	1
Драйвер EGA				
EGALo	0	640x200	16 цветов	4
EGAHi	1	640x350	16 цветов	2
Драйвер EGA64				
EGA64LO	0	640x200	16 цветов	1
EGA64Hi	1	640x350	4 цвета	1
Драйвер EGA-MONO
EGAMonoHi	3	640x350	2 цвета	1
EGAMonoHi	3	640x350	2 цвета	2
Драйвер HERC				
HercMonoHi	0	720x348	2 цвета	2
Драйвер АТТ400				
АТТ400С0	0	320x200	СО	1
АТТ400С1	1	320x200	С1	1
256
Turbo Pascal: учитесь программировать
окончание табл. 11.2
Имя константы	Код	Разрешение	Палитра	Поддержка страниц
"АТТ400С2	2	320x200	С2	1
АТТ400СЗ	3	320x200	СЗ	1
ATT400Med	4	640x200	2 цвета	1
ATT400Hi	5	640x400	2 цвета	1
Драйвер VGA				
VGALo	0	640x200	16 цветов	2
VGAMed	1	640x350	16 цветов	2
VGAHi	2	640x480	16 цветов	1
Драйвер PC3270				
PC3270Hi	0	720x350	2 цвета	1
Драйвер IBM8514				
IBM8514LO	0	640x480	256 цветов	1
IBM8514Hi	0	1024x768	256 цветов	1
В четвертом столбце таблицы представлена информация о цветах, поддерживаемых тем или иным режимом. Подробнее о цветах речь пойдет в разделе “Цвета, палитры, заполнения”. В пятом столбце указано количество страниц, которое поддерживает данный режим. Со страницами мы познакомимся в разделе "Прочие процедуры и функции”.
Процедура DetectGraph
Тестирует аппаратуру и определяет, какой графический драйвер и режим (максимально допустимые) подходят для данного видеоадаптера.
Заголовок процедуры:
Procedure DetectGraph(Var Driver, Mode : Integer);
где Driver — параметр, определяющий подходящий тип графического драйвера;
Mode— параметр, задающий один из графических режимов, поддерживаемых данным драйвером.
DetectGraph обычно вызывается процедурой InitGraph и сведения о приемлемом драйвере и режиме затем передаются этой же процедуре. Если видеоадаптер обнаружен не был, то в этом случае параметр-переменная Driver возвращает значение grNotDetected (не удалось определить тип адаптера). Это же значение вернет и функция GraphResult (ем. табл. 11.3).
Если для параметра Driver не задано значение, отличное от Detect (ем. табл. 11.1), процедура InitGraph вызывает процедуру DetectGraph,
Глава 11. Использование ресурсов модуля GRAPH	257
2016
которая находит и загружает подходящий драйвер, а затем инициали* зирует графическую систему.
Функция GraphResult
Возвращает код ошибки графической операции, выполнявшейся последней.
Заголовок функции:
Function GraphResult : Integer;
Код ошибки устанавливают следующие процедуры и функции модуля GRAPH:
Ваг, Bar3D, ClearViewPort, CloseGraph, DetectGraph, DrawPoly FillPoly, FloodFill, GetGraphMode, ImageSize, InitGraph, InstallUserDriver InstallUserFont, PieSlice, RegisterBGIdriver, RegisterBGIfont, SetAllPalette SetFillPattern, SetFillStyle, SetGraphBufSize, SetGraphMode, SetLineStyle SetPalette, SetTextJustify, SetTextStyle. (Каждой из этих подпрограмм i данной главе посвящен раздел.)
Значения, возвращаемые функцией GraphResult, определяются на бором констант, объявленных в модуле GRAPH (табл. 11.3).
Таблица 11.3. Константы и коды ошибок графических операций
Имя константы	Код	Текстовое сообщение (перевод)
grOk	0	Без ошибок
grNolnitGraph	-1	Не инициализирован графический режим
grNotDetected	-2	Не удалось определить тип адаптера
grFileNotFound	-3	Не обнаружен файл с драйвером
grlnvalidDriver	-4	Обнаруженный файл не содержит соответствующего драйвера
grNoLoadMem	-5	Недостаточно памяти для загрузки драйвера
grNoScanMem	-6	Недостаточно памяти для просмотра областей
grNoFIoodMem	-7	Недостаточно памяти для заполнения областей
grFontNotFound	-8	Не обнаружен файл со шрифтом
grNoFontMem	-9	Недостаточно памяти для загрузки шрифта
grlnvalidMode . >4	-10	Недопустимый режим для выбранного драйвера
grError	-11	Общая ошибка
grIOerror	-12	Ошибка ввода-вывода
grlnvalidFont	-13	Неверный формат шрифта
grlnvalidFontNum	-14	Неверный номер шрифта
При вызове GraphResult эта функция, как уже отмечалось, возвра-щает код ошибки графической операции и при этом код ошибки уста-
258
Turbo Pascal; учитесь программировать
цавливается в О (grOk) Если GraphResult вызвать повторно, то этот результат (grOk) и будет возвращен.
Функция GraphErrorMsg
Возвращает текст сообщения об ошибке (по-английски) по ее число-
вому коду.
Заголовок функции:
Function GraphErrorMsg(ErrorCode : Integer) : String;
где ErrorCode— код ошибки, который возвращает функция GraphResult.
Программа, выводящая на экран все числовые коды ошибок и соответствующие им сообщения, содержится в примере 11.1 (рис. 11.1).
S Пример 11.1
Рис. 11.1. Сообщения об ошибках графических операций
Здесь в окне Output можно видеть сообщения (по-английски), каждое из которых расположено против соответствующего ему числового кода. Перевод сообщений содержится в табл. 11.3. Эта программа не нуждается в переходе в графический режим.
А нельзя ли сделать так, чтобы эти сообщения выдавались по-русски? Дл я этого вам придется вместо GraphErrorMsg создать собственную функцию. Подсказка: в этой функции очень удобно использовать оператор CASE.
Процедура RestoreCrtMode
Осуществляет переход в видеорежим (текстовый), использовавшийся До перехода в графический ражим.
Глава 11. Использование ресурсов модуля GRAPH
259
Заголовок процедуры:
Procedure RestoreCrtMode;
RestoreCrtMode, в отличие от процедуры CloseGraph, не освобождай память и не сбрасывает параметры графического режима.
Данная процедура может использоваться совместно с процедурой SetGraphMode, чтобы временно (и быстро) переходить в программе из графического режима в текстовый и обратно.
Процедура SetGraphMode
Устанавливает для используемого драйвера новый графический режим и очищает экран.
Заголовок процедуры:
Procedure SetGraphMode(Mode : Integer);
где Mode — целое число (от О до 5), определяющее режим.
Если процедура InitGraph задает драйвер и указывает для него видеорежим, то процедура SetGraphMode позволяет перейти в иной видео-режим — один из доступных для данного драйвера.
SetGraphMode прежде всего предназначена для перехода в иной графический режим, отличный от используемого. Однако данная процедур также может использоваться совместно с процедурой RestoreCRTMode, чтобы временно (и быстро) переходить из графического режима в текст< вый и обратно.
Процедура SetGraphMode устанавливает для всех существующв < графических параметров (палитра, цвет, область просмотра и т.п.) зна чения по умолчанию, заданные для данного режима.
При попытке установить (с помощью процедуры SetGraphMode) для используемого драйвера недопустимый режим функция GraphResult вернет код ошибки —10 (grlnvalidMode, см. табл. 11.3).
Функция GetGraphMode
Возвращает числовой код (от О до максимум 5 для каждого драйвера; используемого в данный момент графического режима, установленного с помощью процедуры InitGraph или SetGraphMode.
Заголовок функции:
Function GetGraphMode : Integer;
Констцнты графических режимов для всех драйверов, объявленные в модуле GRAPH, представлены в табл. 11.2.
Функция GetModeName
Возвращает строку с именем константы используемого графического режима.
260
Turbo Pascal: учитесь программировав
Заголовок функции:
Function GetModeName(ModeNumber : Integer) : String;
где ModeNumber — код графического режима.
Коды и имена графических режимов для всех драйверов представлены в табл. 11.2.
Программу, в которой используются функции GetModeName, можно видеть в примере 11.2
Функция GetDriverName
Возвращает имя файла используемого в данный момент драйвера (т.е. имя .BGI-файла без расширения).
Заголовок функции:
Function GetDriverName : String;
Программу, в которой используется функция GetDriverName вы найдете в примере 11.2
Функция GetMaxMode
Возвращает код предельно допустимого графического режима.
Заголовок функции:
Function GetMaxMode : Integer;
Функция GetMaxMode позволяет определить код предельного графического режима (загруженного драйвера), в котором смог бы работать используемый адаптер (см. табл. 11.2). Этот код затем можно передать 11роцедуре SetGraphMode.
Программу, в которой используются функции GetModeName, GetDriverName и GetMaxMode, можно видеть в примере 11.2 (рис. 11.2).
В этой программе переход в графический режим инициируют операторы:
i:=detect;
initgraphfi,j, " );
Проверка, не было ли ошибок при переходе в графический режим, с юуществляется так:
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err)) else ...
Такая проверка должна проводиться в каждой программе, в которой используется графический режим (именно для этого предназначена функция GraphResult).
Глава 11. Использование ресурсов модуля GRAPH
261
I
Interne
Пример 11.2
Рекин; 64(1 x ZUO EGA
Реяим.640 x 350 EGA
Рекин:640 x 480 VGA
Драйвер ' EGAlKJft:
Драйвер:EGAVGA;
Драйвер;EGnUGn:
C1 IS, E di .Search Run JXomPl U UgbuqlJalP-Qli2 .
= []	\MOM£OK~l\PA3CAL\nPOrPA~l\CH2_10~l\MODENAME. PAS
program ModDrive; uses graph;
var i,j,k,Err:integer;
begi n
i:-detect;
i ni tgraphCi , j , ' * );
Err:=GraphResult;
If Err <> grOK then
Wri teLnCGraphErrorMsgCErrll else for k:=0 to GetMaxMode do begi n
Wri teLnCДрайвер:’,GetDri verName,*; Режим: ’,GetModeName(k)); end:
readin;
CloseGraph;
end.
4:1
f! He 1 p f 2 save f 3 open ' a1£^f9 compile" f> Make , '’aT^-ffIO Ukscal menu
Рис. 11.2. Информация о драйвере и режиме
Далее с помощью функций GetModeName, GetDriverName GetMaxMode выясняется нужная информация (имя файла драйвера перечень допустимых графических режимов), которая затем выводите на экран.
После запуска подобной программы инициируется графический ре жим и результаты работы выводятся на графический экран. Для тог-чтобы увидеть эти результаты, лучше всего добавить в программу one ратор ReadLn без параметров. В результате программа, ожидая ввода клавиатуры, приостанавливает работу, предоставляя при этом возмож ность посмотреть, что отображено на экране. Для того чтобы продол жить работу программы, достаточно нажать клавишу <Enter>.
В конце вызывается процедура CloseGraph, которая завершает раб< ту видеоадаптера в графическом режиме.
Результат работы программы (т.е. вывод на экран) показан там же.
Процедура GetModeRange
Возвращает диапазон кодов допустимых графических режимов дг указанного драйвера.
Заголовок процедуры:
Procedure GetModeRange (Driver : Integer; Var MinMode, MaxMode : Integer);
где Driver — код используемого графического драйвера (см табл. 11.1);
262
Turbo Pascal: учитесь программировав
MinMode — код самого “младшего” режима;
MaxMode — код предельного режима.
Если заданное значение параметра Driver окажется недопустимо, переменные MinMode и MaxMode вернут значения -1.
Перед обращением к процедуре GetModeRange переходить в графический режим необязательно.
Программу, в которой используется процедура GetModeRange, можно видеть в примере 11.3 (рис. 11.3).
Пример ИИ.З
Рис. 11.3. Допустимые значения режимов для различных драйверов
В этой программе организован цикл, в теле которого вызывается процедура GetModeRange, причем значение параметра цикла передается процедуре в качестве значения ее параметра Driver. Возвращенные этой процедурой значения минимального и максимального режимов выводятся на экран для каждого драйвера построчно. В результате формируется таблица значений. Для того чтобы сделать эту таблицу яснее, в программе объявлена константа-массив, элементы которого представляют собой значения типа STRING, содержащие буквенные обозначения драйверов. Эти обозначения выводятся в первом столбце нашей таблицы.
Для того чтобы проверить, как процедура GetModeRange отреагирует на недопустимое значение кода драйвера, количество циклов увеличено до 11 (1..10 — допустимые коды драйверов). Как и положено, в ответ на сообщенный ей недопустимый код (код 11) процедура GetModeRange возвратила для параметров MinMode и MaxMode значения —1.
Глава 11. Использование ресурсов модуля GRAPH
263
Необходимо понимать, что в этом примере все драйверы поочередг, загружаются на одном компьютере, и данная программа проверяет, i кие режимы доступны для того или иного драйвера при использовани его с определенным видеоадаптером (в данном случае это SVGA). Судя г полученной таблице (если сравнить ее с табл. 11.2), этот адаптер не по держивает отдельные режимы некоторых драйверов.
Процедура CloseGraph
Восстанавливает видеорежим (текстовый), использовавшийся до ш рехода в графический ражим.
Заголовок процедуры:
Procedure CloseGraph;
При этом (здесь имеет место отличие CloseGraph от проце/iypi RestoreCRTMode) освобождается память, занятая различными графич< скими буферами и драйвером.
Функция InstallUserDriver
Позволяет добавить в ВС129-систему графический драйвер для н< стандартного видеоадаптера.
Заголовок функции:
Function InstallUserDriver (FileName: string;
AutoDetectPtr: pointer): integer;
где FileName — строка, содержащая имя файла (и путь) нового драй вера;
AutoDetectPtr—указатель, позволяющий вызвать функцию автооп ределения (видеоадаптера), которая может прилагаться к новому драй веру. Эта функция не имеет параметров и возвращает значение типе Integer.
Если имеется нестандартный видеоадаптер30, к которому изготови тель приложил графический драйвер, функция InstallUserDriver предо< тавляет возможность воспользоваться таким адаптером. Существуе два способа подключить драйвер, приложенный к нестандартному ви деоадаптеру.
Во-первых, можно вызвать функцию InstallUserDriver, просто зада! при этом имя файла драйвера в качестве значения параметра FileNam и NIL— в качестве значения параметра функции AutoDetectPtr, а зате передать возвращенное ею значение процедуре InitGraph как парамет* Driver.
29 BGI (Borland Graphic Interface — графический интерфейс фирмы Borland)
30 Нестандартный видеоадаптер— тот, для которого не подходит ни один г имеющихся драйверов (см. табл. 11.1).
264	Turbo Pascal: учитесь программировать
Значение NIL, переданное функции InstallUserDriver как параметр AutoDetectPtr, указывает, что для данного драйвера функция автоопределения не предусмотрена. Однако необходимо понимать, что программа, в которой графический режим инициируется с указанием конкретного драйвера, сможет работать только с соответствующим видеоадаптером. Иными словами, такой подход резко ограничит возможности ее применения.
Другой, более общий способ использования этого драйвера состоит в том, чтобы вызвать (из процедуры InitGraph) функцию автоопределения нашего нестандартного видеоадаптера — как часть процесса определения аппаратуры, инициируемого этой процедурой. Если известный системе (т.е. такой, для которого имеется драйвер) видеоадаптер обнаружен не будет, функция вернет значение -11 (grError — общая ошибка). В противном случае возвращенное значение представляет собой код режима, который должен использоваться для этого видеоадаптера по умолчанию.
У функции автообнаружения нет параметров, она возвращает единственное значение типа Integer и в ее заголовке должно использоваться зарезервированное слово FAR (директива компилятора, позволяющая передать эту подпрограмму в качестве параметра другой подпрограмме). При инсталляции драйвера (с помощью функции InstallUserDriver) вы передаете адрес функции автообнаружения как значение параметра AutoDetectPtr (вместе с именем файла в качестве значения параметра FileName). Адрес функции автообнаружения представляет собой ее имя, преобразованное с помощью оператора @ в указатель.
Цвета, палитры, заполнения
Вывод изображений на экран в Turbo Pascal может осуществляться с использованием различных цветов. Набор цветов, доступных в том или ином режиме, называется палитрой. Кроме того, если речь идет о заполнении экрана или какой-либо замкнутой фигуры, то это можно осуществить как сплошным фоном определенного цвета, так и некоторым узором. Использованию цветов, палитр и заполнений и посвящен данный раздел.
Процедура SetColor
Устанавливает текущий цвет—один из цветов используемой палитры.
Заголовок процедуры:
Procedure SetColor(Colot : Word);
где Color — новый текущий цвет.
Глава 11. Использование ресурсов модуля GRAPH
265
Значения, которые может принимать параметр Color, опреде । набором определенных в модуле GRAPH констант. Перечень этих кон стант, а также соответствующих кодов, можно видеть в табл. 11.4.
Таблица 11.4. Константы и коды цветов
Имя константы Код	Цвет
Black	0	Черный
Blue	1	Темно-синий
Green	2	Темно-зеленый
Cyan	3	Бирюзовый
Red	4	Красный
Magenta	5	Фиолетовый
Brown	6	Коричневый
LightGray	7	Светло-серый
DarkGray	8	Темно-серый
LightBlue	9	Синий
LightGreen	10	Светло-зеленый
LightCyan	11	Светло-бирюзовый
LightRed	12	Розовый
LightMagenta	13	Малиновый
Yellow	14	Желтый
White	15	Белый
Blink	128	Мерцание
Например, обращение SetColor(2) сделает текущим цвет с кодом (Green — зеленый) из палитры.
Нетрудно заметить, что представленная выше таблица, совпадает г аналогичной таблицей из модуля CRT.
Функция GetColor
Возвращает код текущего цвета.
Заголовок функции:
Function GetColor : Word;
Данная функция вернет значение, которое ранее было задано фуЩ-j цией SetColor, либо которое используется по умолчанию.
Функция GetMaxColor
Возвращает наибольший код цвета, который может быть переда!’ процедуре SetColor в качестве параметра.
266
Turbo Pascal: учитесь программиро! с
Заголовок функции:
Function GetMaxColor : Word;
Значение, возвращаемое функцией, определяется типом адаптера и юпользуемым драйвером. Например, для адаптера SVGA с режимом, ,-становленным с использованием автообнаружения, данная процедура )ернет значение 15.
Однако, если для этого же адаптера задать режим CGA InitGraph(i, j,''); , где i=l и j=5), GetMaxColor возвратит значение 1 (т.е. > гот режим поддерживает всего два цвета — с кодами О и 1).
Процедура SetBkColor
Устанавливает цвет фона — один из цветов используемой палитры.
Заголовок процедуры:
Procedure SetBkColor(Color : Word);
где Color — новый цвет фона;
Цвет фона определяется не для окна, а для всего экрана. Коды цветов фона могут находиться в диапазоне от О до 15, в зависимости от используемых драйвера и графического режима. Например, обращение SetBkColor (2) окрасит фон в цвет, код которого 2 (Green — зеленый).
Функция GetBkColor
Возвращает значение, представляющее собой код используемого цвета фона.
Заголовок функции:
Function GetBkColor : Word;
Значения, которые может вернуть функция, принадлежат диапазону О.. 15. В этом отличие графического режима от текстового. В текстовом режиме для фона можно использовать только первую половину набора доступных цветов.
Процедура GetPalette
Возвращает коды цветов из текущей палитры, а также ее размер.
Заголовок процедуры:
Procedure GetPalette(Var Palette : PaletteType);
где Palette— параметр-переменная, принадлежащая типу PaletteType, который объявлен в модуле GRAPH. Вот описание этого типа (а также константы MaxColors):
const
MaxColors = 15;
type
PaletteType = record
Глава 11. Использование ресурсов модуля GRAPH	267
Size : Byte;
Colors : arrayfO..MaxColors] of Shortint;
end;
Тип PaletteType представляет собой запись, поля которой имеют следующий смысл:
Size — число цветов в палитре, доступной для используемых драйвера и режима;
Colors — массив, содержащий числовые коды всех цветов (от О до 15)
Из массива Colors в каждом конкретном случае (в зависимости от драйвера и режима) используется набор кодов от О и до Size-1. Насколько значение Size-1 близко к MaxColors (т.е. к 15). определяется используемыми драйвером и режимом.
Процедура SetPalette
Заменяет один из цветов в палитре новым цветом.
Заголовок процедуры:
Procedure SetPalette(Cut : Word; Paste : Shortint);
где Cut — код цвета в палитре (заменяемого);
Paste — код нового цвета (заменяющего).
Процедура заменяет цвет, ассоциированный с кодом Cut, на цвет, код которого Paste. Например, обращение SetPalette(9,11) (или SetPalette (9, LightCyan), что то же самое) меняет цвет в палитре с кодом 9 (синий) на цвет с кодом 11 (светло-бирюзовый). После этого обращения все пиксели изображения на экране, которые до этого светились синим цветом, поменяют цвет на светло-бирюзовый.
Если процедуре передать недопустимый параметр, то функция GraphResult вернет значение grError (общая ошибка, см. табл. 11.3) и палитра останется неизменной.
Процедура SetPalette может использоваться с драйверами для видеоадаптеров EGA, EGA64 или VGA, однако не подходит для IBM 8514.
Процедура SetRGBPalette
Изменяет компоненты палитры при использовании драйверов VGA или IBM 8514.
Заголовок процедуры:
Procedure SetRGBPalette(ColNum, RedVal, GreenVal, BlueVal : Integer)
где ColNum — код одного из цветов палитры;
RedVal, GreenVal. BlueVal— определяют интенсивность соответственно красной, зеленой и синей составляющих цвета, код которого ColNum.
Для драйвера IBM 8514 значение ColorNum может принимать значения О..255. Для VGA ColorNum принимает значения О.. 15.
268
Turbo Pascal: учитесь программировать
При задании интенсивности в параметрах RedValue, GreenValue и BlueValue используются только шесть старших бит их младших байтов.
Процедура SetAIIPalette
Изменяет одновременно несколько цветов в палитре (или все сразу) на заданные.
Заголовок процедуры:
Procedure SetAIIPalette(Var Palette);
где Palette — нетипизированный параметр-переменная, первый байт которого определяет размер палитры, а остальные— коды цветов палитры:
Для замены цветов в палитре достаточно изменить нужным образом значения соответствующих байтов. Диапазон допустимых значений для этих байтов— от —1 до MaxColors. Если какой-либо из байтов будет содержать значение —1, то это является признаком, что данный цвет не меняется.
Процедура SetAIIPalette работает с теми же адаптерами, что и проце-iypa SetPalette (см. выше)
Функция GetPaletteSize
Возвращает значение, информирующее, сколько цветов (максимум) может содержать палитра (при данном драйвере и режиме).
Заголовок функции:
Function GetPaletteSize : Integer;
Функция GetDefaultPalette
Возвращает сведения о содержимом палитры, используемой по умолчанию.
Заголовок функции:
Function GetDefaultPalette(Var Palette : PaletteType);
где Palette — значение типа PaletteType (о типе PaletteType см. в раз-(еле “Процедура GetPalette”).
Палитра, о которой идет речь, создается графическим драйвером при инициализации графической системы (при обращении к процедуре InitGraph).
Процедура SetFillStyle
Определяет шаблон и цвет заполнения.
Заголовок процедуры:
Procedure SetFillStyle(Pattern : Word; Color : Word);
где Pattern — шаблон заполнения (см. табл. 11.5 ниже);
"лава 11. Использование ресурсов модуля GRAPH	269
Color — цвет заполнения.
Заполнение— операция, позволяющая некий замкнутый контур красить сплошным цветом (например, цветом фона или текущим цветом) либо заполнить его некоторым узором (периодически повторяющимся).
В модуле GRAPH имеется несколько готовых (или, если угодно “стандартных”) шаблонов заполнения, с каждым из которых ассоцииро!
вана мнемоническая константа. Перечень этих шаблонов представлен в табл. 11.5.
Таблица 11.5. Константы, коды и образцы заполнений
Имя константы	Код
EmptyFill	О
SolidFill	1
LineFill	2
LtSlashFill	3
SlashFill	4
BkSlashFill	5
LtBkSlashFill	6
HatchFill	7
XHatchFill	8
InterleaveFill	9
WideDotFill	10
CloseDotFill	11
UserFill	12
Заполнение
Сплошное заполнение цветом фона (без узора)
Сплошное заполнение текущим цветом (который • танавливается процедурой SetColor)
Шаблон заполнения, определенный пользователем
По умолчанию используются константа SolidFill (код 1) и цвет с максимальным номером из текущей палитры. Шаблон и цвет, определен-
270
Turbo Pascal: учитесь программировать
ni.ie процедурой SetFillStyle, применяются всеми процедурами и функциями, в которых используется операция заполнения.
Если параметр Pattern имеет значение UserFill (код 12). используется шаблон, определенный пользователем (с помощью процедуры SetFillPattern, см. далее).
Если процедуре SetFillStyle передать недопустимые параметры, то функция GraphResult вернет значение grError (общая ошибка, см. габл. 11.3) и текущие установки заполнения изменены не будут.
Процедура SetFillPattern
Позволяет определить собственный шаблон заполнения.
Заголовок процедуры:
Procedure SetFillPattern(Pattern : FillPatternType; Color : Word);
где Pattern — значение, принадлежащее типу FillPatternType и опре-еляющее пользовательский шаблон заполнения;
Color — цвет заполнения.
Тип FillPatternType определен в модуле GRAPH. Его описание выглядит следующим образом:
type
FillPatternType = array [1..8] of Byte;
Тип FillPatternType. представляющий собой массив из восьми значений типа Byte, позволяет управлять свечением матрицы пикселей 8x8 (8 байтов, в каждом из которых по 8 бит). Если какой-либо из этих 64 бит имеет значение 1, соответствующий пиксель светится; если О — нет. Когда инициируется операция заполнения, экран как бы делится на множество ячеек, каждая из которых представляет собой описанную выше матрицу. При этом светящиеся или несветящиеся пиксели каждой матрицы образуют на экране сплошной повторяющийся узор. Пару образцов созданных таким образом заполнений можно видеть на рис. 11.4.
о 94 66 ББ ББ ББ 94
О
I13 13 13 13П1] 13 13 13 1313 13ПП13 13 13 1313 13131313□□ I13 13 13 13 ПП 13 13 13 13 13 13 13 ООО 13 13 13 13 13 13 13 13 13 H3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3 11313131313131313I3I3I3I3I3I3I3I3I31313131313131313 Ii3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3i3 113 13 013131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 H3I3I3I3I31313131313131313131313131313131313131313 10131313131313 01313 013131313131313 013131313 013 113131313131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 113131313131313131313131313131313131313131313131313 * П1313131313131313131313131313131313 11313131313131313131313131313131313 11313131313131313131313131313131313 113131313131313131313131313131313 О 11313131313131313131313131313131313 11313131313I3I3I3I3I3I3I3I3I3I3I3I3 11313131313131313131313131313131313 11313131313131313131313131313131313 11313131313131313131313131313131313 11313131313131313131313131313131313
Рис. 11.4. Создание собственного шаблона заполнения
лава 11. Использование ресурсов модуля GRAPH
271
Здесь показаны два шаблона с матрицами 8x8. Десятичные значе ния соответствующих байтов матриц представлены сбоку.
Процедура GetFillPattern
Возвращает текущий шаблон заполнения, установленный ранс процедурой SetFillPattern.
Заголовок процедуры:
Procedure GetFillPattern(Var FillPattern : FillPatternType);
где Pattern параметр-переменная, принадлежащая типу FillPattemTyp (см. выше).
Если до этого обращений к SetFillPattern не было, процедур GetFillPattern возвращает массив, каждый из элементов которого име*= значение 255 (или FF в 16-ричной системе). Иными словами, биты вс байтов здесь имеют значение 1 и, следовательно, все пиксели на экра] светятся, т.е. имеет место заполнение сплошным цветом (текущим-константа SolidFill).
Процедура GetFillSettings
Возвращает те!сущие цвет и шаблон заполнения.
Заголовок процедуры:
Procedure GetFillSettings(Var Fill : FillSettingsType);
где Fill — параметр-переменная, принадлежащая типу FillSettingsiyp который определен в модуле GRAPH. Описание этого типа:
type
FillSettingsType = record
Pattern	: Word;	{шаблон}
Color	: Word;	{цвет}
end;
Тип FillSettingsType представляет собой запись, в полях Pattern Color которой содержится информация соответственно о теютцем ша лоне и цвете заполнения. Эти шаблон и цвет были заданы ранее с пом< щью процедур SetFillPattern, SetFillStyle и SetColor. С помощью этих № процедур их можно изменить в случае необходимости.
Если значение поля Pattern равно UserFill (т.е. 12), вам придется во' пользоваться процедурой SetFillPattern, чтобы определить свой шабж заполнения.
Координаты и окна
С такой характеристикой графического режима, как разрешение, м уже знакомы. Разрешение определяется количеством светящихся точс (или пикселей) по горизонтали и вертикали. Положение той или ин1-
272
Turbo Pascal: учитесь программирово
точки на экране определяется ее порядковыми номерами (или координатами) по горизонтали и вертикали, которые отсчитываются от левого верхнего угла экрана, начиная с О31. В этом разделе мы познакомимся с процедурами и функциями, позволяющими переместить указатель текущей позиции (что-то наподобие курсора в текстовом режиме, только невидимое на экране) в любую точку экрана или выяснить, где он в настоящий момент находится.
Вывод можно осуществлять не на весь экран, а только в пределах некоторой его области, которая называется окном. В этом разделе мы также научимся использовать процедуры и функции, создающие такие окна и управляющие ими.
Функции GetX и GetY
Возвращают координаты по горизонтали и вертикали (или X- и Y-координаты) указателя текущей позиции.
Заголовки функций:
Function GetX : Integer;
Function GetY : Integer;
Координаты GetX и GetY отсчитываются относительно левого верхнего угла активного окна, начиная с О.
Функции GetMaxX и GetMaxY
Возвращают текущие значения разрешений (т.е. число пикселей32) ио горизонтали и вертикали соответственно.
Заголовки функций:
Function GetMaxX : Integer;
Function GetMaxY : Integer;
Возвращаемые значения зависят от используемых графического драйвера и режима.
Процедура MoveTo
Перемещает указатель текущей позиции в точку с заданными координатами.
Заголовок процедуры:
Procedure MoveTofX, Y : Integer);
где X и Y — координаты точки на экране, в которую будет перемещен указатель.
1 Здесь, вероятно. уместно напомнить, что позиции символов в текстовом режиме считаются также от левого верхнего угла экрана (или текущего окна), но I начиная с 1.
>г Пиксель — точка на экране, свечением которой можно управлять.
Г лава 11. Использование ресурсов модуля GRAPH	273
Отсчет координат ведется относительно верхнего левого угла актив ного окна, а если окон нет, — относительно верхнего левого утла экрана.
Процедура MoveRel
Перемещает указатель на заданное расстояние (определяемое прира щениями координат Хи Y) относительно его текущего местоположения.
Заголовок процедуры:
Procedure MoveRel(Dx, Dy : Integer);
где Dx и Dy — приращения текущих координат Хи Y.
Например, если указатель находится в точке с координатами (X, У), то MoveRel задаст для него новые координаты: (X+Dx, Y+Dy).
Чем процедура MoveRel отличается от процедуры MoveTo, нагляднс демонстрирует рис. 11.5.
Рис. 11.5. Процедура MoveTo ведет отсчет от левого верхнего угла экрана (параметры X и Y). а процедура MoveRel — от указателя текущей позиции (параметры Dx и Dy)
Большой прямоугольник здесь представляет площадь экрана. Предположим, указатель требуется переместить из точки А в точку В. Так вот, если для этой задачи воспользоваться процедурой MoveTo. данной процедуре в качестве параметров придется сообщить величины X и У. А процедура MoveRel переместит указатель в нужное место, если ей в качестве параметров сообщить величины Dx и Dy (см. рис. 11.5).
Процедура SetViewPort
Создает окно на экране в графическом режиме.
Заголовок процедуры:
Procedure SetViewPort(xl, yl, x2, y2 : Integer; Clip : Boolean);
где (XI, У1) — координаты, определяющие верхний левый угол окна;
274
Turbo Pascal: учитесь программироват
(Х2, Y2) определяют нижний правый угол окна;
Clip — параметр, определяющий, должно ли отображаться на экране то. что не помещается в окне.
Параметр Clip может принимать два значения — TRUE и FALSE. Эти значения можно задавать, используя две, определенные в модуле GRAPH, константы — ClipOn и ClipOff:
const
ClipOn =True;
ClipOff =False;
Если параметр Clip имеет значение ClipOff, изображение будет представлено на экране полностью. Если параметр Clip имеет значение ClipOn, то часть изображения, не помещающаяся в окне, обрезается по его краю. Как >то выглядит, демонстрирует рис. 11.6.
Здесь изображены два окна с разным значением параметра Clip. Для левого окна Clip равен ClipOff, а для правого— ClipOn. Изображение линии начинается в окне и закан-
Рис. 11.6. Действие параметра Clip
чивается за его пределами. Для первого окна (ClipOff) линия отображается полностью, для второго — обрезается по его краю.
После того как окно создано, координаты его верхнего левого утла становятся равны (О, О).
Для процедур и функций, что-либо отображающих, перемещающих указатель или выясняющих местоположение указателя (таких как GetX, OutText. Rectangle, MoveTo и т.д.) координаты отсчитываются относи
тельно активного окна. Для процедур, устанавливающих или выясняющих данные о режимах, например InitGraph, GraphDefaults или SetGraphMode, областью действия является весь графический экран. Характеристики активного окна можно выяснить, обратившись к процедуре GetViewSettings (см. дальше).
Процедура GetViewSettings
Возвращает параметры активного окна.
Заголовок процедуры:
Procedure GetViewSettings(Var Viewport : ViewPortType);
где ViewPort — переменная, принадлежащая типу ViewPortType, который объявлен в модуле GRAPH.
Вот как выглядит описание этого типа:
type
ViewPortType = record
xl, yl, x2, y2 : integer;
Г лава 11. Использование ресурса модуля GRAPH
275
Clip : Boolean;
end;
Фигурирующие здесь переменные XI, X2, Yl, Y2 и Clip имеют тот  смысл, что и параметры процедуры SetViewPort (см. выше).
Процедура ClearDevice
Очищает экран и перемещает указатель текущей позиции в левый верхний угол.
Заголовок процедуры:
Procedure ClearDevice;
При очистке экран заполняется цветом фона, установленным процедурой SetBkColor.
Процедура ClearViewPort
Очищает активное окно. Если окна на экране не создавались, очищается весь экран.
Заголовок процедуры:
Procedure ClearViewPort;
При этом фон заполняется цветом из текущей палитры, код которогс равен нулю, а указатель перемещается в верхний левый угол.
Процедура GetAspectRatio
Возвращает два числа, из которых может быть вычислен коэффициент коррекции изображения для данного графического режима.
Заголовок процедуры:
Procedure GetAspectRatio(Var XAsp, YAsp : Word);
где XAsp и YAsp — возвращаемые переменные, соотношение которых равно коэффициенту коррекции.
Можно сказать, что величины XAsp и YAsp позволяют вычислить соотношение между высотой и шириной одного пикселя для используемо го графического режима.
Мы уже знаем, что изображение на экране в графическом режиме формируется из пикселей— точек, свечением которых можно управлять. Количество пикселей по горизонтали и вертикали определяется разрешением. А разрешение, в свою очередь, определяет используемый графический режим. Например, режим VGAHi обеспечивает разрешение 640x480. Это значит, что по горизонтали длина экрана составляет 640 точек, а по вертикали — 480.
Однако, если взять линейку и измерить экран по высоте и ширине, а затем посчитать соотношение измеренных величин, полученное значе ние может не совпасть с соотношением чисел точек по горизонтали и
276
Turbo Pascal: учитесь программировать
вертикали. Иными словами, пиксель представляет собой вовсе не квадрат, а прямоугольник — его высота и ширина не равны!
Теперь предположим, что нам необходимо отобразить на экране квадрат. Линии, образующие его горизонтальные и вертикальные стороны, мы задаем содержащими равное число пикселей (для квадрата это напрашивается). Однако на экране отобразился не квадрат, а прямоугольник. Дала себя знать разница в высоте и ширине пикселя. А теперь вспомним, что существует множество графических режимов, каждый из которых способен исказить наш квадрат по-своему. Как же при таком разнобое сделать так, чтобы программа отображала на экранах различных мониторов и при любом разрешении именно квадраты, а не прямоугольники (или, например, окружности, а не эллипсы)? Для этого и предназначен коэффициент коррекции, который позволяет вычислить процедура GetAspectRatio.
Вот программа, в которой используется процедура GetAspectRatio и которая вычерчивает два квадрата со сторонами, содержащими одинаковое число пикселей (так задано). Только первый квадрат отображается с учетом значений, возвращенных процедурой GetAspectRatio, а второй — нет. Для примера выбран режим О драйвера EGA. Текст этой программы содержится в примере 11.4 (рис. 11.7). Здесь же можно видеть результаты работы программы.
L
nternet
Пример 11.4
Fi1е £di t search Run Compile Debug Tools optionswindow Help g=l>]—'	\МОИДОК~1\РА5СА1_\ПРОГРА~1\СН2_10~1\А5РЕСТК. PAS =———1=E 1]=^
Program AspectRatio;	n
Uses Graph; var i,j,k,Err:integer; x,y:word;
begi n
i:=EGA; j:=0;
InitGraph(i.j,' '
I Err:-GraphResul t;
If Err <.> grOK then
Wri tei_n(GraphErrorMsgCErr}) else	______________________________
begi n	_
Ge t As p e c t P.a t i о Cx, y); k-=50;
Rectangle(50,50,50+Round(k*y/x),50+k};	>
Rectangle (250,50,250+k, 50+kj;	’;
P.eadLn;
CloseGraph;
end;	------------------------------ 3
jjend.	, L
-o----- 13.4 ----!	.	“
Fl ielo F2. Save f 3 Iper r Compi7 ь 17 ~ Make t'4 10 1'	• m
Puc. 11.7. Без процедуры GetAspectRatio построить правильную фигуру сложно
Значения, которые возвращает процедура GetAspectRatio, присваиваются переменным X и У. Значение переменной К определяет сторону квадрата. Иными словами, если бы мы захотели вычертить на экране
лава 11. Использование ресурсов модуля GRAPH
277
фигуры, большие тех, что на рис. 11.7, то для этого было бы достаточно присвоить переменной К соответствующее значение.
Квадрат на экране отображается с помощью процедуры Rectangle (с которой мы познакомимся в разделе “Незаполненные фигуры” дальше). В этой процедуре первые два параметра задают левый верхний угс прямоугольника, а вторая пара — нижний правый угол.
У второго квадрата (при создании которого не используется коэффициент коррекции) координаты правого нижнего угла относительно координат левого верхнего угла просто увеличиваются на величину к (которая соответствует стороне квадрата).
У первого квадрата величина верхней и нижней сторон (т.е. значение К) корректируется с помощью выражения Round(k*y/x). Значения Хи У нам предоставила функция GetAspectRatio. Их соотношение представ ляет собой коэффициент коррекции, умножение на который величин’ К должно сделать верхнюю и нижнюю стороны квадрата на экране (приблизительно) равными правой и левой. Использованная здесь функция Round (из модуля SYSTEM) округляет полученное значение f целого, поскольку параметры функции Rectangle должны представлять собой целые значения.
Процедура SetAspectRatio
Позволяет изменить коэффициент коррекции изображения, задан ный по умолчанию. (Можно сказать, что она позволяет "откорректировать" коэффициент коррекции.)
Заголовок процедуры:
Procedure SetAspectRatio(XAsp, YAsp : Word);
где XAsp и YAsp— сообщаемые процедуре значения, соотношени которых равно коэффициенту коррекции.
Иными словами, данная процедура позволяет искусственно исказить изображение на экране, вытянув (или сжав) его по вертикали. Предположим, имеется программа, в которой осуществлен переход ц графический режим, сделаны все необходимые установки, а далее имеется последовательность операторов:
GetAspectRatio(х,у);
for i:=0 to 20 do
begin
S etAspectRatid(x-i*400,y);
Circle(GetMaxX div 2,GetMaxX div 2, 150);
end;
Здесь организован цикл, в теле которого последовательно уменыпа ется коэффициент коррекции и для каждого полученного коэффициент вычерчивается своя окружность.
278
Turbo Pascal: учитесь программирово
В результате на экране отображается последовательность фигур, постепенно превращающихся из окружности во все более плоский эллипс. Как это выглядит на экране, демонстрирует рис. 11.8.
Рис. 11.8. По горизонтали все размеры неизменны, но по вертикали их можно сжимать или растягивать
Использованная здесь процедура Circle33 (с которой мы познакомимся в разделе “Незаполненные фигуры” дальше) служит для отображения на экране окружности. Первые два ее параметра определяют координаты центра, а третий — радиус.
Точки И ЛИНИИ
До сих пор речь шла о процедурах и функциях модуля GRAPH, настраивающих экран нужным образом перед выводом графических изображений (если на экран и выводились какие-то изображения, то это делалось только для того, чтобы продемонстрировать действие тех или иных настроек). Теперь же наступило время познакомиться со средствами, позволяющими что-то отображать на экране. В данном разделе речь пойдет о процедурах и функциях, выводящими на экран самые простые изображения —точки и линии.
При использовании процедуры Circle коррекция производится автоматически, т.е. в любом графическом режиме всегда получится окружность, а не эллипс.
I лава 11. Использование ресурсов модуля GRAPH	279
Функция GetPixel
Возвращает значение, соответствующее коду цвета пикселя, ко наты которого (X, Y).
Заголовок функции:
Function GetPixel(Xf Y : Integer) : Word;
где Хи Y — координаты;
Значение, возвращаемое функцией, представляет собой один г дов цветов, которые можно видеть в табл. 11.4.
Процедура PutPixel
Отображает точку в заданной позиции заданным цветом.
Заголовок процедуры:
Procedure PutPixel(X, Y : Integer; Color : Word);
где X и Y— координаты, указанные относительно верхнего лс угла окна (или экрана);
Color — код цвета.
Предположим, в программе, в которой уже инициирован гра< ский режим, далее имеются следующие операторы:
For i:=l to 100 do
for j:=l to 50 do
PutPixel(100+4*i,100+4*j,15);
Здесь организуются два вложенных цикла, в теле которых вызьг ся процедура PutPixel. Данная процедура выводит на экран матриц-чек 100x50. Чтобы получилась именно матрица точек, а не сплои прямоугольник, местоположение каждой очередной точки относите предыдущей сдвигается на четыре пикселя. Как все это выглядит, монстрирует рис. 11.9.
280
Turbo Pascal; учитесь программирс
Процедура Line
Отображает прямую линию между двумя точками, координаты кото-ых заданы в качестве параметров процедуры.
Заголовок процедуры:
Procedure Line(Xl, Yl, Х2, Y2 : Integer);
где (Xl, Y1] и (X2, Y2) — координаты начала и конца линии.
Линия отображается с использованием стиля и толщины, опреде-енных процедурой SetLineStyle (см. далее), и цвета, заданного процедурой SetColor.
Рассмотрим пример. Предположим, в программе, в которой уже шициирован графический режим, далее имеются следующие строки:
For i:=l to 100 do
Line(100+4*i,100,100+4*i,300);
Здесь организуется цикл, в теле которого вызывается процедура Line. Данная процедура выводит на экран последовательность вертикальных линий. Чтобы получилась именно последовательность линий, а не сплошной прямоугольник, местоположение очередной линии относительно предыдущей сдвигается вправо на четыре пикселя. Как это
Для того чтобы определить способ наложения вычерчиваемых линий на существующее на экране изображение (если таковое имеется), можно использоваться процедурой SetWriteMode. Речь о ней пойдет дальше.
Процедура LineTo
Отображает прямую линию от текущей позиции (точки, в которой Находится указатель) до точки с заданными координатами.
Заголовок процедуры:
Procedure LineTofX, Y : Integer);
где Хи Y— координаты точки;
Глава 11. Использование ресурсов модуля GRAPH
281
Линия отображается с использованием стиля и толщины, опре; ленных процедурой SetLineStyle (см. далее); при этом используется цвет» заданный с помощью процедуры SetColor.
Процедура LineTo очень удобна для вычерчивания различных много, угольников или ломанных линий. Попробуем отобразить на экране извольный многоугольник. Предположим, в программе, в которой уже инициирован графический режим, далее имеются следующие операторы;
MoveTo(100,100);
LineTo(200,100);
LineTo(250,150);
LineTo(150,250);
LineTo(50,150);
LineTo(100,100);
Первой здесь вызывается процедура MoveTo, которая перемещае!
указатель текущей позиции в заданную точку экрана. Затем последовательно пять раз вызывается процедура LineTo, которая каждый раз от<>-
Рис. 11.11. Вычерченные на экране линии образовали многоугольник
бражает очередную сторону нашего многоугольника. Чтобы многоугольник получи., замкнутым, при вычерчивании последи стороны многоугольника процедуре Line' должны быть переданы те же координаты, ко торые вначале были сообщены процедур MoveTo. Полученный в итоге многоугольник можно видеть на рис. 11.11.
Для определения способа наложения вы черчиваемых с помощью процедуры Line' линий на уже имеющееся на экране изображ ние, существует процедура SetWriteMode. этой процедурой мы познакомимся дальше.
Процедура LineRel
Отображает прямую линию от текущей позиции и до точки, коорд.-наты который определены относительно положения указателя (т.е. тс кущей позиции) -
Заголовок процедуры:
Procedure LineRel(Dx, Dy : Integer);
где Dx и Dy — приращения координат текущей позиции X и У.
Например, если указатель находится в точке с координатами (X, то процедура MoveRel переместит его в точку с координатами (Х+Г Y+Dy) и при этом между двумя точками будет вычерчена прямая линг
Процедура LineRel, так же как, и процедура LineTo (см. выше), п красно подходит для вычерчивания различных многоугольников И ломанных линий. Попробуем отобразить на экране ломанную лини*
282
Turbo Pascal: учитесь программиро*
Предположим, в программе, в которой уже инициирован графический режим, далее имеются следующие операторы:
MoveTof100,100);
for i:=l to 8 do
begin
If i mod 2=0 then j:=-200 else j:=200;
LineRel(i+50,j);
end;
Первой здесь вызывается процедура MoveTo, которая перемещает указатель текущей позиции в заданную точку экрана. Затем организуется цикл, в теле которого вызывается процедура MoveRel, вычерчивающая на экране очередной участок ломанной линии. В какую сторону направить очередной участок— вверх или вниз— определяется с помощью условного оператора IF. Полученную в итоге ломанную линию можно видеть на рис. 11.12.
Рис. 11.12. Ломанная линия, полученная с помощью процедуры LinePel
Для определения способа наложения вычерчиваемых с помощью процедуры LineRel линий на уже имеющееся на экране изображение существует процедура SetWriteMode. С этой процедурой мы познакомимся дальше.
Процедура SetLineStyle
Задает новый стиль линии.
Заголовок процедуры:
Procedure SetLineStyle(Type, Pattern, Thick : Word);
где Type — тип линии;
Pattern — шаблон линии;
Thick — толщина линии.
Глава 11. Использование ресурсов модуля GRAPH
283
Тип линии задается с помощью набора определенных в мо GRAPH констант. Перечень этих констант, соответствующие им вые коды и образцы линий представлены в табл. 11.6.
Таблица 11.6. Константы, коды и образцы типов линий		
Имя константы	Код	Образец
SolidLn	0	Сплошная линия
DottedLn	1	Линия из точек
CenterLn	2	Штрих-пунктир
DashedLn	3	Пунктир
UserBitLn
Стиль линии, определенный пользователе*
Рис. 11.13. Таким образом можно создать линию на любой вкус
Если переданный процедуре параметр Туре имеет знач UserBitLn (4), т.е. тип линии определен пользователем, открывает возможность задать также и шаблон линии (параметр Pattern). Дань параметр принадлежит типу Word. т.е. представляет собой слово дли в два байта. Каждый бит этих двух байтов соответствует одному пик> лю в линии. Если бит равен 1, ветствующий пиксель светите ли бит равен О,— не светит' Иными словами, с помощью це> ки из 16 пикселей (светящихся нет) формируется шаблон лит Линия, отображенная на экран использованием шаблона, пр ставляет собой последовательн таких цепочек пикселей. Несколг примеров линий, параметр Туре торых равен 4 (UserBitLn), а зна ния параметра Pattern представлю ны рядом с образцами соответ*’
вующих линий, можно видеть на рис. 11.13.
284
Turbo Pascal: учитесь программироЕ
Представленные здесь четыре типа линий формируются значениями хцтов двухбайтового слова. Биты этого слова представлены здесь квад-атами. Заполненные квадраты соответствуют 1; незаполненные— О. ццсла рядом представляют собой значения соответствующих двухбайтных слов в десятичной системе.
Что касается параметра Thick, то он может принимать только значения (всего два), представленные в табл. 11.7
таблица. 11.7. Константы и коды толщины линии
Имя константы	Код	Комментарий
		
NormWidth	1	Толщина линии 1 пиксель
ThickWidth	3	Толщина линии 3 пикселя
Стиль линии, определенный с помощью процедуры SetLineStyle, в дальнейшем используется различными процедурами, отображающими на .’кране разного рода линии, дуги и фигуры, такими как Line, LineTo, Rectangle, DrawPoly. Arc и т.п.
Если процедуре SetLineStyle передать параметры с недопустимыми значениями, то в этом случае функция GraphResult вернет значение grError (общая ошибка, см. табл. 11.3) и существующие параметры линии изменены не будут.
Процедура GetLineSettings
Возвращает информацию о типе, шаблоне и толщине линии, установленных с помощью процедуры SetLineStyle.
Заголовок процедуры:
Procedure GetLineSettings(Var Info : LineSettingsType);
где Info — параметр-переменная, принадлежащая типу LineSettingsType и возвращающая данные о стиле линии.
Тип LineSettingsType определен в модуле GRAPH. Вот как выглядит ег° описание:
type
LineSettingsType = record
LineStyle : Word; {тип}
Pattern	: Word; {шаблон}
Thickness : Word; {толщина}
end;
Глава 11. Использование ресурсов модуля GRAPH
285
Процедура SetWriteMode
Определяет способ наложения вычерчиваемых линий (или фигур) На уже имеющееся на экране изображение.
Заголовок процедуры:
Procedure SetWriteMode(WriteMode : Integer);
где WriteMode — параметр, задающий способ наложения.
Если WriteMode имеет значение О, линии, вычерчиваемые на экране, накладываются на существующее изображение обычным способом — как на бумаге. Иными словами, линия (т.е. цепочка светящихся пикселей) пройдет по экрану независимо, было ли на экране что-нибудь до этого
Если WriteMode имеет значение 1 и если линия (т.е. цепочка светящихся пикселей) пройдет по светящейся области экрана, в этом случае соответствующие пиксели гаснут, т.е. здесь используется логическая функция “исключающее ИЛИ” (excluded OR — XOR).
Значения, которые может принимать параметр WriteMode, определяются двумя константами, объявленными в модуле GRAPH (табл. 11.8).
Таблица 11.8. Константы и коды, определяющие способ наложения
Имя константы	Код	Комментарий
CopyPut	0	Наложение без учета существующего изображения
XORPut	1	Наложение на существующее изображение с использованием операции XOR
Как это выглядит на экране, демонстрирует рис. 11.14.
Рис. 11.14. Два способа наложения линий на имеющееся изображение
Перед выводом верхней линии процедура SetWriteMode вызывалась со значением параметра О (CopyPut). Перед выводом нижней линии вызов процедуры SetWriteMode осуществлялся со значением 1 этого параметра (XORPut).
286
Turbo Pascal: учитесь программировс
Незаполненные фигуры
Помимо точек и линий, на экране можно отображать и кое-что посложнее. В этом разделе речь пойдет о процедурах и функциях, позволяющих вычерчивать на экране прямоугольники, многоугольники, окружности, дуги и эллипсы.
Процедура Rectangle
Отображает прямоугольник с использованием текущего стиля и цвета линии.
Заголовок процедуры:
Procedure Rectangle(XI, Yl, Х2, Y2 : Integer);
где (XI, Y1) и (Х2, Y2)— координаты соответственно верхнего левого и нижнего правого углов прямоугольника;
Для того чтобы на экране появился прямоугольник, достаточно в программу, в которой до этого инициирован переход в графический режим и сделаны все предварительные установки, вставить следующий оператор:
Rectangle(100,100,300,200);
В результате на экране отобразится фигура, которую можно видеть на рис. 11.15.
Рис. 11.15. Проще не бывает
Процедура DrawPoly
Рисует контур многоугольншса, используя текущий цвет и стиль линии.
Заголовок процедуры:
Procedure DrawPoly(Points: Word; Var PointCoords);
где Points — число углов многоугольника;
PointCoords— нетипизированный параметр, определяющий координаты углов.
Глава 11. Использование ресурсов модуля GRAPH
287
Каждый элемент PointCoords представляет собой два значения Word — X и Y. Поэтому данный параметр можно изобразить как ь: элементов, принадлежащих определенному в модуле GRAPH PointType:
type
PointType = record
X, Y : integer;
end;
Очевидно, что число координат (т.е. элементов типа PointType), обр зующих переменную типа PointCoords, равно значению параметра Point* Попробуем создать программу, рисующую на экране (с поме процедуры DrawPoly) многоугольник с заданным числом вершин, может выглядеть подобная программа, демонстрирует пример 11.5.
Internet
Пример 11.5
program DrwPoly;
uses graph;
const n=20; var
d,r,e,Rad,Err:integer;
m:array[0..n+1] of PointType;
к:word;
begin
d:=detect;
InitGraph(d,r,");
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err))
else begin
Rad:=trunc(GetMaxY/8);
for k:=0 to n do with m[k] do begin
x:= trunc(GetMaxX/2+Rad*Cos(2*pi*k/n));
y:= trunc(GetMaxY/2-Rad*sin(2*pi*k/n)); end;
SetLineStyle(0,0,3);
DrawPoly(n+l,m);
ReadLn;
CloseGraph end end.
Результаты работы этой программы демонстрирует рис. 11.16.
288
Turbo Pascal: учитесь программиро)
Рис. 11.16. Ничто не мешает вычертить многоугольник с любым числом вершин
На рис. 11.16 представлены образцы 3-, 5- и 20-угольника (который выглядит как окружность), вычерченных с помощью этой программы. В программе инициируется графический режим, проверяется наличие ошибок, а далее задается величина “радиуса” будущего многоугольника (переменная Rad). Затем вычисляются координаты вершин (переменные Хи У). Число вершин многоугольника определяет значение константы N.
В заключение определяется стиль линии (SetLineStyle), рисуется многоугольник (DrawPoly), осуществляется задержка (чтобы можно было увидеть результат — ReadLn) и затем — выход из графического режима (CloseGraph).
Процедура Circle
Вычерчивает окружность.
Заголовок процедуры:
Procedure Circle(X, Y: Integer; Rad : Word);
где (X, Y) — координаты центра;
Rad — радиус окружности (в пикселях, по горизонтали).
Окружность вычерчивается текущим цветом, установленным с помощью процедуры SetColor. При этом используется стиль линии, определенный процедурой SetLineStyle с единственным исключением: каким бы ни был текущий тип линии (точечная или пунктирная), окружность всегда рисуется сплошной линией.
При рисовании окружности автоматически учитывается коэффициент коррекции для используемого драйвера— тот самый, который молено получить с помощью процедуры GetAspectRatio. Иными словами. Радиус в пикселях, который задается как параметр процедуры Circle, определяется по горизонтали. После этого рисуется геометрически правильная (относительно) окружность без учета, сколько пикселей окажется в вертикальном радиусе. (Мы уже знаем, что если нарисовать окружность”, вертикальный и горизонтальный радиусы которой содержали бы равное число пикселей, это скорее всего оказалась бы не окружность, а эллипс.)
Глава 11. Использование ресурсов модуля GRAPH	289
1,1 -2016
Предположим, в программе, в которой осуществлен переход в граф ческий режим, далее организован цикл:
For i:=l to 20 do
Circle(200+5*i,200,100+i);
В теле цикла вызывается процедура Circle, рисующая последова тельность окружностей, при этом каждый раз смещая центр вправо ц увеличивая радиус. Результат можно видеть на рис. 11.17.
Рис. 11.17. Последовательность окружностей
Процедура Аге
Рисует дугу окружности.
Заголовок процедуры:
Procedure Arc(X, Y : Integer; bangle, EAngle, Rad : Word);
где (X. Y) — координаты центра:
BAngle и EAngle — начальный и конечный углы дуги:
Rad — радиус.
Углы для процедуры Аге (так же, как и для процедур Ellipse FillEllipse, PieSlice и Sector, см. далее) отсчитываются против часовоГ стрелки. Например, угол 00 соответствует 3 часам на часовом цифер блате, 90°— 12 часам, 180°— 9 часам и т.д. Так же, как и с окружно стью (см. раздел “Процедура Circle”), при вычерчивании дуги автомати чески учитывается коэффициент коррекции. Кроме того, так же выби раются стиль линии и цвет.
Предположим, в программе, в которой осуществлен переход в графический режим, далее организован цикл:
For i:=l to 20 do
Arc(200,200,180+10*i,450+10*i,50+5*i);
Line(40,200,360,200);
Line(200,360,200,40);
290
Turbo Pascal: учитесь программировать
В теле цикла вызывается процедура Аге, рисующая последовательность концентрических дуг, при этом каждый раз увеличивая радиус, а также начальный и конечный углы. Результат можно видеть на рис. 11.18.
Процедура GetArcCoords
Возвращает координаты центра, начала и конца дуги, построенной при последнем обращении к процедуре Аге или Ellipse.
Заголовок процедуры:
Procedure GetArcCoords(Var ArcCoords : ArcCoordsType);
где ArcCoords— параметр-переменная, принадлежащая типу ArcCoordsType, описанному в модуле GRAPH.
Вот как выглядит описание этого типа:
type
ArcCoordsType = record {координаты:}
X,Y	: integer {центра}
Xstart,Ystart: integer {начала дуги}
Xend,Yend : integer; {конца дуги}
end; I
Значения, полученные с помощью процедуры GetArcCoords, могут быть полезны, например, если требуется построить с помощью дуги сопряжение двух прямых.
Вернемся к предыдущему примеру и попробуем соединить линиями Координаты начал всех дуг с центром. Вот соответствующая последовательность операторов:
Глава 11. Использование ресурсов модуля GRAPH
291
10*
for i:=l to 20 do
begin
Arc(200,200,180+10*i,450+10*i,50+5*i);
GetArcCoords(a);
Line(a.x, a.y, a.Xstart, a.Ystart);
end;
Естественно, ранее в разделе описания переменных должна быть объявлена переменная А:
a:ArcCoordsType;
Как выглядят результаты работы такой программы, демонстрирует рис. 11.19.
Рис. 11.19. Процедура GetArcCoords позволяет без проблем соединить концы дуг с центром
Процедура Ellipse
Вычерчивает дугу эллипса.
Заголовок процедуры:
Procedure Ellipse(X, Y : Integer; BAngle, EAngle : Word; XRadius, YRadius : Word);
где (X, Y) — координаты центра:
BAngle и EAngle — начальный и конечный утлы дуги;
XRad и YRad — соответственно горизонтальный и вертикальный ра диусы эллипса (в пикселях).
При вычерчивании эллипсной дуги стиль линии и цвет выбираютс так же, как и при рисовании окружности (см. раздел “Процедура Circle Начало и направление отсчета утла — те же, что и при рисовании дут окружности (см. раздел “Процедура Аге”).
292	Turbo Pascal: учитесь программировав
Предположим, в программе, в которой осуществлен переход в графический режим, далее организован цикл:
For i:=l to 20 do
begin
Ellipse(250,250,100+4*i,80-4*i,100+6*i,30+2*i);
В теле цикла вызывается процедура Ellipse, рисующая последовательность концентрических эллипсных дуг, каждый раз увеличивая радиус, а также изменяя начальный и конечный углы. Результат можно видеть на рис. 11.20.
Рис. 11.20. Концентрические эллипсные дуги
Заполненные фигуры
Помимо незаполненных (см. предыдущий раздел), средства модуля GRAPH позволяют выводить на экран также заполненные фигуры. Речь идет о таких фигурах, как прямоугольники, параллелепипеды, многоугольники, эллипсы и сектора. С использованием заполнений мы познакомились в разделе “Цвета, палитры, заполнения”.
Процедура FloodFill
Заполняет замкнутую область, используя текущий стиль заполнения (шаблон и цвет).
Заголовок процедуры:
Procedure FloodFill(X, Y : Integer; Border : Word);
где Хи Y— координаты произвольной точки в области, которую требуется заполнить;
Border — код цвета линии, ограничивающей заполняемую область.
Нужный стиль заполнения должен быть предварительно задан процедурой SetFillStyle или SetFillPattern.
Если точка (X, Y) находится внутри замкнутой области, заполнена окажется эта область. Если точка находится снаружи замкнутой области, заполняется все пространство вне области. Если же область окажется незамкнута, заполненным окажется весь экран.
Глава 11. Использование ресурсов модуля GRAPH
293
Каков смысл параметра Border? Предположим, в программе имеется такая последовательность операторов:
SetColor(14);
Rectangle(150,150,350,350);
SetColor(4);
Rectangle(200,200,300,300);
FloodFill(250,250,4); {4 или 14}
Эти операторы вычерчивают на экране два вложенных один в другой квадрата. Причем больший квадрат отображен цветом, код которого 4, а меньший — цветом с кодом 14. Далее следует вызов процедуры FloodFill, задающая точку внутри маленького квадрата. Последний параметр этой процедуры. Border, — как раз то, что нас сейчас интересует. Так вот, если здесь задать значение 4, заполненным окажется большой квадрат (рис. 11.21 слева), а если 14— маленький (рис. 11.21 справа). Иными словами, когда имеется несколько фитур, вложенных одна в другую, параметр Border позволяет указать, какую из них следует заполнить.
Рис. 11.21. Заполнить можно любую фигуру
Процедура Ваг
Отображает необведенный прямоугольник, заполненный с использованием текущих шаблона и цвета.
Заголовок процедуры:
Procedure Bar(XI, Yl, Х2, Y2 : Integer);
где (XI, Y1) и (Х2, Y2)— координаты соответственно верхнего левого и нижнего правого углов прямоугольника:
Для заполнения используются шаблон и цвет, определенные с помощью процедур SetFillStyle и SetFillPattern.
Примечание
Если возникнет необходимость нарисовать обведен.' прямоугольник, воспользуйтесь процедурой Bar3D (с-далее), с параметром Depth, равным кулю.
294
Turbo Pascal: учитесь программировав
Вот последовательность операторов, которая, будучи включена в программу, в которой до этого инициирован переход в графический режим, а также выполнены установки заполнения и шрифта, отобразит па экране столбчатую диаграмму.
Ьаг(100,400,150,500);
Ьаг(200,380,250,500);
Ьаг(300,360,350,500);
Ьаг(400,340,450,500);
OutTextXY(110,430, '1998');
OutTextXY(210,420,'1999');
OutTextXY(310,410,'2000');
OutTextXY(410,400,' 2001');
Результат запуска такой программы, показан на рис. 11.22.
Рис. 11.22. Оптимистическая диаграмма, свидетельствующая о неуклонном росте
С использованной здесь процедурой OutTextXY вы познакомитесь дальше в разделе “Текст в графическом режиме”.
Процедура Bar3D
Отображает трехмерный параллелепипед с заполненной передней гранью.
Заголовок процедуры:
Procedure Bar3D(Xl, Yl, Х2, Y2 : Integer; Depth : Word; Top : Boolean);
где (Xl, Yl) и (X2, Y2)— координаты соответственно верхнего левого и нижнего правого углов прямоугольника;
Depth34— параметр, определяющий “глубину” параллелепипеда (в пикселях);
Тор — параметр, задающий отображение (или неотображение) верхней грани параллелепипеда.
При заполнении передней грани используются шаблон и цвет, ранее определенные при обращении к процедурам SetFillStyle или SetFillPattern.
4 Английское слово depth переводится как глубина.
Глава 11. Использование ресурсов модуля GRAPH
295
Трехмерный контур параллелепипеда вычерчивается линией, цве г стиль которой ранее определены с помощью процедур SetColor SetLineStyle.
Для того чтобы понять смысл параметра Depth, включим в прогрг j, му, в которой инициирован переход в графический режим и сделаны в предварительные установки, следующие операторы:
Bar3D(100,200,150,300,10,true);
Bar3D(200,200,250,300,20,true);
Bar3D( 300,200,350,300,30,true);
Bar3D(400,200,450,300,40,true);
Эти операторы задают отображение четырех параллелепипедов, п раметр Depth которых равен соответственно 10, 20, 30 и 40 пикселе Результат можно видеть на рис. 11.23.
Рис. 11.23. Параметр Depth, определяет глубину третьего измерения
Что касается параметра Тор, то если он равен TRUE, у параллелепг педа отображается верхняя грань, а если Тор равен FALSE, верхю грань не отображается. Эта возможность позволяет располагать одг поверх другого несколько параллелепипедов.
Вот два оператора, отображающие параллелепипеды — с верхнг гранью и без нее:
Bar3D(250,160,300,300,50,true);
Bar3D(400,160,450,300,50,false);
Результаты демонстрирует рис. 11.24.
Рис. 11.24. Смысл параметра Тор понять несложно
296
Turbo Pascal: учитесь программировс
Процедура FillPoly
Рисует заполненный многоугольник.
Заголовок процедуры:
Procedure FillPoly(Points : Word; Var PointCoords);
где Points — число углов многоугольника;
PointCoords— нетипизированный параметр, определяющий координаты углов.
Каждый элемент PointCoords представляет собой два значения типа Word — Хи Y. Поэтому данный параметр можно представить как массив элементов, принадлежащих определенному в модуле GRAPH типу PointType:
type
PointType = record
X, Y : integer;
end;
Очевидно, что число координат (т.е. элементов типа PointType), образующих переменную типа PointCoords, равно значению параметра Points.
Процедура FillPoly заполняет многоугольник, используя текущий стиль и цвет заполнения, определенные с помощью процедур SetFillStyle и SetFillPattern. Контур многоугольника обводится линией текущего цвета и типа, установленных процедурами SetLineStyle и SetColor.
Процедура FillPoly очень похожа на процедуру DrawPoly с которой мы познакомились раньше. Единственное отличие в том, что FillPoly рисует заполненный прямоугольник. Поэтому, для того чтобы попрактиковаться с этой процедурой, можно взять за основу старую программу, в которой только потребуется заменить DrawPoly на FillPoly, а до этого задать установки для заполнения (процедура SetFillStyle). Текст новой программы содержится в примере 11.6.
’игшажГ	Пример АЛ.6
program FillPoly;
uses graph;
const n=4; var
d,r,e,Rad,Err:integer;
m:array[0..n+1] of PointType;
kzword;
begin
d:=detect;
InitGraph(d,r, " );
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err))
Глава 11. Использование ресурсов модуля GRAPH
297
else
begin
Rad:=trunc(GetMaxY/8);
for k:=0 to n do with m[k] do
begin
x:=trunc(GetMaxX/2+Rad*Cos(2*pi*k/n));
y:=trunc(GetMaxY/2-Rad*sin(2*pi*k/n)); end;
SetLineStyle(0,0,3);
SetFillStyle(5,14);
FillPoly(n+l,m);
ReadLn;
CloseGraph
end
end.
Результаты работы этой программы можно видеть на рис. 11.25.
Рис. 11.25. Можно нарисовать заполненный многоугольник с любым числом вершин
Здесь с помощью программы FilPoly созданы 4-, 7- и 20-угольнг Для того чтобы задать число вершин многоугольника, достаточно д. константы N указать нужное значение.
Процедура FillEllipse
Отображает заполненный эллипс.
Заголовок процедуры:
Procedure FillEllipsefX, Y : Integer; XRad, YRad : Word)
где (X, Y) — координаты центра эллипса;
XRad и YRad — соответственно горизонтальный и вертикальный р диусы.
Заполнение осуществляется с использованием шаблона и цвета, о' ределенных с помощью процедур SetFillStyle и SetFillPattem. Контур э липса обводится линией, параметры которой ранее определены прог дурами SetLineStyle и SetColor.
298
Turbo Pascal: учитесь программировс
Снова обратимся к примеру программы, в которой инициирован переход в графический режим, сделаны все предварительные установки, а далее имеются следующие операторы:
FillEllipse(100,30,100,30);
FillEllipse(50,230,30,100);
FillEllipse(300,100,100,100);
FillEllipse(250,300,150,30);
Данные операторы отображают на экране четыре разных эллипса. Какой эффект оказывает тот или иной параметр на форму эллипса, можно судить, сравнивая числовые значения этих параметров с формой и расположением соответствующих эллипсов (рис. 11.26).
Рис. 11.26. Процедура FillEllipse позволяет отобразить эллипс любой формы
Одна из отображенных здесь фигур представляет собой частный случай эллипса — круг.
Процедура Sector
Отображает заполненный сектор эллипса.
Заголовок процедуры:
Procedure Sector(X, Y : Integer; BAngle, EAngle, XRad, YRad : Word)
где (X, Y) — координаты центра;
BAngle и EAngle — начальный и конечный углы сектора;
XRad и YRad — соответственно горизонтальный и вертикальный радиусы эллипса (в пикселях);
Сектор вычерчивается от угла BAngle до EAngle. При этом внешняя граница фигуры отображается линией текущих цвета и стиля, а запол-
Глово 11. Использование ресурсов модуля GRAPH
299
некие проводится с использованием стиля и цвета, определенных п, цедурами SetFillStyle и SetFillPattern.
Углы процедура Sector отсчитывает против часовой стрелки и измеряет их в градусах. Отсчет углов начинается от радиуса, направленна от центра вправо. Если начальный и конечный углы равны 0° и 360", ц экране отобразится полный эллипс.
Для того чтобы отобразить сектор окружности (не эллипса), дост точно задать равные горизонтальный и вертикальный радиусы.
Снова обратимся к примеру программы, в которой инициирован п<-реход в графический режим, сделаны все предварительные установки.
далее имеются следующие операторы:
Sector(100,30,	90,300,	100,30);
Sector(50,230,	0,270,	30,100);
Sector(300,100,	45,270,	100,100);
Sector(250,300,	315,45,	150,30);
Данные операторы отображают на экране четыре разных сектор Все углы на рис. 11.27 обозначены, поэтому определить, какой секте отображает тот или иной оператор, не составит труда.
Рис. 11.27. Секторы на любой вкус
Процедура PieSlice
Отображает заполненный сектор окружности.
Заголовок процедуры:
Procedure PieSlice(X, Y : Integer; BAngle, EAngle, Rad : Word);
где (X, Y) — координаты центра;
BAngle и EAngle — начальный и конечный углы сектора;
300
Turbo Pascal: учитесь программиров
Rad — радиус (определенный в пикселях по горизонтали).
Закраска сектора проводится стилем и цветом, определенными с помощью процедур SetFillStyle и SetFillPattem. При этом внешняя граница фигуры отображается линией текущего цвета и стиля.
Процедура PieSlice35 очень удобна для построения круговых диаграмм. Пусть в программе, в которой инициирован переход в графический режим и сделаны все необходимые установки, имеются следующие операторы:
SetFillStyle(7,14);
PieSlice(300,200, 0,135, 150);
SetFillStyle(8,14);
PieSlice(300,200, 135,225, 150);
SetFillStyle(9,14);
PieSlice(300,200, 225,280, 150);
SetFillStyle(10,14);
PieSlice(300,200, 280,360, 150);
OutTextXY(300,110,'37,5%');
OutTextXY(170,180,'25%');
OutTextXY(210,280,'15,3%');
OutTextXY(330,230,'22,2%');
Эти операторы отображают четыре сектора с общим центром (для этого используются процедуры PieSlice), но каждый сектор заполняется оригинальным узором (заполнение выбирается с помощью процедуры SetFillStyle). Затем в каждом секторе с помощью процедуры OutTextXY выводится текстовая строка (с этой процедурой мы познакомимся в разделе ‘Текст в графическом режиме”). Результаты можно видеть на рис. 11.28.
Рис. 11.28. Типичная круговая диаграмма
io Pie Slice дословно переводится как ломтик (т.е. сектор) пирога (круглого)
Глава 11. Использование ресурсов модуля GRAPH	301
Текст в графическом режиме
Текст, который, казалось бы, предназначен сугубо для текстовое режима, оказывается, можно использовать и с графикой. Более того, графическом режиме можно менять шрифты, варьировать величин букв и выбирать направление вывода (слева направо или снизу вверх' Данный раздел посвящен процедурам и функциям, которые позволяй делать все это, а также многое другое.
Процедура OutText
Выводит строку текста, начиная с текущей позиции.
Заголовок процедуры:
Procedure OutText(Text : String);
где Text — текстовая строка (значение типа STRING).
Процедура OutText использует шрифт, ранее установленный проце дурой SetTextStyle (см. далее). Если в одном тексте используется несколько шрифтов, при компоновке такого текста для определения дли ны и высоты той или иной строки можно воспользоваться процедурал TextWidth и TextHeight.
При выводе строки используются текущие установки выравнивания заданные с помощью процедуры SetTextJustify.
Если строка, представленная векторным шрифтом, слишком длин на, отображается только часть ее, помещающаяся на экране. Если этс случится со строкой, представленной матричным (т.е. стандартным) шрифтом, такая строка не отображается вовсе.
^/Процедура OutTextXY
Выводит строку в указанном месте экрана.
Заголовок процедуры:
Procedure OutTextXY(X, Y : Integer; Text : String);
где (X, Y) — координаты позиции, с которой начинается отображенИ-строки;
Text — текстовая строка (значение типа STRING).
Процедура OutText (см. выше) предназначена для вывода текста из текущей позиции на экране. А если требуется вывести текст из иной точки, не совпадающей с текущей позицией, то лучше воспользоваться процедурой OutTextXY.
302
Turbo Pascal: учитесь программировав
Как и OutText, процедура OutTextXY использует шрифты и установки выравнивания, заданные процедурами SetTextStyle и SetTextJustify соответственно.
Слишком длинные строки, выводимые процедурой OutTextXY, отображаются (или не отображаются) на экране так же, как и при использовании процедуры OutText.
Процедура SetTextStyle
Определяет текущий стиль текста, выводимого в графическом режиме.
Заголовок процедуры:
Procedure SetTextStyle(Font, Direction, Size : Word);
где Font — код шрифта;
Direction — код направления вывода;
Size — код размера символов.
Значение параметра Font определяется набором констант, описанных в модуле GRAPH (табл. 11.9). Шрифт с кодом О (DefaultFont) — единственный матричный шрифт (8x8 точек). Все остальные шрифты векторные, каждый из которых содержится в собственном файле.
Таблица 11.9. Константы и коды стандартных шрифтов
Имя константы	Код	Файл (.CHR)	Образец шрифта
DefaultFont	0		RaBbCc 12345
TriplexFont	1	TRIP	AaBbCc 12345
SmallFont	2	ИЛ	AaBbCc 12345
SansSerifFont	3	SANS	AaBbCc 12345
GothicFont	4	GOTH	Лп®Ы£с 1H345
	5	SCRI	AMo 12345
	6	SIMP	AaBbCc 12345
	7	TSCR	АссВЪСс 12345
	8	LOOM	AaBbCc 12345
	9	EURO	AaBbCc 12345
	10	BOLD	
Глава 11. Использование ресурсов модуля GRAPH
303
Примечание
В версиях Turbo Pascal до 7.0 можно было использова' только шрифты с кодами 0-4. Однако в версии 7.0 пере чень доступных шрифтов значительно увеличен (но? шрифты имеют коды 5-10, но константы для них не от ределены, см. табл, выше). 
Матричный шрифт (DefaultFont) доступен всегда, поскольку содеу жится в модуле GRAPH. Для доступа к векторным шрифтам (которые
после инсталляции Turbo Pascal находятся в каталоге BGI) необходим перенести их файлы в текущий каталог.
Векторные шрифты, имеющиеся в составе Turbo Pascal 7.0 (в отличи от DefaultFont), не содержат букв кириллицы. Однако эти шрифты можн модифицировать. Кроме того, шрифты с кириллицей можно найти в Internet (например, по адресу http://halyava.ru/bgi/chrfont.html).
Вспомним, что помимо Font, в процедуре SetTextStyle имеются такж параметры Direction и Size, позволяющие задать соответственно на правление вывода и размер символов. Так вот, направление вывода за дается с помощью кодов и констант, представленных в табл. 11.10.
Таблица 11.10. Константы и коды направления вывода
Имя константы	Код	Направление вывода
HorizDir	0	Слева направо
VertDir	1	Снизу вверх
Для того чтобы это понять, представим, что существует некотора
программа, инициирующая графический режим, в которой имеются
следующие операторы:
Рис. 11.29. Вывод текста слева направо и снизу вверх
SetTextStyle(0,0,3);
OutTextXY(0,0,'АаВЬСс 12345');
SetTextStyle(0,1,3);
OutTextXY(0,0,'АаВЬСс 12345');
Два из них задают два текстовы стиля, совпадающие во всем, за ис ключением направления вывода Оставшиеся два оператора инициг руют вывод строки текста относи тельно указанной позиции (одной £ обоих случаях). Как все это выглядит, демонстрирует рис. 11.29.
Точка, относительно которой выводится текст, отмечена здесь небольшим косым крестиком.
Что касается параметра Size пр< цедуры SetTextStyle, то он позволяв
304
Turbo Pascal: учитесь программирова.
задать размер шрифта и может изменяться от 1 до 10. Снова обратимся к примеру программы, инициирующей графический режим, в которой далее имеются следующие операторы:
for i:=l to 10 do
begin
SetTextStyle(O,O,i);
OutTextXY(10+i*i*4,100,'A');
SetTextStyle(4,0,i);
OutTextXY(10+i*i*4,150,'A');
end;
Здесь организуется цикл в котором параметр Size увеличивается от 1 до 10. (Выражение i*i*4 подобрано так, чтобы расстояние между выводимыми символами было приблизительно пропорционально их размеру36.) Результаты можно видеть на рис. 11.30.
Рис. 11.30. Последовательное увеличение символов
Кроме прочего, это изображение позволяет судить, насколько непригляден увеличенный матричный шрифт.
Процедура SetTextJustify
Устанавливает значения выравнивания текста, используемые процедурами OutText и OutTextXY.
Заголовок процедуры:
Procedure SetTextJustify(Horiz, Vert : Word);
где Horiz и Vert— параметры, задающие горизонтальное и вертикальное выравнивания.
Для задания значений этих параметров можно использовать определенные в модуле GRAPH константы (табл. 11.11).
36 Здесь вместо вручную подобранного выражения можно воспользоваться функцией TextWidth., возвращающей ширину текстовой строки. Об этой функции речь пойдет дальше.
Глава 11. Использование ресурсов модуля GRAPH
305
Таблица 11.11. Константы и коды выравнивания текста по горизонтали и вертикали
Имя константы	Код	Комментарий
LeftText	0	Указатель слева
CenterText	1	Указатель посередине (по горизонтали и вертикали)
RightText	2	Указатель справа
BottomText	0	Указатель под строкой
TopText	2	Указатель над строкой
Хотя в именах этих констант фигурирует слово текст, в действительности первые половины имен этих констант указывают на положение указателя относительно текста. Это нашло свое отражение в комментариях в таблице выше и это подтверждают примеры, с которыми мы сейчас познакомимся.
Итак, после вызова SetTextJustify весь выводимый текст будет выравниваться заданным способом относительно указателя текущей позиции. Следующий фрагмент программы трижды выводит строку символов, каждый раз меняя выравнивание по вертикали:
SetTextJustify (0,1);
OutTextXY(0,10 0,’AaBbCc');
SetTextJustify (0,0);
OutTextXY(160,100,'AaBbCc');
SetTextJustify (0,2);
OutTextXY(3 2 0,10 0,'AaBbCc');
Результат работы программы с этими операторами представлен на рис. 11.31.
Рис. 11.31. Использованы константы выравнивания CenterText, BottomText и TopText соответственно
Строка выводится трижды, причем вертикальная координата (Y) постоянна, а горизонтальная (X) изменялась таким образом, чтобы выводимые строки не накладывались одна на другую. Имеющаяся здесь (для наглядности) линия проходит по точкам, координаты которых передавались процедуре OutTextXY в качестве параметров.
306
Turbo Pascal: учитесь программировав
Относительно выравнивания по горизонтали поступим аналогично. Вот фрагмент программы, которая трижды выводит символ “А”, каждый раз меняя выравнивание по горизонтали:
SetTextJustify (1,0);
OutTextXY(100,100,'А');
SetTextJustify (0,0);
CutTextXY(100,200,'А');
SetTextJustify (2,0);
OutTextXY(100,300,'A');
Результат работы программы с этими операторами представлен на рис. 11.32.
Как и в первом случае, здесь символ также выводится трижды, причем горизонтальная координата (X) постоянна, а вертикальная (Y) изменяется так, чтобы выводимые символы не накладывались один на другой. Имеющаяся на рисунке линия проходит по точкам, координаты которых передавались процедуре OutTextXY в качестве параметров.
Рис. 11.32. Использованы константы выравнивания соответственно (сверху вниз) CentefText, LeftText и RightText
Процедура SetUserCharSize
Изменяет ширину и высоту символов.
Заголовок процедуры:
Procedure SetUserCharSize(Xl, Х2, Yl, Y2 : Word);
где (Xl, Х2) и (Yl, Y2) — значения, позволяющие задать коэффициенты изменения соответственно ширины и высоты символов.
Коэффициент изменения символов равен отношению: по горизонтали — XI к Х2, а по вертикали — Y1 к Y2. Например, чтобы сделать текст вдвое шире, достаточно установить значение XI равным 2, а Х2 — равным 1.
Предположим, имеется программа с такой последовательностью операторов:
SetTextStyle(7,0,2);
for i:=l to 10 do
begin
SetUserCharSize(6+i,6,1,1);
OutTextXY(0,10 0+3 0 * i,'AaBbCc 12345');
end;
Здесь организован цикл, в котором строка текста выводится десять раз, расширяясь с каждым разом. Выражения, определяющие ширину символов, имеющие здесь вид 6 и 6*i, выбраны с расчетом, чтобы расширенная строка не вышла за пределы экрана. Как это работает, можно судить по рис. 11.33.
Глава 11. Использование ресурсов модуля GRAPH
307
Рис. 11.33. Символы “поправились"
Аналогично можно организовать растягивание символов по высоте. Вот возможная последовательность операторов:
SetTextStyle(3,0,7); for i:=l to 5 do begin
SetUserCharSize(1,1,3+i,3);
OutTextXY(0,10+70*i,'AaBbCcDdEeFfGgHhliJjKkLlMmNnOoPpQqRr'); end;
Как выглядит экран после запуска подобной программы, демонстрирует рис. 11.34.
AaBbCcDdEeFfGgHhliJjKkLIMmNnOoPpQqRr
AaBbCcDdEeFfGgHhliJjKkLIMmNnOoPpQqRr
AaBbCcDdEeFfGgHhliJjKkLIMmNnOoPpQqRr
AaBbCcDdEeFfGgHhliJjKkLIMmNnOoPpQqRr AaBbCcDdEeFfGgHhliJjKkLIMmNnOoPpQqRr
Puc. 11.34. Символы “выросли"
308
Turbo Pascal: учитесь программировать
Здесь, как и в предыдущем случае, выражения, определяющие ши-ину символов (З+i и 3), выбраны с расчетом, чтобы растянутые по вы->те строки поместились на экране.
Можно ли организовать увеличение символов по высоте и по ширине ^повременно? Можно, только это имеет смысл при непропорциональ-ом увеличении. В противном случае целесообразнее воспользоваться роцедурой SetTextStyle, ее параметр Size как раз для этого и предна-начен.
В заключение осталось сказать, что процедура SetUserCharSize воз-ействует только на векторные шрифты.
Функция Textwidth
Возвращает длину выводимой строки (в пикселях).
Заголовок функции:
Function Textwidth(Text : String) : Word;
где Text — выводимая строка (значение типа STRING).
Функция учитывает текущий размер шрифта и коэффициент изме-ения ширины символов.
В каких случаях может быть полезна эта функция? Помните, когда ня рассматривали параметр Size процедуры SetTextStyle, нам пришлось скусственио подобрать выражение i*i*4, для того чтобы расстояние ежду выводимыми увеличивающимися символами было приблизи-льно пропорционально их размеру (см. рис. 11.30). Так вот, вместо то-э чтобы заниматься ручным подбором, там вполне можно было исполь->вать функцию TextWidth.
Функция TextHeight
Возвращает высоту выводимой строки (в пикселях).
Заголовок функции:
Function TextHeight(Text : String) : Word;
где Text — выводимая строка (значение типа STRING).
Функция учитывает текущий размер шрифта и коэффициент изменил высоты символов.
Функция TextHeight полезна в случаях, аналогичных приведенному в ячестве примера для функции TextWidth (см. выше). Кроме того, функ-по TextHeight можно применять для корректировки расстояния между роками, для вычисления высоты области просмотра, установки раз-ра заголовка, чтобы он уместился в окне, и т.д.
лава 11. Использование ресурсов модуля GRAPH
309
Процедура GetTextSettings
Возвращает сведения о текущих шрифте, направлении вывода (ел [ направо или снизу вверх), размере и выравнивании (горизонтальном или вертикальном) текста.
Заголовок процедуры:
Procedure GetTextSettings(Var Textinfo : TextSettingsType);
где Textinfo — параметр-переменная, принадлежащий определенному в модуле GRAPH типу TextSettingsType. Вот как выглядит описани-этого типа:
type
TextSettingsType =	record
Font	:	Word;	{шрифт}
Direction : Word; {направление вывода}
CharSize	:	Word;	{размер}
Horiz	:	Word;	{выравнивание	по	горизонтали}
Vert	:	Word;	{выравнивание	по	вертикали}
end;
Значения, которые возвращает процедура GetTextSettings, установлены ранее процедурами SetTextStyle и SetTextJustify.
Функция InstallUserFont
Устанавливает новый шрифт.
Заголовок функции:
Function InstallUserFont(FileName : String ) : Integer;
где FileName— строка, содержащая путь и имя файла с новым шрифтом.
Функция возвращает значение, соответствующее коду нового шри та (см. табл. 11.9), который с этого момента вы можете указывать в качестве параметра Font процедуры SetTextStyle. Новый шрифт — тот, который не был встроен в BGI-систему (и который не входит в комплект поставки Turbo Pascal 7.0). Новым шрифтам присваиваются коды 10 11, 12 и т.д.
Прочие процедуры и функции
Здесь собрана информация о процедурах и функциях модуля GRAPH которые не удалось отнести ни к одному из предыдущих разделов этом разделе мы научимся работать со страницами, узнаем, как сохра
310
Turbo Pascal: учитесь программировав
нить в памяти изображение из определенной области экрана и вывести его на экран, а также выясним, как встраивать драйверы и шрифты в исполняемый файл программы.
Страницы
Видеопамять можно разделить на области, известные как страницы. При этом в каждый момент времени на экране отображается единственная страница, а вывод можно осуществлять в любую существующую страницу. Заранее подготовленные таким образом страницы очень удобно последовательно выводить на экран. Этот метод чаще всего используется при создании анимаций. Для работы со страницами в модуле GRAPH предназначены две процедуры.
Процедура SetActivePage
Делает активной одну из страниц видеопамяти.
Заголовок процедуры:
Procedure SetActivePage(Page : Word);
где Page — номер страницы.
Весь графический вывод направляется на активную страницу с номером Page. Многостраничный вывод возможен только при наличии соответствующего видеоадаптера — EGA, VGA и т.п.
Процедура SetVisualPage
Делает видимой графическую страницу, номер которой указан в качестве параметра процедуры.
Заголовок процедуры:
Procedure SetVisualPage(Раде : Word);
где Page — номер страницы.
Видимая страница — та. которая отображается на экране. А активной является страница, на которую осуществляется вывод. Иными словами, программа осуществляет графические построения на невидимой (но активной) странице, затем с помощью данной процедуры выводит эту страницу — тем самым практически мгновенно отображая картинку на экране.
Пример программы, в которой используется многостраничный вывод, можно видеть в примере 11.7.
Internet
program SetPage; uses graph,crt;
1 лава 11. Использование ресурсов модуля GRAPH
311
var i,j,R,Dx,Dy,Err:integer; x,y:word;
begin
i:=3; j:=0;
initgraph(i,j, ");
Err:=GraphResult;
If Err <> grOK then
WriteLnfGraphErrorMsg(Err))
else
begin
GetAspectRatio(x,у);
R:=5;
for i:=0 to 15 do
begin	{заполняем страницы}
SetActivePage(i);
Circle(320,100,100);
Dx:=320+Round(30*Cos(i*2*Pi/16)*y/x);
Dy:=100-Round(30*Sin(i*2*Pi/16)); FillEllipse(Dx,Dy,R*Round(y/x),R); end;
While not KeyPressed=True do
for i:=0 to 15 do	{демонстрируем страницы
begin
SetVisualPage(i);
Delay(200);
end;
CloseGraph;
end end.
Puc. 11.35. Многостраничный вывод позволяет сделать изображение подвижным
Как это выглядит на экране, см. рис. 11.35.
В этой программе выбран режим О для драйвера EGA (код 3). Почему именно oi Если заглянуть в табл. 11.2, то можно убедиться, что данный режим (единственнг поддерживает 4-страничный вывод.
В этой программе организованы Д1 i цикла. В первом цикле страницы заполн ются, а во втором— демонстрируются. Пс очередная смена страниц обеспечивает эффект вращения крупных точек по кругу (см-рис. 11.35).
Для завершения работы программы дос таточно нажать любую клавишу.
ЗИ2
Turbo Pascal: учитесь программирова
Изображения: сохранение в памяти и отображение на экране
Функция ImageSize
Возвращает объем памяти (в байтах), необходимой для сохранения в 1мяти изображения из заданной прямоугольной области экрана.
Заголовок функции:
Function ImageSize(xl, yl, x2, у2 : Integer) : Word;
где (XI, Yl] и (X2, Y2) — координаты, определяющие верхний левый и эавый нижний утлы области.
Процедура Getlmage
Сохраняет в памяти прямоугольную область экрана.
Заголовок процедуры:
Procedure Getlmage(xl, yl, x2, y2 : Integer; Var BitMap);
где XI, Yl. X2, Y2— координаты, определяющие прямоугольную об-н ть на экране:
BitMap— нетипизированный параметр, значение которого должно (впяться шести плюс объему памяти, занимаемому изображением.
Для того чтобы определить размер параметра BitMap, можно вос-шьзоваться функцией ImageSize.
Процедура Putlmage
Выводит на экран изображение, содержащееся в памяти.
Заголовок процедуры:
Procedure Putlmage(х, у : Integer; var BitMap; Mode : Word);
где X и Y— координаты, определяющий верхний левый угол прямо-ольной области на экране:
BitMap — нетипизированный параметр, содержащий высоту, шири-v. а также двоичное изображение, которое будет помещено на экран;
Mode— параметр, определяющий, какая двоичная операция будет пользована при выводе изображения на экран. Указанная операция пределяет взаимодействие каждого бита выводимого изображения с ответствующим битом изображения, которое существовало на экране > этого. Допустимые значения параметра Mode ограничиваются пятью шстантами, определенными в модуле GRAPH. Перечень этих констант ожно видеть в табл. 11.12.
-кава 11. Использование ресурсов модуля GRAPH	ЗЛЗ
Таблица 11.12. Константы и коды логических операций, применяемых при выводе изображения
Константа	Код	Комментарий
NormalPut	0	Простое копирование
XORPut	1	Исключающее ИЛИ
OrPut	2	Логическое сложение (ИЛИ)
AndPut	3	Логическое умножение (И)
NotPut	4	Логическое отрицание (НЕ)
Встраивание в исполняемый файл драйверов
При создании и отладке программы инициализации графического драйвера обычно означает загрузку соответствующего BGl-файла с диска в память. Система Turbo Pascal 7.0 поставляется с набором графических драйверов (см. табл. 11.1), которые при создании и отладке программы (т.е. при работе с интегрированной средой разработчика) всегда находятся под рукой.
Но вот программа уже создана, отлажена, откомпилирована и попала к потребителю. Потребитель пытается запустить ее на своем компьютере, на котором, скорее всего, нет соответствующих графических драйверов. В итоге программой невозможно воспользоваться. Где же выход?
Выход из этой ситуации, предусмотренный разработчиками Turbo Pascal 7.0, состоит в том, чтобы включать необходимый драйвер (или набор драйверов) непосредственно в исполняемый файл программы. Это осуществляется в два этапа.
Сначала файл драйвера (BGI-файл) преобразуется в OBJ-файл. Для этого необходимо вызвать утилиту BINOBJ, которая имеется в каталоге BIN, с тремя параметрами: именем BGI-файла (преобразуемого), именем OBJ-файла (получаемого) и именем процедуры автоопределения, по которому можно будет обратиться к драйверу, встроенному в исполняемый файл. (Второе и третье имя могут быть произвольными.) Вот как это выглядит:
.,bin\binobj ega.bgi еда ega_drv
Затем в программе следует создать внешнюю процедуру (EGA_DRVj-имя которой в качестве одного из параметров указывалось при вызове BINOBJ:
Uses Graph;
Procedure EGA_DRV; external;
{$L ega.obj}
314
Turbo Pascal: учитесь программировать
var i,j : integer;
begin
if RegisterBGIDriver (@EGA_DRV) < 0 then
begin
Writein('Ошибка регистрации драйвера');
Halt;
end;
{ Инициализация графики }
i:=EGA; j;=EGALo;
InitGraph(i,j,'
Эта подпрограмма загружает и регистрирует драйвер, передавая казатель на нее функции RegisterBGIDriver (@EGA_DRV), с тем, чтобы ipn вызове InitGraph загружался именно этот драйвер. Имеющаяся лесь директива {$L} предписывает компилятору включить заданный райл в компилируемую программу. (С использованной здесь функцией RegisterBGIDriver мы познакомимся ниже.) Функция RegisterBGIDriver юзвращает значение, принадлежащее типу Integer, которое использует-я для контроля правильности регистрации драйвера. Если это значе-1ие меньше нуля, значит, имеет место ошибка. В противном случае возращенное значение представляет собой код зарегистрированного райвера, который можно передать в качестве параметра процедуре nitGraph при переходе в графический режим.
Функция RegisterBGIDriver
Регистрирует в графической системе драйвер формата .BGI загруженный пользователем или включенный в исполняемый файл рограммы).
Заголовок функции:
Function RegisterBGIDriver(Driver : Pointer) : Integer;
где Driver — указатель на внешнюю процедуру регистрации драйвера.
Если имеет место ошибка регистрации, функция возвращает значе-ие, меньшее нуля. Иначе возвращается код драйвера.
Встраивание в исполняемый файл шрифтов
Подобно драйверам, часто очень удобно включить в исполняемый •»айл программы все используемые шрифты. Для этого файл шрифта 'HR-файл) с помощью утилиты BINOBJ преобразуется в OBJ-файл:
..bin\binobj goth.chr goth goth_fnt
юва 11. Использование ресурсов модуля GRAPH
315
Затем в программе следует создать внешнюю процедуру (например GOTH_FNT), имя которой в качестве одного из параметров указывалось при вызове BINOBJ:
Uses Graph;
Procedure GOTH_FNT; external;
{$L goth.obj}
begin
if RegisterBGIFont (@goth_fnt) < 0 then
Данная подпрограмма служит для регистрации шрифта. Использованная здесь функция RegisterBGIFont рассмотрена ниже.
Функция RegisterBGIFont
Регистрирует в графической системе загружаемый пользователем или включенный в исполняемый файл программы шрифт формата .CHR.
Заголовок функции:
Function RegisterBGIFont(Font : Pointer) : Integer;
где Font — указатель на внешнюю процедуру регистрации шрифта.
Если имеет место ошибка регистрации, функция возвращает знач<= ние, меньшее нуля. Иначе возвращается код шрифта.
ЗИ6
Turbo Pascal: учитесь программироо'"
-Ж
лава 12
Iff
Объектно-ориентированное программирова
ние
В этой главе...
	Введение в ООП
	Инкапсуляция
	Наследование
	Виртуальные методы
	Полиморфизм
	Конструкторы, динамические объекты, деструкторы
	Поля и методы: скрытые и общедоступные
В этой главе мы познакомимся с объектно-ориентированным пр граммированием, представляющим собой дальнейшее развитие идеи структурирования программ.
Что такое ООП
Объектно-ориентированное программирование (ООП)— более про грессивный метод проектирования программ, по сравнению со структурным программированием, с которым мы до сих пор имели дело. В главе 3 уже шла речь о том, что на определенном этапе развития науки о программировании пришло понимание, что всякую сложную задачу для облегчения ее решения полезно разделить на простые подзадачи. Идея заключалась в том, чтобы программа состояла не из огромного числа операторов, а из набора относительно самостоятельных частей (подпрограмм), каждой из которых назначена отдельная, сравнительно узкая роль. Подпрограммы избавили программистов от необходимости вникать в подробности реализации простейших задач: после того как соответствующая подпрограмма создана, ею можно пользоваться, не зная, как она устроена. Необходимо только быть в курсе, что делает та или иная процедура или функция.
Позже идея структурирования программ получила дальнейшее развитие. Речь идет о концепции модулей. Модуль — это компилируемый файл Turbo Pascal, в котором могут содержаться описания констант, типов данных, переменных, а также процедур и функций. Все это нам уже известно.
Так вот, ООП — это результат естественной эволюции более ранних методологий программирования. Подобно тому, как подпрограммы предоставляют программисту возможность не вникать в подробности реализации простейших задач, объекты позволяют манипулировать данными, не зная, как эти данные организованы.
Необходимо отметить, что объектно-ориентированное программирование— это не для простых программ, выполняющих несложные расчеты. Если в подобном случае применить методы ООП, такая программа будет выглядеть перегруженной излишними языковыми конструкциями. Если же создаваемая программа достаточно объемиста, средства ООП оказываются весьма и весьма кстати.
В основе объектно-ориентированного программирования лежат три основных принципа: инкапсуляция, наследование и полиморфизм. С указанными принципами мы познакомимся ниже.
318
Turbo Pascal: учитесь программировать
Инкапсуляция
Описание объекта (как и всех прочих типов) должно содержаться в разделе описаний. Данные, которые содержит объект, называются полями объекта. Описание простейшего объектного типа очень похоже на описание записи, только вместо одного зарезервированного слова ( RECORD) используется другое (OBJECT), например:
type
Dot = object
a, b : integer;
end;
Этот объектный тип, содержащий два поля, представляет собой точку на экране с координатами Ли В.
Как уже отмечалось, помимо данных в виде полей (которые могут принадлежать любому типу, в том числе и объектному), объект также может содержать подпрограммы, описывающие действия, допустимые над этими полями. Такие подпрограммы называются методами. Метод имеет доступ к полям объекта, не нуждаясь в передаче их ему в качестве параметров. Свойство объектов, содержать в себе не только данные (поля), но и описания действий, допустимых над этими данными (методы), называется инкапсуляцией.
При этом непосредственно в описании объекта присутствуют только заголовки подпрограмм, а тело каждой подпрограммы задается отдельно. Вернемся к типу Dot из предыдущего примера. Вот как выглядит описание этого объектного типа, дополненное необходимыми методами (описания полей всегда должны предшествовать заголовкам методов):
type
Dot=object
a, b :integer;
procedure Init (x,y:integer);
procedure Show;
procedure Hide;
procedure Move (Da,Db: integer);
end;
procedure Dot.Init;
begin
a:=x; b:=y;
end;
procedure Dot.Show;
лава 12. Объектно-ориентированное программирование	319
begin
PutPixel(a,b,White);
end;
procedure Dot.Hide;
begin
PutPixel(a,b,Black);
end;
procedure Dot.Move;
begin
Hide;
a:=a+Da; b:=b+Db;
Show
end;
В этом примере объект содержит четыре метода. Метод Init инищ лизирует объект (т.е. присваивает точке на экране некоторые начал ные значения). Методы Show и Hide “зажигают” и “гасят” точку на экр,. не. Наконец, метод Move перемещает точку по экрану.
После того как объектный тип объявлен, ничто не мешает создава переменные этого типа, или, следуя терминологии ООП, экземпляр объекта. Это могут быть как статические переменные, объявленные разделе описания переменных, так и динамические, созданные с пом< щью стандартной процедуры New (о динамических объектах речь пой дет в разделе “Конструкторы, динамические объекты и деструкторы” i этой главе дальше). Например:
var
Doti : Dot;
Здесь объявлена (статическая) переменная Doti (или экземпляр объекта), принадлежащая типу Dot. После того как экземпляр объекта соз дан, его поля становятся доступны для методов, хотя к полям объект возможен и непосредственный доступ— как к полям записи (этог Turbo Pascal не запрещает). Для того чтобы непосредственно применит к полю объекта какую-либо стандартную подпрограмму, достаточн воспользоваться его составным именем — указать идентификатор объ екта и (через точку) идентификатор этого поля. Однако такой подход был бы отступлением от принципов объектно-ориентированного про граммирования (ООП). ООП предполагает использование при манигг лировании полями объекта только его методов. Например:
Doti.Init(100,100);
Doti.Show;
Dotl.Move(50,50);
320
Turbo Pascal: учитесь программировал
Так же, как к записям, к объектам применим оператор WITH:
with Doti do
begin
Init(100,100);
Show;
Move(50,50);
end;
Представленные выше последовательности операторов эквивалентны.
Полный текст программы, с фрагментами которой мы только что имели дело, представлен ниже. Данная программа отображает на экране светящуюся точку (пиксель). Кроме того, отображаемую точку можно перемещать по экрану в четырех направлениях с помощью соответствующих клавиш-стрелок.
Пример 12.1
program ObjDot;
uses crt, graph;
type
Dot=object
a, b :integer;
procedure Init (x,у:integer);
procedure Show;
procedure Hide;
procedure Move (Da, Db: integer);
end;
procedure Dot.Init;
begin
a:=x; b:=y;
end;
procedure Dot.Show;
begin
PutPixel(a,b,White);
end;
procedure Dot.Hide;
begin
PutPixel(a,b,0);
end;
procedure Dot.Move;
begin
Hide;
a:=a+Da; b:=b+Db;
Глава 12. Объектно-ориентированное программирование 321
J 1 2010
Show end;
var i,j,k,Err : integer; a : char;
Doti : Dot;
begin {тело программы}
i:=detect;
initgraph(i,j,'');
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err))
else
begin
Dotl.Init(GetHaxX div 2,GetMaxY di
Doti.Show;
while KeyPressed do a:=ReadKey;
repeat
begin
a:=ReadKey;
case ord(a) of
72:Dotl.Move(0,-5);
80.‘Doti.Move(0,5);
77:Doti.Move(5,0);
75:Dotl.Move(-5,0);
end ;
end;
until a = chr(27);
end;
end.
В программе объявлен уже знакомый нам объект Dot. содержат., два поля: Л и В. которые определяют положение точки на экране, а таи же четыре метода: Init. Show. Hide и Move.
Далее следует раздел описания переменных, в котором среди прочу переменных объявлен экземпляр объекта Doti. Тело программы начи наепя с операторов, обеспечивающих переход в графический ре® Подробнее об этом можно узнать из главы 1 1
Далее следует оператор REPEAT, выявляющий нажатие опреД^1 1авиши (о том. как выявить нажатие определенной клавиши.
речь в главе 10). Оператор CASE здесь содержит четыре варианта.*5*
ЧеТЫ₽еМ -““-.ам-стрелкам.^а^ды/из У"»* обеспечивающими перевдиТГ°Д M°Ve ° *актическими параМ<)2-’ НИИ и на определенное расстояХ^™^1^ Т°ЧКИ В в ояние — на пять пикселей.
322
Turbo Pascal: учитесь прогооммиоо*
,CJ1,v. „авер.нения цикла, организованного с пом
ЕРЕАТ, является нажатие клавиши reiiencJ.	ЦЬ1<’о,,еРатоРа
Наэтомзавертиаетраб^'™^	27 (.„о
И о 1у и В( Я Программа в целом.
наследование
Предположим, мы создаем программу, в которой помимо объекта-очки, фигурирует, также объект-окружность. Конечно, можно было бы писание этого нового типа создать с нуля, подобно тому, как мы описа-и тип Dot в предыдущем разделе. Однако этот новый тип-окружность назовем его Ring) имеет много общего с существующим типом Dot. В са-1ом деле, как и точка, окружность характеризуется двумя координатами: А и В, определяющими положение ее центра. Однако для создаваемого объекта необходимо добавить поле, задающее радиус окружности.
Что касается методов, то для нового типа Ring подошел бы метод Move, тоскольку перемещение точки и перемещение окружности (собственно, ее центра) по экрану осуществляется одинаково. Однако метод, инициализирующий объект (Init), а также методы, делающие окружность видимой юти невидимой (Shown Hide), придется создать новые.
Итак, мы выяснили, что новый тип Ring кое в чем повторяет тип Dot. А нельзя ли новый тип создать на основе уже существующего, просто Добавив в него новые поля и методы? Оказывается, эго возможно благодаря свойству объектных типов, известному как наследование. Поскольку речь идет о наследовании, в соответствии с генеалогической терминологией существующий тип. служащий основой для создания нового объекта, называют предком, или родительским типом, а создаваемый объект____ потомком, или дочерним типом. Потомок автомати-
чески наследует все поля и методы своего предка.
Свойство наследования широко используется в обьектно-ориентированном программировании. Благодаря ему на основе сущесг-вующего объекта можно создать любое количество новых объектов Основываясь на этих новых объектах, можно создавать еще обьек гы- и т п	рппчки наследования ничем не ограничивается.
‘Д-, причем длина цепочки на» л м
может иметь любое количество потомков, но ири этом каждый объект можп и.
только единственного предка.
л	, ,, „ ппим типам Dot и Ring. В описании типа-
А теперь вернемся к нашим
,„от1 «-я имя роди гельского типа (в круглых скоб-Потомка должно указывал ы я имл 1	«
ках после зарезервировавши <> i лова О
type
Ring = object (Dot)
Rad : integer;
end;
Глава 12. Объектно-ориентированное программирование 323
В приведенном описании типа Ring имеется поле Rad, определяю радиус окружности, которого не было у типа Dot. Кроме того, тип Шпр унаследовал все поля своего предка (два значения типа INTEGER, опре деляющие положение точки на экране). Однако здесь пока отсутствуют методы. Вот как может выглядеть описание типа Ring, дополненное с ответствующими методами:
Ring = object (Dot)
Rad : integer;
procedure Init (x, y, r : integer);
procedure Show;
procedure Hide;
end;
procedure Ring.Init;
begin
a:=x; b:=y; Rad:=r;
end;
procedure Ring.Show;
begin
SetColor(White);
Circle(a,b,Rad);
end;
procedure Ring.Hide;
begin
SetColor(Black);
Circle(a,b,Rad);
end;
Необходимо заметить, что методы объекта-потомка заменяют code, (или переопределяют) для потомка одноименные методы родительского объекта. Иными словами, если имеет место обращение к методу Ring.Move, система смотрит, не задан ли метод с таким именем в описании объекта Ring. Если да, используется этот новый метод; если нет, используется метод, унаследованный от предка. (При этом необходим1 помнить, что переопределять можно только методы, имена полей в объ екте-потомке’не должны совпадать с именами полей родительского объекта.)
После того как тип-потомок объявлен, прежде чем приступить к ма нипулированию его полями, необходимо создать экземпляр объекта
var
ringl : ring;
324
Turbo Pascal: учитесь программировать
Виртуальные методы и полиморфизм
Давайте вернемся к методу Move из предыдущей программы. Вот его описание:
procedure Dot.Move;
begin
Hide;
a:=a+Da; b:=b+Db;
Show
end;
Вероятно, читатель обратил внимание, что изнутри метода Move имеют место обращения к методам Hide и Show. Смысл этих обращений очевиден: сначала объект делается невидимым на экране (вызывается метод Hide), затем перемещается (координаты точки на экране нужным образом изменяются) и, наконец, снова делается видимым (вызывается метод Show).
Но что произойдет, если метод Move в данном виде использовать в программе с двумя объектами: Dot и Ring? Вспомним, что метод Move наследуется объектом Ring от объекта Dot, а методы Hide и Show, поскольку сокрытие и показ окружности на экране осуществляется не так, как точки, в объекте Ring переопределяются. Так вот, для точки при этом никаких осложнений не возникает. Точка без проблем "гаснет”, меняет координаты и затем снова “зажигается”, поскольку все вызываемые здесь методы (сначала Move, а из него — Hide и Show) для объекта Dot являются “родными”.
Что касается окружности, то при вызове метода Ring.Move система пытается обнаружить метод с таким именем в описании объектного типа Ring и, не найдя его, продолжает поиск в объекте-предке. В результате имеет место обращение к методу Dot.Move. После этого из метода Move должны быть вызваны (переопределенные) методы Ring.Hide и Ring.Show, однако этого не происходит из унаследованного метода Dot.Move, экземпляр объекта Ringl, вместо Ring.Hide и Ring.Show, вызывает одноименные методы объекта Dot. Это объясняется тем, что методы Dot.Move, Dot.Hide и Dot.Show жестко связаны, поскольку они были откомпилированы в едином контексте — объектном типе Dot. Иными словами, связь между этими методами, которая была установлена при компиляции, имеет статический характер. В этом случае окажется перемещена также точка, а не окружность. (Правда, текст соответствующей программы здесь не приводится, однако читатель может самодеятельно проверить, что это именно так — для этого достаточно нуж
г лава 12. Объектно-ориентированное программирование	325
ным образом преобразовать текст примера 12.2. При нажатии нужных клавиш, которые должны бы перемещать окружность, на экране появляется вторая точка, которая и перемещается вместо окружности.)
Как же сделать так, чтобы методы Hide и Show вызывались в зависи мости от того, экземпляр какого объекта инициировал обращение к методу Move? Здесь на помощь приходит механизм, известный как динамическое (или позднее) связывание— в отличие от статического (или раннего) связывания. Указанный механизм реализуется с помощью виртуальных методов.
Заголовок виртуального метода в описании объектного типа дополняется зарезервированным словом VIRTUAL. Если в потомках этого объектного типа имеются переопределяющие методы (т.е. методы с тем же именем), они также должны быть объявлены как виртуальные и при этом иметь тот же набор формальных параметров, что и метод объекта-предка. Вот как выглядят описания объектных типов Dot и Ring с вир туальными методами:
Dot=object
a, b :integer;
constructor Init (x,y:integer);
procedure Show; virtual;
procedure Hide; virtual;
procedure Move (Da, Db: integer);
end;
Ring = object (Dot)
Rad : integer;
constructor Init (x, y, r : integer);
procedure Show; virtual;
procedure Hide; virtual;
end;
(Здесь CONSTRUCTOR— это зарезервированное слово, обозначаю щее особый вид процедуры, о котором речь пойдет в ближайшем разделе. Пока только скажем, что вызов виртуального метода должен быть предварен обращением к такой процедуре.)
Теперь вернемся к вызову экземпляром объекта Ring! метода Move, а из него — методов Hide и Show. Здесь сначала система обращается к методу Dot.Move (предварительно метод с таким именем ищется в описании объекта Ring и; поскольку его здесь нет, имеет место обращение к соответствующему методу объекта-предка). После этого для перемещения окружности сначала требуется сделать ее невидимой (вызывать метод Ring. Hide), затем нужным образом изменить координаты ее центра и, наконец, отобразить окружность в новом месте на экране (вызывать метод Ring.Show). А поскольку при выполнении программы Turbo Pascal обеспечивает обращение именно к тому виртуальному методу, которь’й
326
Turbo Pascal: учитесь программировать
определен для вызывающего объекта, из метода Dot.Move имеют место обращения к методам Ring.Hide и Ring.Show.
В заключение приведем полный текст программы, отображающей на >кране точку и окружность, которые можно перемещать, нажимая соот-етствующие клавиши.
Пример 12.2______________________________________________________________
program ObjDotCirc;
uses crt, graph;
type
Dot=object
a, b :integer;
constructor Init (x,у:integer);
procedure Show; virtual;
procedure Hide; virtual;
procedure Move (Da, Db: integer);
end;
Ring = object (Dot)
Rad : integer;
constructor Init (x, y, r : integer);
procedure Show; virtual;
procedure Hide; virtual;
end;
constructor Dot.Init;
begin
a:=x; b:=y;
end;
procedure Dot.Show;
begin
PutPixel(a,b,White);
end;
procedure Dot.Hide;
begin
PutPixel(a,b,Black);
end;
procedure Dot.Move;
begin
Hide;
a:=a+Da; b:=b+Db;
Show
лава 12. Объектно-ориентированное программирование	327
end;
constructor Ring.Init;
begin
a:=x;
b:=y;
Rad:=r;
end;
procedure Ring.Show;
begin
SetColor(White);
Circle(a,b,Rad);
end;
procedure Ring.Hide;
begin
SetColor(Black);
Circle(a,b,Rad);
end;
var i,j,k,Err:integer; a:char; DotlzDot; Ringl:Ring;
begin {тело программы)
i:=detect;
initgraph(i,j, " );
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err))
else
jegin
Doti.Init(GetMaxX div 2, GetMaxY div 2);
Doti.Show;
Ringl.Init(GetMaxX div 2, GetMaxY div 2, GetMaxY div 6);
Ringl.Show;
while KeyPressed do a:=ReadKey;
repeat
begin
a:=ReadKey;
case ord(a) of
72:Dotl.Move(0,-5);
80:Dotl.Move(0,5);
77:Dotl.Move(5,0);
75:Dotl.Move(-5,0);
73:Ringl.Move(0,-5);
81:Ringl.Move(0,5);
328
Turbo Pascal: учитесь программировать
79:Ringl.Move(5,0);
71:Ringl.Move(-5,0);
end;
end;
until a = chr(27);
end;
end.
Данная программа отличается от программы, приведенной в этой главе выше, только тем, что здесь дополнительно объявлен тип-потомок r^ing. Кроме того, методы Show и Hide обоих объектов объявлены как виртуальные, а методы Init преобразованы в конструкторы (о конструкторах речь пойдет в разделе “Конструкторы, динамические объекты и деструкторы” дальше).
Также оператор CASE в новой программе дополнен следующими вариантами:
73:Ringl.Move(0,-5);
81:Ringl.Move(0,5);
79:Ringl.Move(5,0);
71:Ringl.Move(-5,0);
Представленные варианты обеспечивают перемещение окружности по экрану в четырех направлениях. Перемещение имеет место при нажатиях клавиш <PgUp> (вверх), <PgDn> (вниз), <End> (вправо) и <Ноте> (влево), генерирующих скэн-коды соответственно 73, 81, 79 и 71.
В этой программе особое внимание следует обратить на вызовы метода Move в теле оператора CASE. В первых четырех случаях имеет место обращение к методу Dot.Move, а в остальных случаях— к методу Ring.Move. Однако мы знаем, что метод Move— единственный. Он объявлен в объекте Dot и унаследован объектом rang. Иными словами, один и тот же метод Move работает по-разному (перемещает точку или окружность), в зависимости от того, какой объект его вызывает. Такое свойство объектов называется полиморфизмом.
Конструкторы, динамические объекты и деструкторы
Как указывалось в предыдущем разделе, если в объектном типе имеется хотя бы один виртуальный метод, в нем также должен быть и специальный метод, известный как конструктор, который непременно
Глава 12. Объектно-ориентированное программирование	329
должен быть применен к экземпляру объекта до первого обращения к виртуальному методу. В силу этого конструктор обычно представляет собой метод, задающий для объекта некоторые начальные значения (т.е. выполняющий его инициализацию). Конструктор может быть определен либо в данном объекте, либо унаследован от объекта-предка. При этом сам конструктор виртуальным методом быть не может.
В описании объектного типа заголовок конструктора разнится от заголовка обычного метода только тем. что в нем зарезервированное слово PROCEDURE заменено на CONSTRUCTOR. Чем реально конструктор отличается от обычного метода? Конструктор, помимо описанных в нем действий, устанавливает связи между объектом и специальной таблицей виртуальных методов, содержащей адреса кодов, которые реализуют виртуальные методы.
Как уже отмечалось в этой главе выше, экземпляры объектных типов могут определяться как статические (в разделе описаний переменных) и как динамические, причем последнее имеет место чаще всего. Вот как можно создать динамические экземпляры объектов Doti и Ringl
var
Doti : 'Dot
Ringl : 'Ring;
begin
New(Doti, Init);
New(Ringl, Init);
Выше упоминалось, что если в объекте имеются виртуальные методы, перед обращением к ним экземпляр данного объекта должен вызвать конструктор. Как раз таким конструктором здесь является Init, который вызывается процедурой New (в качестве своего второго параметра, используя при этом расширенный синтаксис). (Пример программы, в которой экземпляры объектов Doti и Ringl объявлены в качестве динамических, имеется в конце данного раздела.)
После завершения работы с динамическим объектом выделенную для него память следует освободить. Это выполняется с помощью стан дартной процедуры DISPOSE:
Dispose (Doti, Done);
Dispose (Ringl, Done);
Здесь процедура DISPOSE обращается к деструктору DONi^ который указан в качестве ее второго параметра. В описании объектного типа заголовок деструктора отличается от заголовка обычного метода только тем, что в нем зарезервированное слово PROCEDURE заменено на DESTRUCTOR. Однако, в отличие от конструктора, зарезервированное слово DESTRUCTOR является синонимом PROCEDURE. Иными словами, метод, завершающий работу с объектом, оформляется специальным зарезервированным словом только для того, чтобы соблюсти стилистическую симметрию (если есть специальный начинающий метод.
330
Turbo Pascal: учитесь программировать
логика диктует, что должен быть и соответствующий завершающий метод). Кроме того, в отличие от конструкторов, деструкторы могут представлять собой виртуальные методы. При этом необходимо понимать что вызов деструктора Done не в качестве параметра процедуры Dispose, а самого по себе, динамическую память не освободит.
В заключение приведем текст программы, аналогичной предыдущей, в которой объекты Doti и Ringl объявлены в качестве динамических.
Пример 12.3
program ObjDotCircl;
uses crt, graph;
type
Dot=object
a, b :integer;
constructor Init (x,y:integer);
procedure Show; virtual;
procedure Hide; virtual;
procedure Move (Da, Db: integer);
destructor Done;
end;
Ring = object (Dot)
Rad : integer;
constructor Init (x, y, z : integer);
procedure Show; virtual;
procedure Hide; virtual;
destructor Done;
end;
constructor Dot.Init;
begin
a:=x;
b:=y;
end;
procedure Dot.Show;
begin
PutPixel(a,b,White);
end;
procedure Dot.Hide;
begin
PutPixel(a,b,0);
end;
procedure Dot.Move;
лава 12. Объектно-ориентированное программирование 331
begin
Hide;
a:=a+Da; b:=b+Db;
Show
end;
constructor Ring.Init;
begin
a:=x;
b:=y;
Rad:=z;
end;
procedure Ring.Show;
begin
SetColor(Black);
Circle(a,b,Rad);
end;
procedure Ring.Hide;
begin
SetColor(0);
Circle(a,b,Rad);
end;
destructor Dot.Done;
begin
Hide;
end;
destructor Ring.Done;
begin
Hide;
end;
var i,j,k,Err:integer; a:char; Doti:"Dot; Ringl:"Ring;
begin	{тело программы}
i:=detect;
initgraph(i,j,'');
Err:=GraphResult;
If Err <> grOK then
WriteLn(GraphErrorMsg(Err))
else
begin
New(Dotl,Init(GetMaxX div 2, GetMaxY div 2));
Doti".Show;
332
Turbo Pascal: учитесь программировать
New(Ringl,Init(GetMaxX div 2, GetMaxY div 2, GetMaxY div 6)); Ringl*.Show;
while KeyPressed do a:=ReadKey;
repeat
begin
a:=ReadKey;
case ord(a) of
72:Dotl*.Move(0,-5);
80:Dotl*.Move(0,5);
77:Doti *.Move(5,0);
75:Dotl*.Move(-5,0);
73:Ringl*.Move(0,-5);
81:RinglA.Move(0,5);
79-.RinglA .Move(5,0);
71:RinglA.Move(-5,0);
end;
end;
until a = chr(27);
Dispose(Dotl,Done);
Dispose(Ringl,Done)
end;
end.
В каких случаях имеет смысл использовать динамические переменные, мы выяснили при изучении указателей и использования динамической памяти (см. главу 6). Например, если программа оперирует множеством объектов (а не всего двумя, как в нашем случае) и обычной (или с татической) памяти для всех этих объектов не хватает, следует поместить их в динамическую память. Кроме того, если использование объекта начинается в середине программы или завершается задолго до ее конца, чтобы не занимать память все время, также целесообразно объявить такие объекты в качестве динамических. (Последнее для нашего примера также не актуально, поскольку экземпляры объектов здесь используются от начала и до конца; т.е. строго говоря, память с помощью деструкторов в нашей программе можно было бы и не освобождать.)
Поля и методы: скрытые и общедоступные
Поля и методы в описании объектного типа могут объявляться как скрытые, либо как общедоступные. Соответствующие разделы в описании объекта открываются директивами PRIVATE и PUBLIC. Вот так можно использовать директивы в описании типа Dot из программы, с которой мы имели дело в предыдущем разделе:
Глава 12. Объектно-ориентированное программирование 333
Dot=object
private
a, b :integer;
public
constructor Init (x,у:integer);
procedure Show; virtual;
private
procedure Hide; virtual;
procedure Move (Da, Db: integer);
public
destructor Done;
end;
В этом примере в качестве скрытых объявлены поля А и В, а также методы Hide и Move. В то же время методы Init. Show и Done имеют здесь статус общедоступных. Читатель уже понял, что каждая очередная директива PRIVATE или PUBLIC отменяет действие предыдущей директивы. При этом, если в описании типа указанных директив нет, по умолчанию считается, что все поля и методы этого типа общедоступны.
Поля и методы объекта, объявленные после директивы PRIVATE, будут доступны только в пределах данной программы или модуля. Однако если этот объект содержится в подключенном к программе модуле, идентификаторы скрытых полей и методов окажутся для программиста невидимы. При этом сам объект будет полностью открыт для использования. Для чего это нужно? Например, если это коммерческое приложение, вполне естественно, что его создатели ограничивают доступ пользователей к подробностям реализации данного приложения (в результате приложением можно пользоваться, ио его нельзя модифицировать по своему вкусу). Кроме того, часто имеет смысл ограничить доступ к некоторым полям и методам объекта, чтобы программист случайно (по недосмотру) не внес в них изменений, которые могут повлечь непредсказуемые последствия.
334
Turbo Pascal: учитесь программировать
иложение А
Интегрированная среда
В этой главе...
	Понятия и определения
	Система меню
	Команды редактора

Интегрированная среда разработчика (Integrated Devei Environment — IDE)37 включает несколько компонентов: текстов дактор (предназначенный для подготовки текстов программ), тор языка, редактор связей и отладчик. Все перечисленные ере?* становятся доступны сразу после запуска интегрированной срец.' 1 чем доступ к ним осуществляется через систему меню. С системой
мы познакомимся дальше, а прежде усвоим некоторые основные по** тия и приобретем навыки, необходимые для работы с интегрирование средой Turbo Pascal.

Основные понятия
и определения
Рабочая область интегрированной среды (рис.А. 1) содержит (или может содержать) такие элементы, как разного рода окна (есл: < ни открыты). строку меню (всегда), меню (если оно открыто). а такав подсказки (всегда). Рабочая область с открытыми окном оедактс ню показана на рис. А. 1.
Л ' ^^^^^ыраз1Х1еотчика
37 »	"**"
£сли в чрило^ еНци вам
чина или среде Turbo Pascal \ ^тРегпягпся упомшкишх <> < Рсл<-. <  ''«<
• 3Hawme, что во всех случаях/*™. •"*."//,/
336	т
• urbo Paseoi; учитесь прогри ммироврт
Ниже мы познакомимся с указанными элементами, которые могут содержаться в рабочей области, а также научимся ими пользоваться.
Информационные окна
В Turbo Pascal 7.0 пользователю придется иметь дело с двумя видами окон: информационными и диалоговыми. Первым посвящен данный раздел, вторым — следующий.
К информационным относятся окна, в которых пользователь может вводить информацию (например, тексты программ), или в которых отображается информация для пользователя. Вот какими признаками обладают информационные окна:
	содержат в заголовке порядковый номер окна;
	размеры информационных окон поддаются изменению (всех, за исключением окна CPU);
	информационные окна, будучи открыты, появляются в списке открытых окон (для того чтобы увидеть этот список, следует выбрать в меню Window пункт List);
В интегрированной среде Turbo Pascal 7.0 можно встретить шесть видов информационных окон:
	окна редактора
	окно Output
	окно Call stack
	окно Message
	окно CPU
	окна справочной системы
Для чего предназначены все эти окна и как их открыть, выясним позже.
Информационное окно обладает такими элементами, как кнопка закрытия, кнопка сворачивания-разворачивания, заголовок, линии прокрутки (кроме окна CPU), табло местоположения курсора (последнее — только у окна редактора). Все эти элементы показаны на рис. А. 1.
Чаще всего приходится иметь дело с окнами редактора, в которых содержатся тексты программ. Окно редактора (как разновидность информационного окна) можно видеть на рис. А. 1. Здесь в верхней части показана строка меню, в нижней— строка подсказки. Так вот, окно редактора расположено как раз между этими строками.
Когда окно редактора требуется убрать с экрана (или закрыть), мы пользуемся кнопкой закрытия. Эта кнопка расположена в левом верхнем углу окна (слева от заголовка) и имеет вид небольшого квадрата, заключенного в квадратные скобки. Для того чтобы закрыть окно, достаточно на этом квадрате один раз щелкнуть мышью. Кнопка закрытия
Приложение А. Интегрированная среда
337
появляется только у активного окна, в котором в данное время находится курсор (мигающая горизонтальная черта (или прямоугольник), показывающая, где будет введен следующий символ). Это легко заметить, если открыть на экране сразу несколько информационных окон (любых).
Кнопка сворачивания-разворачивания предназначена, для придания окну максимальных размеров, либо для возвращения его исходных границ (т.е. к размерам, которые данное окно имело при открытии). В соответствии с текущими размерами окна меняется и вид кнопки. Если окно имеет максимальные размеры (т.е. его можно только свернуть), кнопка имеет вид двунаправленной стрелки (см. рис. А. 1), заключенной в квадратные скобки. Если окно свернуто (и его можно только развернуть), кнопка имеет вид стрелки, направленной вверх, также в скобках. Для того чтобы изменить размеры окна, достаточно щелкнуть мышью на этой кнопке один раз. Кнопка сворачивания-разворачивания, также как и кнопка закрытия, появляется только у активного окна.
Заголовок, расположенный в верхней части окна (см. рис.А.1), включает название этого окна и его порядковый номер. Кроме того, в строке заголовка расположены кнопки закрытия и сворачивания-разворачивания. Помимо информативной (имя и порядковый номер окна), заголовок играет и функциональную роль. Для того чтобы изменить размеры окна, достаточно щелкнуть на заголовке дважды. Кроме того, за заголовок можно перетащить окно с места на место на экране. “Перетащить" означает поместить указатель мыши на заголовок, щелкнуть один раз и, не отпуская кношу мыши, переместить мышь таким образом, чтобы окно заняло нужное положение.
Линии прокрутки (см. рис. А. 1) расположены вдоль нижнего и правого краев окна редактора. Если содержимое, которое отображается в окне, в нем не помещается, с помощью линий прокрутки можно переместить скрытую в данный момент информацию в пределы окна.
У нижнего края экрана, слева от горизонтальной полосы прокрутки, расположено табло местоположения курсора. Это табло отображает два числа, разделенные двоеточием. Первое число соответствует номеру строки, в которой в данное время расположен курсор, второе — номеру позиции в строке. Табло местоположения курсора имеется только у окна редактора. Все прочие информационные (тем более, диалоговые) окна этого элемента не имеют.
Диалоговые окна
Диалоговые окна в среде разработчика Turbo Pascal предназначены для сервисных функций: создания, открытия и сохранения файлов, управления процессом отладки и управления средой. Как и информационные окна, диалоговое окно обладает кнопкой закрытия и заголовком (но без номера окна). Однако в диалоговом окне вы не найдете кнопки сворачивания-разворачивания (т.е. изменение размеров диалоговых
338	Turbo Pascal: учитесь программировать
окон, как уже отмечалось, не предусмотрено) и полос прокрутки. Впрочем если диалоговое окно в целом не может иметь полос прокрутки, то их могут иметь некоторые содержащиеся в нем элементы.
В диалоговом окне можно обнаружить такие управляющие элементы. как командные кнопки, списки, поля овода (с раскрывающимся списком и без), переключатели, флажки. Все эти элементы показаны на рис. А.2 и А.4.
Командная кнопка в диалоговом окне служит для выполнения некоторого действия. О характере этого действия можно судить по надписи на кнопке, например, OK, Cancel (Отменить), Help (Справка) (см. рис. А.2).
Список с прокруткой Кнопка раскрывающегося списка
Поле ввода
Командные кнопки
A.
Puc. A. 2. (Типичное) диалоговое окно Save File As (Сохранить как)
i les
•rjirAS
E'XFERIM.'PAS
EXPEPJM2 .PA'S GP.EP2MSG.PA5 FRNFLTR.PAS PRO6RAM1.PAS
' av - ; „ 1
СТАРЫЙ
Список в диалоговом окне представляет собой перечень чего-то (обычно файлов), в котором можно выбрать один пункт (см. рис. А.2). Такой список, если он обширный, снабжается полосой прокрутки.
Поле ввода служит, как нетрудно догадаться, для ввода некоторой информации — имени файла или каталога, либо некоторого числового значения (см. рис. А.2). Поле ввода может быть дополнено раскрывающимся списком (который еще называют списком предыстории — history list). В этом случае справа от поля присутствует стрелка вниз (см. рис. А.2). Если щелкнуть на этой стрелке, откроется список, содержащий перечень того, что вводилось в этом поле раньше в текущем сеансе работы (см. рис. А.З). Например, если это поле предназначено для ввода имени файла, который требуется сохранить на диске, в раскрывающемся списке данного поля будут содержаться имена файлов, сохранявших-
Приложение А. Интегрированная среда
339
я до этого. Если выбрать один из пунктов этого перечня и нажать кл вишу <Enter>, список закроется, а текст выбранного пункта появится поле ввода. Предположим, вы создаете, а затем сохраняете файл! Programl, Program2, РгодгашЗ и т.д. Для того чтобы каждый раз не вводит имя полностью, достаточно выбрать один из пунктов в списке, а зат< только изменить цифру. Раскрывающийся список, подобно обычно окну, снабжен кнопкой закрытия, однако его, в отличие от окна, нелг перетащить с места на место.
Рис. А.З. В этом раскрывающемся списке содержатся имена файлов, которые сохранялись раньше
Помимо полей ввода и списков, в диалоговых окнах среды Turb< Pascal часто можно встретить переключатели и флажки. Переключат ли всегда объединяются в группы. В такой группе можно выбрать только единственный переключатель. Если он выбран, то имеет вид крупной точки в круглых скобках. Если не выбран, круглые скобки пусты (рис. А.4).
Флажки, как и переключатели, также часто объединяются в группь по функциональному признаку. Однако, в отличие от переключателей, г группе можно установить любое число флажков. Если флажок установ лен, он имеет вид косого креста (который еще называют “знаком умно жения”) внутри небольшого квадрата. Если флажок не установлен (т.е сброшен), квадрат будет пуст (см. рис. А.4).
И флажки, и переключатели служат для установки различных от ций38. Для того чтобы задать в диалоговом окне нужные значения оп ций. достаточно установить должным образом все флажки и управ
;is Опция (option)— вариант, альтернатива Иными словами, опция в среде разрс ботчика Turbo Pascal — это некоторый параметр, способный принимать два ил больше значений, и значение которого определяется в диалоговом окне посредсте ' управляющего элемента (переключателя, флажка поля ввода итп.).
34Q	Turbo Pascal: учитесь программироват
ляющие кнопки, ввести в полях ввода или выбрать в списках нужные значения, а затем щелкнуть на кнопке ОК.
Группа флажков
Командные кнопки
Рис. А.4. Диалоговые окна бывают, очень разными как по размеру, так и по набору содержащихся в них управляющих элементов
Чтобы манипулировать управляющим элементом в диалоговом окне, нужно сделать этот элемент активным. Если это поле ввода, то вводить текст можно только в активное поле ввода. Устанавливать или сбрасывать можно только активный флажок (для этого служит клавиша пробела). А выбрать переключатель в группе (с помощью клавиш-стрелок) можно, только если эта группа активна. Например, на рис. А.4, где представлено диалоговое окно Debugger, активным является флажок Integrated (он выделен светлым).
В каждый момент времени в любом диалоговом окне может быть активным (или выбранным) только один управляющий элемент. Для того чтобы сделать элемент активным, достаточно щелкнуть на нем мышью. Можно также циклически осуществлять выбор элементов в диалоговом окне с помощью клавиши <ТаЬ> (вперед) или комбинации <Shift+Tab> (назад). Для того чтобы понять, как это происходит, лучше всего нажимать указанные клавиши при открытом на экране диалоговом окне.
Для того чтобы сделать элемент в диалоговом окне активным, можно также воспользоваться так называемой быстрой клавишей. Быстрая клавиша определяется буквой, выделенной в названии того или иного управляющего элемента желтым цветом. Например, на рис А.4 в названиях переключателей None, Smart и Always (в группе Display swapping) выделены соответственно буквы N, m и А. Для того чтобы выбрать в этом диалоговом окне один из этих переключателей, достаточно воспользоваться комбинацией клавиш <Alt+N>, <Alt+M> или <Alt+A>.
Приложение А. Интегрированная среда
341
Строка меню
Строка меню была показана на рис. А. 1 вместе с другими элемента ми. Отдельно она представлена на рис. А.5. В этой строке содержатся заголовки десяти меню: File (Файл), Edit (Правка), Search (Поиск), Run (Запуск), Compile (Компиляция), Debug (Отладка), Tools (Инструментальные средства) Options (Опции), Window (Окно) и Help (Справка). Для того чтобы открыть любое из этих меню, достаточн, щелкнуть один раз на его заголовке.
Открыть меню можно и без помощи мыши. Достаточно нажать клавишу <F10>, в результате заголовок одного из меню окажется выделен. После этого с помощью клавиш-стрелок остается переместить курсор на заголовок нужного меню и нажать клавишу <Enter>.
Подобно тому, как быстрые клавиши имеются у каждого элемента в диалоговом окне (см. выше), они есть у меню и пунктов меню. Так, для того чтобы открыть меню, можно нажать клавишу <Alt> и, не отпуская ее, нажать клавишу с буквой, которая выделена в названии этого меню красным цветом (это первая буква названия). Например, для того чтобы открыть меню File, следует воспользоваться комбинацией клавиш <Alt+F>. Это быстрая клавиша меню File.
IFi.le Edit Search, Run Compile Qebln; . To<1s Options Win-lpw1’ Hein'
Puc. A.5. Строка меню
Меню
Нам уже известно, для того чтобы открыть меню, достаточно щелк нуть на его заголовке в строке меню. Открытое меню (в данном случае это меню File) представлено на рис. А.6.
Меню содержит набор пунктов (или команд). Некоторые из этих пунктов светлее других (на рисунке это видно плохо, но на экране сразу бросается в глаза). Пункты, “имеющие бледный вид,” в данный момент недоступны. Например, если окно редактора не открыто и сохранять пока нечего, в этой ситуации пункты Save (Сохранить), Save As (Сохранить как) и Save АН (Сохранить все) из меню File недоступны.
Из набора "пунктов, которые содержатся в меню, можно выделить один. О том, какой пункт выделен, свидетельствует полоса более темного цвета, служащая для него фоном. Перемещать эту полосу вниз или вверх по меню можно с помощью соответствующих клавиш-стрелок. (А если при открытом на экране меню воспользоваться клавишами-стрелками вправо и влево, открываются соседние меню.) Для того чтобы инициировать действие, ассоциированное с данным пунктом меню, достаточно щелкнуть на нем один раз мышью (без необходимости предварительно его выбирать). Если мыши нет, это можно сделать и с помо
342
Turbo Pascal: учитесь программировав
Рис. А.6. Dee прочие меню выглядят приблизительно также
щью клавиатуры. Для этого сначала следует открыть нужное меню (см. предыдущий раз-;ел), затем выделить в нем нужный пункт и, наконец, нажать клавишу <Enter>.
Можно поступить и иначе. Подобно тому, как для каждого меню имеется быстрая клавиша (позволяющая открыть данное меню), своя быстрая клавиша есть и у каждого пункта меню. Например, для того чтобы выбрать пункт Open меню File, достаточно воспользоваться комбинацией клавиш <Alt+F>, а затем, когда откроется меню, нажать клавишу с буквой, которая выделена в имени нужного пункта красным цветом (для Open )то клавиша <О>).
Иногда можно сделать еще проще. Про
тив некоторых пунктов в меню указаны клавиши или комбинации клавиш (см. рис. А.6). Это так называемые горячие клавиши (hot key— не путать с быстрыми клавишами39). Для того чтобы выполнить соответствующую команду, достаточно воспользоваться этой клавишей (или комбинацией), даже не открывая при этом меню. Иными словами, горячие клавиши, принадлежащие пунктам меню, которыми вы часто пользуетесь, полезно запомнить.
Помимо пунктов и горячих клавиш, в меню могут присутствовать еще некоторые элементы. Например, пункты мо1ут быть сгруппированы внутри меню по функциональному признаку. Такие группы пунктов отделяются одна от другой горизонтальными линиями.
Если название пункта меню завершается тремя точками, это признак, что данный пункт открывает диалоговое окно. Если трех точек нет, данный пункт выполняет иное действие.
Иногда (в Turbo Pascal 7.0 только в единственном случае) в меню против имени пункта имеется небольшой черный треугольник. Это признак, что соответствующий пункт открывает подменю, содержащее свой набор пунктов. Меню с таким пунктом видно на рис. А.7 (слева). Открытое подменю показано там же справа.
19 ц puf-fjo Pascal 7.0 понятия “быстрая клавиша” и “горячая клавиша” не различаются, а между тем это разные вещи. Так. пункт меню может иметь одновременно и быструю и горячую клавишу. Для того чтобы открыть диалоговое окно Open (т.е. выбрать пункт Open из меню File), можно воспользоваться комбинацией. клавиш <Alt-> F>, чтобы открыть меню File, а затем нажать клавишу <О>, тюбы инициировать команду Open. А можно просто нажать клавишу <F3> >анная клавиша указана против соответствующего пункта меню).
Приложение А. Интегрированная среда
343
Bi rec Tools
Compi Ter. Memory si zes Linker..
Puc. A. 7. Пункт Environment меню Options (единственный в Turbo Pascal 7 О) открывает подменю
Помимо обычных меню, которые открываются из строки меню, ществует еще локальное меню. Оно открывается щелчком правой кист, кой мыши. Подробнее об этом см. в разделе “Локальное меню".
Строка подсказки
Эта строка, которая была показана на рис. А. 1 как составная час: ii рабочей области Turbo Pascal, индивидуально представлена на рис. А.8.
|Е1 Help тЗ. ваУе РЗ open Altura-.bocal menu
Puc. A.8. Наиболее используемые горячие клавиши
В исходном состоянии эта строка содержит перечень горячих к.к> виш самых популярных команд. Однако, если вы начнете что-нибудь делать, в этой строке будет появляться информация, сопровождающая ваши действия (к сожалению, по-английски). Например, если переби рать (с помощью клавиш-стрелок) пункты в каком-либо меню, в строке подсказки синхронно будут отображаться сообщения с информацией об этих пунктах. И еще пример. На рис. А.2 представлено диалоговое окне Save File As (Сохранить как) с курсором в поле для ввода имени файла. Так вот, если на экране имеется такое окно, строка подсказки будет иметь вид, как на рис. А.9.
|rl Held 1 Enter di rectory path and fi le mask
Puc. A. 9. Сообщение гласит: “Введите путь и имя файла”
Иными словами, если на экране открыто какое-нибудь диалогов^-окно или меню, в строке подсказки появляется информация по выбран ному элементу окна или выделенному пункту меню.
344
Turbo Pascal: учитесь программирован в
Если же на экране открыто какое-либо информационное окно, в строке подсказки отображается перечень наиболее употребляемых в данном окне горячих клавиш. Так, на рис. А.8 представлен перечень горячих клавиш для окна редактора, однако прочие информационные окна (например. Output или Watch) имеют собственный набор горячих клавиш.
Система меню
Эта система включает 10 меню, имена которых представлены в строке меню (см. раздел “Строка меню”): File (Файл), Edit (Правка), Search (Поиск), Run (Запуск), Compile (Компиляция), Debug (Отладка), Tools (Инструментальные средства) Options (Опции), Window (Окно) и Help (Справка). В целом о назначении команд, содержащихся в том или ином меню, позволяет судить его имя. Что касается функций каждой отдельной команды, их мы выясним при изучении каждого меню в отдельности.
Меню File
Это меню представлено на рис. А. 10.
В меню File (Файл) видны три группы пунктов (которые отделены одна от другой вертикальными линиями). Первая группа объединяет команды, предназначенные для работы с файлами (создание, открытие и сохранение файлов). Во второй группе собраны команды, в общем-то не имеющие ничего общего. Аналогично, разнородные вопросы, которые
не удалось отнести ни к одному пункту пове-1 тки дня, часто объединяют в пункте “Разное”. В третьей группе представлены имена файлов, которые открывались ранее в этом сеансе работы и затем были закрыты. Если один из таких файлов потребуется открыть повторно, можно не обращаться к пункту Open, а просто выбрать соответствующее имя внизу меню File.
Пункт New
Команда New (Создать) открывает новое окно редактора с именем NONNAMEXX.PAS, где вместо символов XX присутствуют цифры, обозначающие порядковый номер окна редактора, о скрывавшегося в данном сеансе работы.
search
^3
.«lew
Греи.
1. PROGR*M2.PAS
2. PROGRAM1.PAS
Save as. > v: « «Л -¥•'
Save all
ch’nge dir
Pri nt
Pointer setup,.-DOS shell
Exit	Alt+X
Рис. A. 10. Команды для работы с файлами
Приложение А. Интегрированная среда
345
Пункт Open
Открывает диалоговое окно Open a File (Открыть файл), которое можно видеть на рис. А. 11.
Рис. А.11. Здесь можно указать файл, который требуется открыть
В этом диалоговом окне имеется поле ввода Name (Имя), предназн.. ченное для ввода имени файла, который требуется открыть. Если нужный файл содержится не в текущем каталоге, помимо имени файла, здесь придется указать также и путь.
Если имя файла сходно с именами файлов, которые открывались ра нее (в данном .сеансе работы), подходящее имя можно выбрать в рас врывающемся списке (или в списке предыстории), а когда в результате оно отобразится в поле ввода, здесь его отредактировать. Как пользоваться раскрывающимся списком, мы выяснили в разделе “Основные понятия и определения”.
Нужный файл можно также (чтобы не вводить его имя и путь в поле ввода) выбрать в списке (с прокруткой) Files (Файлы). Изначально, при открытии окна Open, в этом списке отображается содержимое текущего каталога. В любом каталоге могут содержаться как файлы (они представлены именем файла и расширением), так и вложенные каталоги (в списке присутствует имя каталога, дополненное обратной косой чертой). Если такой вложенный каталог открыть, там тоже обнаружатся файлы и, возможно, свои вложенные каталоги. И здесь же непременн» (если этот каталог не корневой) будет каталог, имя которого представлено двумя точками с обратной косой чертой. Это каталог верхнего уровня (или родительский каталог), в который вложен каталог, содержимое которого сейчас перед вами. Если попытаться открыть такой каталог, будет осуществлен переход в иерархии каталогов на уровень выше. Иными
346
Turbo Pascal: учитесь программировав
словами, открывая вложенные каталоги или каталоги верхнего уровня, можно таким образом перейти в нужный каталог, где содержится интересующий нас файл.
Оказавшись в нужном каталоге, следует выделить какой-либо файл, чтобы его имя оказалось в поле ввода Name. После этого остается только щелкнуть на кнопке Open, чтобы выбранный файл открылся в собственном окне.
В нижней части диалогового окна Open a File отображается информация о файле, выделенном в списке с прокруткой: путь к файлу, имя файла, объем, а также дата и время его последнего изменения.
Наконец, в диалоговом окне имеются четыре командные кнопки. Кнопка Open открывает файл, имя которого содержится в поле ввода. Кнопка Replace (Замена) загружает указанный файл в активное окно редактора, удаляя при этом его предыдущее содержимое. Кнопка Cancel (Отмена) закрывает диалоговое окно (если вы вдруг передумали открывать файл). Наконец, кнопка Help (Справка) вызывает окно справочной системы с информацией по диалоговому окну Open a File.
Инициировать команду Open можно также, воспользовавшись клавишей <F3>.
Пункт Save
Сохраняет (т.е. переписывает из оперативной памяти на диск) файл, содержащийся в активном окне редактора. Если данный файл до этого еще ни разу не сохранялся, при выборе пункта Save (Сохранить) открывается диалоговое окно Save File As (Сохранить как, см. следующий раздел), в нем можно указать имя (и путь), под которым данный файл следует сохранить.
Инициировать команду Save можно также, воспользовавшись клавишей <F2>.
Пункт Save as
Открывает диалоговое окно Save File As (Сохранить как) которое можно видеть на рис. А. 12.
В этом диалоговом окне имеются те же управляющие элементы, что и в окне Open a File (см. раздел “Пункт Open” выше). Указать файл, который требуется сохранить, означает сделать так, чтобы его имя оказалось в поле ввода Save file as. Как это делается, мы выяснили в разделе “Пункт Open”.
В окне Save File As имеется свой, несколько отличающийся набор командных кнопок. Кнопка ОК инициирует сохранение файла, имя которого содержится в поле ввода. Что касается кнопок Cancel и Help, то их функции те же. что и у одноименных кнопок в окне Open a File.
Приложение А. Интегрированная среда
347
\FROGRA~1\TP/\SIN ».PAS
PAS	4 3	' May 13. 1991- 12:-1pp
Puc. A. 12. Здесь можно указать имя файла и каталог на диске, где требуется сохранить указанный файл
A? Pt'S EX°ERil4.P4Sf E‘S'ERIMl.PAS Z <r£Rlri2.PAS' GREb2& SC PAS PINFLTR.dAS
гйО<ЖАЩ PAS' a\ СТАРЫЙ~1'
i les
Пункт Save all
Команда Save all (Сохранить все) сохраняет все открытые в данный момент файлы (собственно, только те из них, в которые были внесены изменения). Если какие-либо из открытых файлов до этого ни разу не сохранялись, для них всех по очереди откроется диалоговое окно Save File As.
Пункт Change dir
Открывает диалоговое окно Change Directory (Изменение каталога), которое можно видеть на рис. А. 13.
Это диалоговое окно предназначено для изменения текущего каталога. Текущий каталог — тот. содержимое которого автоматически отображается в диалоговых окнах Save File As и Open a File при их открытии.
Диалоговое окно Change Directory содержит знакомые нам поле ввода (с раскрывающимся списком) и список с прокруткой. В поле ввода Directory name (Имя каталога) отображается путь к текущему каталогу. В списке с прокруткой представлен этот путь (символами псевдографики), а также каталоги, вложенные в текущий каталог. Здесь он выделен желтым цветом.
Кроме того, в этом окне имеются четыре командные кнопки. Кнопка Chdir позволяет сменить текущий каталог. Для этого новый каталог прежде следует выбрать в списке с прокруткой (либо ввести соответствующий путь в поле ввода), а затем щелкнуть на кнопке Chdir (либо дважды щелкнуть на нужном каталоге в списке с прокруткой). В результате текущий каталог окажется изменен.
348
Turbo Pascal: учитесь программировать
-TP?
APbtft- J
' - TIN
Di'2Ctory ree
Puc. A. 13. Здесь мож но изменить текущий каталог
Для того чтобы ввести в действие это изменение и закрыть диалоговое окно, следует щелкнуть на кнопке ОК. Кнопка Revert (Вернуть) позволяет отменить последнее изменение текущего каталога (если еще не было щелчка на кнопке ОК). Например, если ранее текущим был каталог BIN, затем текущим вы сделали иной каталог и после этого передумали, то можно все вернуть назад, тут же щелкнув на кнопке Revert. И наконец, знакомая нам кнопка Help позволяет вызвать окно справочной системы с информацией по диалоговому окну Change Directory.
Пункт Print
Команда Print (Печать) инициирует печать содержимого активного <>кна редактора.
Пункт Printer setup
Открывает диалоговое окно Printer Setup (Установка принтера), которое можно видеть на рис. А. 14.
Рис. А. 14. Здесь можно указать, какой принтер подключен к вашему ПК
'оиложение А. Интегрированная среда
349
Это диалоговое окно содержит два поля ввода, один флажок и Tpi командные кнопки.
Поле ввода Filter path (Путь к файлу фильтра) должно содержать имя (и, возможно, путь) файла-фильтра принтера (PRNFLTR.EXE).
Поле ввода Command line (Командная строка) позволяет указать тит вашего принтера, а также задать параметры командной строки. ТигЬ Pascal поддерживает три типа принтеров: матричные типа EPSON, лазерные типа HP LaserJet и PostScript-принтеры.
Значения, которые допускается вводить в поле Command line, пере числены в табл. Л. 1.
Таблица А. 1. Параметры командной строки для установки принтера
Командная строка	Назначение
$NOSWAP /ASCII	Установка для принтера неизвестного типа. На принтер посылаются только символы текста и коды конца строки
$NOSWAP /EPSON	Установка для устройств, совместимых с матричным принтером Epson
$NOSWAP /HP	Установка для устройств, совместимых с лазерным принтером HP LaserJet
$NOSWAP /PS	Установка для принтеров, использующих PostScript — аппаратно-независимый язык описания страниц
$NOSWAP /0<файл>	Установка для вывода в файл. Здесь <файл> - имя файла (и путь), в который направляется вывод. Вместо имени фай ла можно указать стандартное устройство MS DOS (например, LPT1)
/Lxxx	Задает количество строк на страницу (по умолчанию 55)
/Txx	Задает количество пробелов, которым должен быть эквива лентен один символ табуляции (по умолчанию 8)
Примечание
Параметры, задающие количество строк и количеств* пробелов (последние два), могут дополнять установки определяющие тип принтера.
Флажок Send highlighting escape codes (Пересылать выделяющие
Escape-коды) позволяет задать пересылку на принтер вместе с печатае мым текстом, кодов Escape-последовательностей, с тем чтобы выделен
ная на экране информация печаталась курсивом, полужирным или подчеркнутым шрифтом.
Кнопка ОК закрывает диалоговое окно и вводит в силу сделанные и нем установки. Кнопка Cancel отменяет сделанные в окне изменения
Кнопка Help вызывает окно системы справки с информацией по диало говому окну Printer Setup.
350
Turbo Pascal: учитесь программировать
Пункт DOS shell
Команда DOS shell (среда DOS) отображает экран с командной строкой MS DOS (иными словами, осуществляет так называемый временный выход в DOS). Это делается, когда необходимо выполнить какую-iii' JO команду операционной системы, например удалить файл или создать каталог. Данная возможность позволяет, не выходя из среды Turbo pascal, выполнять команды MS DOS.
Ддя того чтобы вернуться в интегрированную среду разработчика, достаточно ввести в командной строке MS DOS команду EXIT. ,,.
Пункт Exit
Команда Exit (Выход) служит для выхода из интегрированной среды разработчика (по завершении работы).
Инициировать команду Exit можно также, воспользовавшись комбинацией клавиш <Alt+X>.
Меню Edit
Как выглядит меню Edit (Правка), демонстрирует рис. А. 15.
Пункты в этом меню разделены на три группы. Первая включает две команды, позволяющие отменить последнее действие. Вторая объединяет четыре команды, использующие буфер обмена (clipboard). В третьей группе содержится единственная команда, также имеющая отношение к буферу обмена, назначение которой мы выясним в соответствующем разделе дальше.
Рис. А. 15. Команды для редактирования текста
Пункт Undo
Отменяет последнее действие, связанное с редактированием текста в окне редактора. Например, если вы вырезали фрагмент текста, а затем решили все вернуть, можно воспользоваться командой Undo (Отменить). Выполнив эту команду несколько раз подряд, можно отменить последовательность действий (в обратном порядке).
Инициировать команду Undo можно также, воспользовавшись комбинацией клавиш <Alt+Backspace>.
Приложение А. Интегрированная среда
351
Пункт Redo
Отменяет результат последнего использования команды Undo. Молено сказать, что команда Redo (Повторить) “отменяет отмену”.
Пункт Cut
“Вырезает” текст, выделенный в окне редактора, и помещает его в буфер обмена. Выделить текст— означает поместить указатель мыши на символ в строке, с которого начинается нужный фрагмент текста, а затем нажать кнопку мыши и провести по диагонали указателем по гек-сту— вплоть до символа в последней строке, которым этот фрагмент оканчивается. В результате соответствующий фрагмент текста окажется выделен фоном иного цвета. Если теперь выбрать пункт Cut (Вырезать), выделенный текст будет удален из окна редактора и помещен в буфер обмена.
Буфер обмена— это область в оперативной памяти компьютера, предназначенная для временного хранения вырезанных (или скопированных, см. следующий раздел) данных. Что можно делать с содержимым буфера обмена, мы выясним в разделе “Пункт Paste".
Инициировать команду Cut можно также, воспользовавшись комбинацией клавиш <Shift+Del>.
Пункт Сору
Копирует в буфер обмена текст, выделенный в окне редактора. Команда Сору (Копировать) отличается от команды Cut только тем, что копируемый в буфер обмена текст при этом из окна редактора не удаляется.
Инициировать команду Сору можно также, воспользовавшись комбинацией клавиш <Ctrl+Ins>.
Пункт Paste
Вставляет содержимое буфера обмена в место в активном окне редактора, где в настоящее время расположен курсор.
С помощью команд Cut, Сору и Paste (Вставить) можно не только переместить текст в окне с одного места на другое, но и перенести его в другое окно. Кроме того, упомянутые выше команды можно использовать не только в окне редактора Turbo Pascal, но и в любом другом месте, где требуется вводить текст, например в поле ввода в диалоговом окне.
Инициировать команду Paste можно также, воспользовавшись комбинацией клавиш <Shift+Ins>.
352
Turbo Pascal: учитесь программировать
Пункт Clear
Команда Clear (Очистить) удаляет выделенный текст, не помещая его при этом в буфер обмена.
Инициировать команду Clear можно также, воспользовавшись комбинацией клавиш <Ctrl+Del>.
Пункт Show clipboard
Выводит на экран окно Clipboard, отображающее текущее содержимое буфера обмена.
Меню Search
Меню Search (Поиск) можно видеть на рис. А. 16.
Пункты этого меню разделены на две группы. Команды первой группы предназначены для поиска и замены текста. Во второй группе собраны команды, также позволяющие осуществлять разного рода поиск.
Пункт Find
Рис. А. 16. Команды для поиска
Эта команда позволяет открыть диалоговое окно Find (Поиск, см. рис. А. 17).
Рис. А. 17. Здесь можно указать, что и как нужно искать
В диалоговом окне имеется поле ввода, позволяющее задать текст для поиска, а также несколько групп переключателей и флажков.
Приложение А. Интегрированная среда
353
12—2016
Для того чтобы инициировать поиск, следует ввести нужный текст в поле Text to find (Текст для поиска) и щелкнуть на кнопке ОК. В результа те будет осуществлен поиск указанного текста в содержимом активного окна редактора. В случае обнаружения текста, он будет выделен.
Содержащиеся в диалоговом окне переключатели и флажки позво ляют задавать различные опции поиска. Группа флажков Options (Опции) конкретизируют поиск. Если флажок Case sensitive (Учитывать регистр) установлен, осуществляется поиск только текста, в котором прописные и строчные буквы строго те же. что и в тексте, заданном в поле ввода Text to find.
Флажок Whole words only (Только слова целиком) указывает, что требуется искать только текст, не являющийся фрагментом других слов. Например, если для поиска задан текст кот, то при установленном флажке Whole words only будет найдено именно это слово, но не слова который, антрекот или слякоть.
Если установлен флажок Regular expression (Спецификаторы), Turbo Pascal будет различать спецификаторы (т.е. символы, имеющие специальное значение), содержащиеся в заданном для поиска тексте. Перечень спецификаторов для поиска представлен в табл. А.2.
Таблица А.2. Спецификаторы для поиска
Спецификатор Функция спецификатора
Если данный символ присутствует в начале поисковой строки, будут найдены только вхождения искомого текста, представляющие собой начала строк
$ Этот символ в конце поисковой строки, задает поиск только концов строк
. (точка) Если в поисковой строке вместо отдельных символов присутствуют точки, будут найдены все вхождения текста, у которых вместо точек может быть такое же число любых символов. Например, при поисковой строке в.. ы окажутся обнаружены слова волы, возы, вязы, вилы и т.д.
Если в поисковой строке после какого-либо символа присутствует звездочка (*), будут найдены все вхождения текста, в которых этот символ повторяется любое число раз (в том числе ни одного). Например, при поисковой строке too* окажутся обнаружены фрагменты текста to, too, tooo, toooo и т.д.
+	' Ёсли в поисковой строке после какого-либо символа присутствует плюс
(+), будут найдены все вхождения текста, в которых этот символ повторяется любое число раз (но не меньше одного). Например, при поисковой строке too+ окажутся обнаружены фрагменты текста tooo, toooo, tooooo и т.д.
354
Turbo Pascal: учитесь программировать
Окончание табл. А.2.
Спецификатор Функция спецификатора
[ ] Если в поисковой строке некоторый набор символов заключен в квадратные скобки, будут найдены все вхождения текста, в которых вместо этого набора в скобках присутствует любой символ из указанного набора. Например, при поисковой строке t[abc]o окажутся обнаружены фрагменты текста и tao, и tbo, и tco
["] Если в поисковой строке набор символов, перед которыми имеется символ ", заключен в квадратные скобки, будут найдены все вхождения текста, в которых вместо этого набора в скобках присутствует любой символ, не входящий в указанный набор
[-] Если в поисковой строке имеются два символа в квадратных скобках с тире между ними, будут найдены все вхождения текста, в которых вместо этих скобок присутствует любой символ из указанного диапазона. Например, при поисковой строке t[a-c]o окажутся обнаружены фрагменты текста и tao, и tbo, и tco
\ Позволяет осуществлять поиск символов, являющихся спецификаторами. Например, если при установленном флажке Regular expression потребуется найти в тексте символ ' (именно как символ, а не как спецификатор), для этого в поисковой строке следует задать \"
Группа Direction (Направление поиска) состоит из двух переключателей. Переключатель Forward (Вперед) задает направление поиска вперед (к концу текста). Переключатель Backward (Назад) задает направление поиска назад (к началу текста).
Группа Scope (Область поиска) также состоит из двух переключателей. Переключатель Global (Весь текст) определяет, что поиск будет осуществляться по всему тексту, а переключатель Selected text (Только выделенный текст) — только по выделенному фрагменту текста.
Наконец, группа Origin (Исходная точка для поиска), как и предыдущие две группы, также содержит два переключателя. Переключатель From cursor (От курсора) дает знать системе, что поиск должен осуществляться от текущего положения курсора (к концу или к началу текста, либо выделенного фрагмента), а переключатель Entire scope (Весь текст) — от начала и до конца (или от конца к началу) всего текста (или только выделенного фрагмента) в зависимости от установок соответствующих опций.
В диалоговом окне Find имеются также три командные кнопке— ОК, Cancel и Help. Назначение их то же, что и одноименных кнопок из других диалоговых окон, о которых шла речь выше.
Приложение А. Интегрированная среда
355
12*
Пункт Replace
Открывает диалоговое окно Replace, которое можно видеть пц рис. А. 18.
Рис. А. 18. Здесь можно задать текст для поиска и замены
Нетрудно заметить, что это окно очень похоже на окно Find. Здесь тоже имеется поле ввода Text to find, предназначенное для ввода поисковой строки. Кроме того, есть также поле ввода New text (Новый текст). Назначение этих полей достаточно очевидно: в поле Text to find вводится заменяемый текст (который система предварительно находит), а в поле New text — заменяющий текст.
В диалоговом окне Replace имеются те же группы опций, что и в окне Find: Options, Scope, Direction и Origin, выполняющие те же функции Единственное отличие в том, что в группе Options имеется одна новая опция— Prompt on replace (Запрос перед заменой). Если соответствующий флажок установлен, система перед каждой заменой будет запрашивать подтверждение.
В диалоговом окне Replace имеются те же командные кнопки (с теми же функциями), что и в окне Find, за исключением одной новой кнопки — Change АН (Заменить все). Если пользоваться кнопкой ОК, замены будут осуществляться по одной, а если щелкнуть на кнопке Change АП, будет выполнена глобальная замена (всех фрагментов текста, соответствующих поисковой строке в поле Text to find).
Пункт Search again
Повторяет команду Find или Replace, которая выполнялась последней. Например, первое вхождение поисковой строки в тексте найдено с помощью команды Find. Теперь, чтобы продолжить поиск других вхож-
356
Turbo Pascal: учитесь программировать
цений в этом тексте, можно инициировать команду Search again, до тех пор, пока не будет достигнут конец текста.
Пункт Go to line number
Открывает диалоговое окно Go То Line Number (Перейти к строке с указанным номером), которое представлено на рис. А. 19.
В этом окне имеется единственное поле ввода Enter new line number (Введите новый номер строки). Данная команда позволяет перейти в тексте про-
Рис. А. 19. Здесь можно указать номер строки, к которой, требуется перейти
граммы к строке с указанным порядковым номером.
Пункт Show last compiler error
Команда Show last compiler error (Показать последнюю ошибку компи-штора) перемещает курсор к месту ошибки, которая была зафиксирована при последнем использовании команды Run (Запуск) из одноименного меню.
Пункт Find error
Открывает диалоговое окно Find error (Поиск ошибки), которое можно видеть на рис. А.20.
Если программа запускается из интегрированной среды разработчика Turbo Pascal, то в случае возникновения ошибки времени исполнения (например, попытки деления на ноль) на эк-
Рис. А.20. Здесь можно указать адрес ошибки, по которому в тексте программы будет найдено место с ошибкой
ране появляется текст программы с курсором, установленным на месте ошибки. Однако, если программа запус
калась вне среды Turbo Pascal или компилировалась без привлечения средств отладки и имеет место ошибка, следует записать два шестнадцатеричных числа, присутствующих в сообщении об ошибке. Зная эти числа, можно вернуться в среду Turbo Pascal, открыть диалоговое окно Find Error, ввести в поле ввода Error address (Адрес ошибки) указанные
Приложение А. Интегрированная среда
357
числа, щелкнуть на кнопке ОК и в результате будет найдено место в тек сте программы, содержащее ошибку.
Два разделенные двоеточием шестнадцатеричных числа, о которых идет речь, представляют собой адрес в памяти, по которому произошла ошибка. Причем первое число — это сегмент, второе — смещение.
Пункт Find procedure
Рис. А.21. Здесь можно задать имя подпрограммы, описание которой требуется найти
Открывает диалоговое окно Find procedure (Поиск процедуры), которое можно видеть на рис. А.21.
В этом окне имеется поле ввода Procedure name (Имя процедуры), в котором можно ввести имя процедуры или функции. Если после этого щелкнуть на кнопке ОК, осуществится поиск нужной подпрограммы.
Чем команда Find procedure отличается от Find? Ведь можно вызвать диалоговое окно Find, ввести в него имя нужной под
программы и осуществить поиск? Дело в том, что команда Find будет реагировать не только на имя подпрограммы в ее заголовке, там где она объявлена в начале программы, но и на все вызовы этой подпрограммы в теле программы. В то же время команда Find procedure найдет именно заголовок описания нужной процедуры.
Меню Run
Рис. А. 22. Команды для запуска программы
Меню Run (Запуск) можно видеть на рис. А.22.
Команды этого меню предназначены для прогона в различных режимах программы из активного окна.
Пункт Run
Осуществляет компиляцию и запуск программы, исходный текст которой находится в активном окне редактора Turbo Pascal. Если программа откомпилирована, сразу выполняется ее запуск.
358
Turbo Pascal: учитесь программировать
щцциировап. команду Run можно также ,ей клавиш <Ctrl+F9>.
воспользовавшись комби-
Пункт Step over
Команда Step Over (По шагам) последовательно выполняет операторы одному за раз в текущей подпрограмме или основной программе. Ес-( при этом встретится вызов иной подпрограммы, команда выполнит о как обычный оператор и перейдет к следующему оператору. Иными [овами. Step Over не осуществляет пошаговое прослеживание операто->в внутри вызываемых подпрограмм.
Для того чтобы инициировать команду Step Over, можно также вос-льзоваться клавишей <Е8>.
Пункт Trace into
Команда Trace into (Трассировать подпрограммы), подобно Step Over, юследовательно выполняет операторы по одному за раз в текущей под-1рограмме или основной программе. Однако, если при этом встретится !ызов иной подпрограммы, команда Trace into, в отличие от Step Over, ерей дет в эту подпрограмму' и при последующих вызовах, будет осуще-твлять пошаговое прослеживание операторов внутри подпрограммы.
Для того чтобы инициировать команду Trace into, можно также воспользоваться клавишей <F7>.
Пункт Go to cursor
Команда Go to cursor (Выполнить до курсора), подобно Step Over, по-о-омаида	опеоаторы по одному за раз в текущей под-
следовательно выполняет опера 1 р	э	otpn Over
„„„й ппогвамме. Однако, в отличие от otep over, программе или основной npoi раммс.	__
рограмме ил1	-олпяются от текущего оператора и до курсора,
операторы по шагам выполняй	э	r-nrcnr можно также
Для того чтобы инициировать команду Go to cursor, можно также воспользоваться клавишей <Р4>.
Пункт Program reset
Приостанавливает процесс отладки, освобождает выделенную для программы память и закрывает все файлы, которые программа использует. Для того чтобы инициировать команду Program reset (Сброс программы), можно также воспользоваться комбинацией клавиш <Ctrl+F2>.
Пункт Parameters
Открывает диалоговое окно Program Parameters (Параметры программы). представленное на рис. А.23.
Ъилткение А Интегрированная среда
359
Рис. А.23. Здесь можно указать параметры, которые будут переданы вызываемой программе
В этом окне имеется поле ввода Parameter (Параметр), предназначенное для ввода параметров командной строки, которые будут переданы программе, содержащейся в окне редактора Turbo Pascal, при ее запуске. Имя самой программы вводить здесь не нужно.
Меню Compile
Рис. А. 24. Команды для компиляции
Как выглядит меню Compile (Компиляция), позволяет судить рис. А.24.
В этом меню все пункты объединены в три группы. В первой группе собраны команды, осуществляющие компиляцию в разных режимах. Во второй группе содержаться команды, выполняющие подготовительные перед компиляцией действия. Наконец, единственная команда третьей группы предоставляет информацию о результатах компиляции.
Пункт Compile
Компилирует файл программы или модуля, содержащийся в активном окне редактора Turbo Pascal. Если из этого файла вызываются какие-либо нестандартные модули (которые не входят в комплект поставки Turbo Pascal 7.0), то они должны быть заранее откомпилированы и присутствовать на диске в виде файлов с расширением .TPU.
Для того чтобы инициировать команду Compile (Компилировать), также можно воспользоваться комбинацией клавиш <Alt+F9>.
Пункт Маке
Команда Маке (Сборка) создает исполняемый файл программы (ЕХЕ-файл), который может содержать обращения к нестандартным модулям. При этом действуют следующие правила:
360
Turbo Pascal: учитесь программировать
	если ранее был задан начальный файл программы (с помощью команды Primary File, см. далее), компилируется этот файл; в противном случае компилируется файл, содержащийся в активном окне редактора Turbo Pascal; при этом система проверяет все файлы модулей, к которым обращается начальный файл;
	если после последней компиляции какого-либо из модулей, файл с его исходным кодом (PAS-файл) претерпел изменения, этот модуль перекомпилируется; если же претерпела изменения интерфейсная часть некоторого модуля, перекомпилируй^! ся все модули, обращающиеся к данному модулю; при этом, если файл с исходным кодом (PAS-файл) обнаружен не будет, система использует имеющийся TPU-файл независимо от даты его создания;
Для того чтобы инициировать команду Маке, можно также воспользоваться клавишей <F9>.
Пункт Build
Команда Build (Полная сборка), в отличие от команды Маке, перекомпилирует все TPU-файлы, к которым обращается начальный файл, независимо от даты их создания.
После успешной компиляции программы (с помощью команды Compile, Make или Build) на экране появляется диалоговое окно Compiling (Компиляция), которое можно видеть на рис. А.25.
SL-
Ma in.fi1е: GREP2MSG-РAS
Dona, ч	........ "	....
Destination:. Memory	Line -in iber:	J
' Free memory:; 298K	Total lines.	67
com; ile successful: Гг-ss any
Рис. А.25. Компиляция завершена
Для того чтобы закрыть это окно и снова получить доступ к исходному тексту программы, достаточно нажать любую клавишу.
Пункт Destination
Команда Destination (Место назначения) определяет, куда должна компилироваться программа при выборе пунктов Compile, Make или Build. Компиляция может осуществляться в память или в файл на диске. Место для компилируемой программы указывает слово в меню рядом с пунктом Destination. Возможны два варианта: Disk (Диск) и Memory
Приложение А. Интегрированная среда	361
(Память). При каждом выборе пункта Destination текущая установка меняется на противоположную.
В случае компиляции в память исполняемый код программы заносится в оперативную память компьютера и будет утрачен при выходе из среды разработчика Turbo Pascal. При компиляции на диск создается исполняемый файл с расширением .EXE.
Пункт Primary file
Открывает диалоговое окно Primary File (Начальный файл), которое можно видеть на рис. А.26.
Рис. А.26. Здесь можно указать начальный файл для компиляции
Это диалоговое окно позволяет задать имя начального файла, с которого будет начинаться компиляция программы при выборе пункта Маке или Build меню Compile. Обычно в качестве начального указывается файл с основной программой. Если начальный файл указан, не играет роли, какой файл в данное время открыт в активном окне редактора — файл основной программы или какого-либо модуля. В этом случае система начнет компиляцию с основного файла и сумеет правильно построить программу. Если же начальный файл не указан, для правильной компиляции необходимо, чтобы в активном окне редактора был открыт файл с основной программой.
Диалоговое окно Primary File очень похоже на знакомые нам окна Open a File и Save As. Здесь также имеется поле ввода (Primary program file — Файл основной программы), позволяющее задать файл. Чтобы не вводить имя файла (и путь) вручную, нужный файл можно выбрать в списке с прокруткой Files, перейдя при необходимости в иной каталог. Когда в поле Primary program file появится нужная информация, чтобы
362
Turbo Pascal: учитесь программировать
лести сделанную установку в действие, следует щелкнуть на кнопке ОК. Кнопка Clear (Очистить) позволяет удалить имя файла, присутствующее в поле Primary program, и закрыть при этом диалоговое окно. Что касается кнопок Cancel и Help, то их назначение то же, что и в других диалоговых окнах, с которыми мы познакомились раньше.
Пункт Clear primary file
Команда Clear primary file (Очистить начальный файл) позволяет удалить значение, заданное ранее в качестве имени начального файла (с помощью команды Primary file).
Пункт Information
Открывает диалоговое окно с информацией о программе, компилировавшейся последней, и об использовании памяти (рис. А.27).
----------- Program
Source compiled:
Code size:
Data size:
Stack size:
Minimum heap size:
Maximum heap size:
"И res bytes bytes bytes bytes
67 23488
9156
16384
0______
655360 bytes
--- Memory
DOS:
IDE: Symbols: Program:
Free: ----- EMS -
68К 271К.
2К 298К ОК.
Status: GREP2MSG.PAS running.
IDE: Other Free:
400к
224к
400К
Puc. A.27. Данные о компиляции
Меню Debug
Меню Debug (Отладка) можно видеть на рис. А.28.
Пункты этого меню объединены в две группы, разделенные горизонтальной чертой. Пункты первой группы открывают различные окна, позволяющие в режиме отладки следить за разными аспектами программ. Пункты второй группы предназначены для обслуживания режима отладки.
Приложение А. Интегрированная среда
363
Greakpoi nts... •
Call stack	Ctrl+F3
Register
watch
user screen .	‘-• 'x'•' "Alt+FS' •
•Evaluate/modify. .. Ctrl+F4
-*Add watch...	1 Ctrl+F? a
Aad b'-eakpo’’ nt.. .
Puc. A. 28. Команды для отладки программ
Пункт Breakpoints
Эта команда открывает диалоговое окно Breakpoints (Контрольные точки), которое представлено на рис. А.29.
Рис. А. 29. Отсюда можно управлять контрольными точками
Данное окно позволяет увидеть перечень существующих в программе контрольных точек и манипулировать ими. Контрольная точка— это место в программе, на котором программа при определенных условиях (или всегда) приостанавливает работу. В программе можно установить произвольное количество контрольных точек.
Для чего нужны контрольные точки? Предположим, созданная программа не работает как нужно и подозрение падает на определенное место в программе. Контрольная точка позволяет организовать останов работы программы в этом месте и исследовать значения различных переменных и выражений для выявления ошибки.
Основной управляющий элемент диалогового окна Breakpoints — список с прокруткой Breakpoint list (Список контрольных точек). В первом столбце списка указано имя файла, которому принадлежит данная контрольная точка. Во втором столбце Line # (Номер строки) указан порядковый номер строки в соответствующем файле, где установлена кон-
364
Turbo Pascal: учитесь программировать
грольная точка. В третьем столбце Condition (Условие) содержится условие останова программы на данной контрольной точке. Наконец, в четвертом столбце Pass (Проход) задано количество обращений к строке с этой контрольной точкой.
Иными словами, останов будет иметь место на определенном по счету обращении к данной строке (соответствующее число указано в столбце Pass), если окажется выполнено условие, заданное в столбце Condition. (Однако в столбцах Condition и Pass может ничего не быть задано. В этом случае останов будет каждый раз.) Условие может представлять собой любое допустимое выражение типа Boolean, которое вычисляется в ходе работы программы. Если условие задано, останов возможен только когда соответствующее выражение принимает значение TRUE.
(Контрольные точки, не содержащие никаких условий (безусловные контрольные точки), можно устанавливать с помощью команды Toggle breakpoint (Установка/удаление контрольной точки) из локального меню (которое вызывается щелчком правой кнопки мыши — см. раздел “Локальное меню”).
В диалоговом окне Breakpoints также имеются шесть командных кнопок. Если назначение кнопок ОК и Help здесь то же, что и в других окнах, то остальные кнопки требуют более пристального внимания.
Кнопка Delete (Удалить) удаляет из файла выделенную в диалоговом окне контрольную точку.
При выделенной в диалоговом окне контрольной точке кнопка View (Просмотр) открывает файл в окне редактора Turbo Pascal и переводит курсор в соответствующую строку.
Кнопка Clear all (Удалить все) удаляет все существующие контрольные точки во всех файлах.
Наконец, кнопка Edit (Правка) открывает диалоговое окно Edit Breakpoint (Редактирование контрольной точки), позволяющее отредактировать параметры выделенной в окне Breakpoints контрольной точки (рис. А.30).
Рис. А.30. Здесь можно отредактировать параметры контрольной точки
Приложение А. Интегрированная среда
365
Здесь имеются четыре поля ввода: Condition (Условие), Pass count (Номер прохода). File name (Имя файла) и Line number (Номер строки), позволяющие задать для выделенной контрольной точки новые значения соответствующих параметров. Имеются также четыре командные кнопки. Кнопка Modify (Преобразовать) вводит в силу сделанные здесь изменения. Кнопка New (Новая точка) устанавливает новую контрольную точку с указанными параметрами. При этом соответствующая строка в исходном тексте программы выделяется красным цветом. Назначение остальных кнопок (Cancel и Help) стандартное.
Пункт Call stack
Открывает (информационное) окно Call stack (Стек вызовов), которое можно видеть на рис. А.31.
Рис. А.31. Окно Call stack позволяет выяснить последовательность вызовов подпрограмм
Предположим, имеется программа, в которой объявлены три процедуры: Procl, Ргос2 и РгосЗ. Причем РгосЗ вызывается из основной программы, Ргос2— из РгосЗ и Procl — из Ргос2. Так вот, окно Call stack отображает последовательность этих вызовов. Если в Procl создать контрольную точку, а затем после останова не ней программы открыть окно Call stack, в нем будет представлена цепочка вызовов подпрограмм (снизу вверх): PROGRAM1^ РгосЗ r^>Proc2c^> Proc 1.
Для чего это нужно? Предположим, вы отлаживаете сложную программу, в которой объявлено множество подпрограмм, причем многие подпрограммы вызывают одна другую. При выявлении ошибки в одной из подпрограмм (и останове на ней) может возникнуть необходимость
366
Turbo Pascal: учитесь программировать
проследить цепочку вызовов этой подпрограммы из основной программы. Осуществить это поможет окно Call stack.
Окно Call stack также можно открыть с помощью комбинации клавиш <Ctrl+F3>.
Пункт Register
Открывает (информационное) окно CPU, в котором отображается текущее содержимое Всех регистров центрального процессора (рис. А.32).
Рис. А.32. Здесь можно узнать текущее состояние регистров центрального процессора
Пункт Watches
Открывает (информационное) окно Watches (11аблюдаемые выражения), которое можно видеть на рис. А.ЗЗ.
Рис. А.ЗЗ. Окно Watches позволяет следить за текущими значениями различных переменных и выражений
Предположим, вы отлаживаете программу в пошаговом режиме. При этом значение некоторой переменной или выражения (либо группы переменных и выражений) вызывает у вас сомнение. В этой ситуации полезно иметь возможность постоянно следить за изменениями соответ-твующего значения (значений). Окно Watches как раз и предоставляет такую возможность.
Приложение А. Интегрированная среда
367
Для того чтобы открыть это окно, достаточно выбрать соответствующий пункт меню. Однако окно Watches при этом открывается пустым. Для того чтобы добавить сюда переменную или выражение, нужно щелкнуть дважды в этом окне. В результате откроется диалоговое окно Edit Watch (Редактирование наблюдаемого выражения) позволяющее задать переменную или выражение для наблюдения (рис. А.34). Для этого идентификатор соответствующей переменной (или соответствующее выражение) следует ввести в поле Watch expression (Выражение для наблюдения), а затем щелкнуть на кнопке ОК. В результате заданный идентификатор переменной или выражение появится в окне Watches. Таким же образом следует сюда добавить и все прочие необходимые выражения и переменные.
Рис. А.34. Здесь можно указать все переменные и выражения (по очереди), значения которых требуется наблюдать
После этого, при прогоне программы в пошаговом режиме, в окне Watches будут отображаться текущие значения всех представленных здесь переменных и выражений.
Пункт Output
Открывает (информационное) окно Output (Вывод), предназначенное для вывода результатов работы программы. Его мы неоднократно использовали в предыдущих главах.
Пункт User screen
Открывает экран пользователя (user screen). По сути, это то же окно Output, только развернутое на весь экран.
Экран пользователя также можно открыть (и закрыть) с помощью комбинации клавиш <Alt+F5>.
Пункт Evaluate/modify
Данная команда открывает диалоговое окно Evaluate and Modify (Вычисление и модификация), которое можно видеть на рис. А.35.
368
Turbo Pascal: учитесь программировать
Рис. А.35. Это окно поможет определить значение любого выражения и любой переменной
Это диалоговое окно позволяет в процессе отладки выяснить значение любой переменной или выражения, а также задать для переменной и выражения новое значение. Здесь имеются три поля: Expression (Выражение), Result (Результат) и New value (Новое значение). Если в процессе отладки в поле Expression ввести идентификатор какой-нибудь переменной, объявленной в программе, либо корректное выражение, а затем щелкнуть на кнопке Evaluate, в поле Result отобразится значение, которое в данный момент имеет эта переменная или выражение. При этом в поле New value можно ввести какое-либо свое значение, а затем щелкнуть на кнопке Modify (Изменить). В результате данное значение окажется присвоено переменной или выражению в программе, которое указано в поле Expression. Если в поле Expression ввести идентификатор, не объявленный в программе, в поле Result отобразится сообщение Unknown identifier (Неизвестный идентификатор).
Перед вызовом диалогового окна Evaluate and Modify можно установить курсор в окне редактора Turbo Pascal на какой-либо идентификатор, а затем выбрать пункт Evaluate/modify в меню Debug. В результате соответствующий идентификатор автоматически попадет в поле Expression. После этого, чтобы выяснить его значение, останется только щелкнуть на кнопке Evaluate. Если имеющееся в поле Expression выражение не совсем вас устраивает, вы тут же можете его отредактировать. В выражении, вводимом в поле Expression, могут участвовать переменные и константы, а также некоторые стандартные функции.
Форматом, в котором отображаются значения в поле Result, можно управлять с помощью ключей, задаваемых в поле Expression в конце выражения после запятой. Ключи, о которых идет речь, перечислены в табл. А.З.
Приложение А. Интегрированная среда
369
Таблица А.З. Ключи управления форматом результата
Ключ	Формат
С	Символьный формат (Char). Предназначен для отображения символов управляющих кодов (0..31). По умолчанию такие символы отображаются в виде так называемых Escape-последовательностей
D	Формат целых десятичных чисел. Все целочисленные значения отображаются в виде десятичных чисел
Fn	Вещественный формат (Real). Здесь п— число значащих цифр (2..18)
Н, X или $	Шестнадцатеричный формат. Отображает все целые числа в шестнадцатеричном формате (с предшествующим символом $)
М	Отображает содержимое памяти, начиная с адреса указанного выражения
Р	Указатель (POINTER). Позволяет отобразить значение указателя в формате сегмент:смещение
R	Запись (RECORD). Позволяет отобразить вместе с именами полей и имя записи
S	Строковый формат (STRING). Как правило, применяется совместно с ключом М
Пункт Add watch
Открывает диалоговое окно Add watch (Добавить выражение для наблюдения), которое можно видеть на рис. А. 36-
Рис. А.36. Здесь можно указать переменною или выражение для наблюдения за ними в окне Watches
В этом окне имеется единственное поле ввода Watch expression (Выражение для наблюдения), позволяющее ввести выражение, которое (после щелчка на кнопке ОК) будет добавлено в окно Watches, (см. рис. А.ЗЗ).
Диалоговое окно Add watch также можно вызвать на экран с помощью комбинации клавиш <Ctrl+F7>.
370
Turbo Pascal: учитесь программировать
Пункт Add breakpoint
Открывает диалоговое окно Add breakpoint (Установить контрольную гочку), позволяющее установить контрольную точку в текущей строке рис. А.37).
Рис. А.37. Здесь можно задать параметры для контрольной точки
В этом окне имеются четыре поля ввода: Condition (Условие), Pass count (Номер прохода), File name (Имя файла) и Line number (Номер строки), позволяющие задать для новой контрольной точки значения соответствующих параметров. Здес ь также имеются три командные кнопки (OK, Cancel и Help), назначение которых стандартное.
Меню Tools
Меню Tools (Инструментальные средства) показано на рис. А.38.
Пункты данного меню разделены на две группы. Команды первой группы предназначены для работы с окном Messages (Сообщения). Во второй группе представлены инструментальные средства, осуществляющие вывод в окно Messages (Изначально здесь содержится единственная программа GREP. Помимо этого, сюда можно добавить такие средства, как
Рис. А.38. Здесь можно создать перечень инструментальных средств для запуска прямо из меню Tools
Turbo Assembler, Turbo Debugger. Turbo Profiler.) Как сделать так, чтобы нужные вам инструментальные средства были представлены в меню Tools, мы выясним при изучении команды Tools из меню Options.
Приложение А. Интегрированная среда
371
Пункт Messages
Открывает (информационное) окно Messages (Сообщения), в котором отображаются сообщения инструментальных средств, представленных в нижней части меню. Сообщения, содержащиеся в окне Messages, можно использовать для поиска нужных мест в текстах программ (рис. А.39)
Рис. А.39. Для того чтобы перейти к соответствующему фрагменту программы, достаточно дважды щелкнуть на сообщении в окне Messages
Пункт Go to next
После двойного щелчка на сообщении в окне Messages открывается окно с соответствующей программой и курсор позиционируется в соответствующее место. Теперь, для того чтобы перейти в другую программу или в иное место этой программы, соответствующее следующему сообщению (из окна Messages), можно воспользоваться пунктом Go to next (Перейти к следующему).
Данную команду также можно инициировать с помощью комбинации клавиш <Alt+F8>.
Пункт Go to previous
Для того чтобы перейти в программе (той же или иной) к месту, соответствующему предыдущему сообщению (из окна Messages), можно выбрать пункт меню Go to previous (Перейти к предыдущему).
То же можно сделать с помощью комбинации клавиш <Alt+F7>.
372
Turbo Pascal: учитесь программировать
Пункт Grep
Этот пункт (а также все прочие пункты, если они имеются в нижней половине меню Tools) открывает диалоговое окно Program Arguments Аргументы программы), которое можно видеть на рис. АЛО. (Это окно также можно открыть с помощью комбинации клавиш <Shift+F2>.)
Рис. А 40. Здесь можно указать командную строку
Данное окно содержит единственное поле ввода Enter program argument (Введите аргументы программы), позволяющее задать командную строку для запускаемой программы.
Утилита GREP осуществляет поиск заданного текста сразу в нескольких файлах. Для чего это нужно? Предположим, вам нужна некоторая подпрограмма, имя которой вы помните, но в каком она файле — забыли. Используя утилиту GREP, можно осуществить поиск этой подпрограммы (по ее имени) в определенных (или во всех) файлах в указанном каталоге.
Меню Options
Как выглядит меню Options (Опции), позволяет судить рис. А.41.
compiler.,.
Memory si zes-Linker...
Debugger... pi rectories..
Tools... 
Open. •.. save turbo.tp Save as...
Puc.A.41. Команды, позволяющие задавать различные опции среды
Приложение А. Интегрированная среда
373
Пункт Compiler
Открывает диалоговое окно Compiler Options (Опции компилятора), которое можно видеть на рис. А.42.
VerTays; allowed
Force
data
Runtime errors
Cfft* Singe: checking [X] tack checking Exj /о checking [ ] Overfldu, hegkjng
Debugging
EX] ^bugiInformation
Ex] oca1 symbols
Syntax options
tXJ Stritt lat-sfrThgs
[ ] complete ooleah eval Ex] £ tended syntax £ ] yped & operator
1 J open i'Sararaetefs
Numeri c processi ng t ] 087/80287 * Ex] mutation
Condi tiо al defines
IB
Puc. A. 42. Здесь можно задать различные опции компилятора
В этом диалоговом окне имеется пять групп флажков. Группа Code generation (Генерация кода) объединяет четыре флажка, задающие методы генерации объектного кода.
В целом возможны две модели вызова процедур и функций, которые обусловлены особенностями архитектуры центрального процессора ПК— ближняя модель (NEAR) и дальняя (FAR). При ближней модели адресация ограничивается единственным сегментом, а дальняя модель допускает межсегментные вызовы. Так вот, флажок Force far calls (Задать дальнюю модель), будучи установлен, задает генерацию машинного кода, рассчитанного на дальнюю модель памяти. Если из программы вызываются другие программы (с помощью процедуры Ехес) или организован оверлей, без дальней модели не обойтись. Однако при использовании блажней модели программный код получается более компактным и такая программа работает быстрее.
Флажок Overlays allowed (Оверлей разрешен), когда он установлен, делает возможной генерацию оверлейного кода.
Флажок Word align data (Выравнивание по словам), будучи установлен, задает выравнивание несимвольных переменных и констант в памяти по четным адресам (или по словам). Когда флажок сброшен, имеет место побайтное выравнивание. При выравнивании по словам расходуется больше памяти, однако возрастает скорость работы программы.
374
Turbo Pascal: учитесь программировать
Флажок 286 instructions (Инструкции процессора 286) в установлен-лом состоянии задет создание кода программы с полным набором инструкций процессора 80286. Когда флажок сброшен, программный код генерируется с использованием набора инструкций процессора 8088. Набор инструкций процессора 80286 включает в себя все инструкции процессора 8088. Если существует хоть малейшая вероятность, что создаваемая программа будет когда-либо запускаться на ПК с процессором 8088, флажок 286 instructions устанавливать не следует.
Группа Runtime errors (Ошибки времени выполнения) объединяет четыре флажка.
При установленном флажке Range checking (Проверка диапазона) генерируется дополнительный код, проверяющий, не вышли ли значения используемых переменных :за пределы допустимых значений. Код программы, откомпилированной при включенной проверке диапазонов, получается более объемным, однако такая программа работает надежнее.
Флажок Stack checking (Проверка стека), будучи установлен, обеспечивает проверку переполнения программного стека. Когда проверка стека включена, генерируется дополнительный код, проверяющий перед каждым вызовом процедуры или функции, имеется ли в стеке свободное пространство для локальных переменных. Если свободного пространства не окажется, фиксируется ошибка времени выполнения.
Флажок I/O checking (Проверка ввода-вывода) в установленном состоянии обеспечивает генерацию дополнительного кода, контролирующего безошибочность операций ввода-вывода.
Флажок Overflow checking (Проверка переполнения) в установленном состоянии обеспечивает генерацию дополнительного кода, контролирующего, нет ли переполнения при выполнении операций + — * Abs Sqr Succ Pred40. Однако при этом операции Inc и Dec на переполнение не проверяются.
Группа Syntax options (Синтаксические опции) объединяет пять флажков, управляющих различными аспектами работы компилятора.
При установленном флажке Strict var-strings (Проверка строковых параметров) система сравнивает объявленный тип строкового параметра (в строке VAR подпрограммы) с типом реального параметра, передаваемого подпрограмме. Если они не совпадают, фиксируется ошибка компиляции. Если флажок сброшен, данная проверка не проводится.
При установленном флажке Complete boolean eval (Полное вычисление логических выражений) система вычисляет логические выражения до конца, даже когда результат известен заранее. Если флажок сброшен, вычисление прекращается сразу же, как только становится возможно
40 Первые три — это сложение, вычитание и умножение, a Abs Sqr Succ Pred Inc и Dec представляют собой, стандартные подпрограммы
Приложение А. Интегрированная среда	375
определить результат. Так, если флажок сброшен, в выражении If False and Eoln then... функция Eoln (конец строки) не будет вызвана, поскольку заранее известно, что значение выражения в целом будет иметь значение FALSE.
При установленном флажке Extended syntax (Расширенный синтаксис) открывается возможность вызывать функции не только в выражениях, но и в виде самостоятельного оператора— как процедуры. Это возможно только для функций, определенных пользователем (т.е. нестандартных) .
Флажок Typed @ operator (Контроль типа указателя) определяет тип указателя, получаемого с помощью оператора @. При сброшенном флажке результат применения оператора @ представляет собой нетипи-зированнй указатель, совместимый с указателем любого типа. Если флажок установлен, применение оператора @ к переменной типа Р дает указатель типа ЛР.
Флажок Open parameters (Открытые параметры), будучи включен, открывает возможность использования открытых параметров.
Группа Debugging (Отладка) объединяет два флажка, управляющие процессом отладки.
Если флажок Debug information (Отладочная информация) установлен, компилятор генерирует отладочную информацию. Эта информация представляет собой таблицу, устанавливающую связь между адресами полученного объектного кода и операторами исходного текста программы. Кроме того, только когда данная опция включена, компилятор позволяет устанавливать контрольные точки и использовать пошаговую трассировку.
При включенном флажке Local symbols (Локальные символы) компилятор получает возможность доступа по именам как к глобальным, так и к локальным переменным.
Группа Numeric processing (Обработка чисел) объединяет два флажка, определяющие, как будут обрабатываться числа с плавающей точкой.
Когда флажок 8087/80287 сброшен, при обработке вещественных чисел допускается использование только типа Real и все операции с вещественными числами реализуются программно. Когда флажок установлен, все вещественные вычисления выполняются с использованием математического сопроцессора. Кроме того, при этом открывается возможность использования четырех дополнительных вещественных типов: Single. Double, Extended и Comp.
Если флажок Emulation (Эмуляция) установлен, Turbo Pascal проверяет, имеется ли в ПК сопроцессор. Если сопроцессор имеется, при необходимости компилятор его использует. Если сопроцессора нет, Turbo Pascal его эмулирует. При сброшенном флажке 8087/80287 опция Emulation игнорируется.
376
Turbo Pascal: учитесь программировать
В поле ввода Conditional defines (Условия) вы сможете задать условия, которые будут использованы в директивах условной компиляции.
Пункт Memory sizes
Открывает диалоговое окно Memory Sizes (Объемы памяти), представленное на рис. А.43.
Рис. А.43. Здесь можно задать объемы стека и кучи
Это окно содержит три поля ввода, позволяющие определить объемы памяти для программы.
Поле Stack size (Размер стека) определяет размер программного стека. Значение по умолчанию — 16384 байт. Максимальный размер — 65536 байт.
Поле Low heap limit (Наименьший объем кучи) определяет минимально необходимый размер кучи (в байтах). Значение по умолчанию — О.
Поле High heap limit (Наибольший объем кучи) определяет максимальный объем памяти, который может быть выделен для кучи. Значение по умолчанию— 655360 байт. Значение High Heap Limit не должно быть меньше Low Heap Limit.
Пункт Linker
Открывает диалоговое окно Linker (Компоновщик), представленное на рис. А.44.
Это диалоговое окно содержит две группы переключателей, которые определяют работу компоновщика Turbo Pascal.
Группа Map file (Файл карты распределения памяти) позволяет задать тип выходного файла компоновщика (или отменить его создание).
При выборе переключателя Off (Выключено) файл карты не создается. (Установка по умолчанию.)
Если выбран переключатель Segments (Сегменты), компоновщик создает карту распределения памяти, содержащую перечень сегментов, к которым обращается программа, а также все сообщения об ошибках, имевших место во время компоновки программы.
Приложение А. Интегрированная среда
377
Рис. А.44. Здесь можно задать опции компоновщика
При выборе переключателя Public (Внешние символы) компоновщик создает ту же карту, что и при выборе опции Segments, дополненную перечнем внешних символов в алфавитном порядке.
При выборе переключателя Detailed (Подробно) компоновщик создает полную карту распределения памяти.
Группа Link buffer (Буфер компоновщика) позволяет определить место для буфера компоновщика— память (опция Memory) или диск (опция Disk). Если буфер компоновщика создан в памяти, увеличивается скорость компиляции, однако в этом случае памяти может не хватить.
Пункт Debugger
Открывает диалоговое окно Debugger (Отладчик), представленное на рис. А.45.
Рис. А.45. Здесь можно задать опции отладчика
Это окно содержит две группы опций, управляющие работой отладчика.
Группа Debugging (Отладка) содержит два флажка, позволяющие задать, какой отладчик будет использоваться.
Если предполагается использовать отладчик, встроенный в среду разработчика Turbo Pascal, следует установить флажок Integrated (Встроенный).
378
Turbo Pascal: учитесь программировать
Если же отладку планируется вести вне среды Turbo Pascal с использованием внешнего отладчика Turbo Debugger, в этом случае нужно установить флажок Standalone (Внешний)
Группа Display swapping (Смена экрана) содержит три переключателя, позволяющие задать режим переключения в режиме отладки между окном редактора и экраном пользователя.
Если выбран переключатель None (Никогда), отладчик че будет переключать экраны вовсе. В этом случае вывод осуществляется в текущее окно редактора. Данную установку полезно использовать для кода, в котором вывод на экран не предусмотрен.
Если выбран переключатель Smart (“Интеллектуальное” переключение), отладчик попытается самостоятельно обнаружить в коде места вывода, и в соответствующие моменты переключится на экран пользователя.
Если выбран переключатель Always (Всегда), отладчик осуществит смену экранов перед выполнением каждого оператора программы.
Пункт Directories
Открывает диалоговое окно Directories (Каталоги), которое показано на рис. А.46.
Рис. А.46. Здесь можно указать каталоги, необходимые для среды Turbo Pascal
В этом окне содержатся четыре поля ввода, позволяющие указать Turbo Pascal, где содержатся (или должны содержаться) необходимые файлы.
В поле ЕХЕ & TPU directory (Каталог для EXE- и TPU-файлов) задается каталог, в который будут помещаться откомпилированные файлы программ (ЕХЕ-файлы) и модулей (TPU-файлы). Если каталог не задан, ЕХЕ- и TPU-файлы будут сохранятся в том же каталоге, в котором содержатся исходные тексты программ.
Приложение А. Интегрированная среда
379
Поле Include directories (Каталог для включаемых файлов) позволяет указать каталог (каталоги), в котором содержатся включаемые в программу файлы (которые задаются директивой компилятору (SI <имя файла>)). Система ищет включаемые файлы в указанном здесь каталоге, только если не найдет их в текущем каталоге.
В поле Unit directories (Каталоги для модулей) следует указать каталог (каталоги), где системе надлежит искать файлы модулей (TPU-файлы). Если заданы несколько каталогов, их можно разделить точкой с запятой. Система ищет файлы модулей в указанном каталоге, только если не найдет их в текущем каталоге.
Поле Object directories (Каталоги для OBJ-файлов) позволяет указать каталоги, в которых содержатся используемые в программе OBJ-файлы.
Пункт Tools
Открывает диалоговое окно Tools (Инструментальные средства), представленное на рис. А.47.
Рис. А.47. Здесь создается список программ, которые можно запускать из меню Tools
Основной управляющий элемент этого окна — список с прокруткой Program titles (Заголовки программ). Здесь формируется перечень программ, имена которых содержатся в нижней части меню Tools (см. раздел “Меню Tools”)- Напомним, в этом меню в виде его пунктов представлены программы, которые выводят сообщения в окно Messages. Пункт Tools меню Options как раз и предназначен для обслуживания этого списка.
Помимо списка с прокруткой, в диалоговом окне Tools находятся также командные кнопки New (Новая программа). Edit (Правка) и Delete (Удаление). (Остальные кнопки имеют стандартное назначение, которое
380
Turbo Pascal: учитесь программировать
мы выяснили раньше.) Кнопка Delete позволяет удалять имена программ из списка Program titles (а также из меню Tools). Что касается кнопок New и Edit, то щелчок на любой из них открывает диалоговое окно Modify/New Tools (Корректирование/Добавление новых средств) (рис. А.48).
Рис. А.48. Здесь можно указать новую программу, которая будет добавлена в меню Tools
В этом окне имеются три поля ввода. Поле Title (Заголовок) позволяет ввести заголовок программы — тот, который будет виден в меню Tools. В поле Path (Путь) задается путь к исполняемому файлу соответствующей программы. Наконец, поле Command line (Командная строка) предоставляет возможность задать командную строку для запуска данной программы.
Кроме того, в этом окне имеется группа переключателей Hot keys (Горячие клавиши), которая позволяет назначить горячую клавишу для запуска данной программы. (Соответствующая комбинация клавиш будет представлена в меню Tools рядом с именем данной программы.)
Пункт Environment
Команда Environment (Среда) открывает подменю, показанное на рис. А.49.
В этом подменю содержатся пять пунктов, назначение которых мы рассмотрим ниже.
Рис. Л. 49. Команды, позволяющие задать опции среды
Приложение А. Интегрированная среда
381
Пункт Preferences
Открывает диалоговое окно Preferences (Установки), представленное на рис. А.50.
Рис. А.50. Здесь можно сделать установки среды Turbo Pascal
Данное окно содержит пять групп опций.
Группа Screen sizes (Размер экрана) состоит из двух переключателей. Когда выбран переключатель 25 lines (25 строк), рабочая область Turbo Pascal содержит 25 строк (включая строку меню, заголовок окна, горизонтальную линию прокрутки и строку подсказки). Если же выбрать переключатель 43/50 lines (43/50 строк), на экране будет 43 либо 50 строк (в зависимости от того, какой у вас видеоадаптер — EGA или VGA).
Группа Source tracking (Выбор окна) состоит из двух переключателей, определяющих, какое окно будет использоваться, если в процессе отладки обнаружится еще незагруженный файл. Если выбран переключатель New window (Новое окно), вновь открываемый файл окажется загружен в новое окно редактора. Если выбран переключатель Current window (Текущее окно), открываемый файл будет загружен в активное окно редактора, заменив собой предыдущее содержимое этого окна.
Группа Auto save (Автоматическое сохранение) состоит из трех флажков.
Если установлен флажок Editor files (Файлы в окнах редактора), при каждом прогоне программы будут автоматически сохранятся все файлы, открытые в окнах редактора (если после последнего сохранения в них были внесены изменения).
Если установлен флажок Environment (Среда), при каждом выходе из Turbo Pascal автоматически сохраняются (в файле TURBO.TP) все изменения в установках, сделанные в текущем сеансе работы.
Если установлен флажок Desktop (Рабочая область), будут автоматически сохраняться (в файле TURBO.DSK) настройки рабочей области
382
Turbo Pascal: учитесь программировать
Turbo Pascal (размеры открытых окон, их положение на экране и т.п.). Данная опция позволяет при вызове среды Turbo Pascal получить ту же рабочую область, какая существовала в момент выхода из среды.
Группа Options (Опции) объединяет три флажка, управляющие взаимодействием окон ObjectBrowser и окон редактора.
Если флажок Auto track source (Автоматическое прослеживание источника) установлен, в окне редактора автоматически будет выделяться отрока исходного текста, в которой находится символ, отмеченный в окне Messages (или в ObjectBrowser). Если флажок уброшен, строка исходного текста выделяться не будет.
Если установлен флажок Close on go to source (При переходе к источнику, закрыть окно), при выборе команды Go to source (Перейти к источнику) закроется окно Messages (или ObjectBrowser). Если флажок сброшен, указанное окно останется открытым.
Если установлен флажок Change dir on open (Изменение каталога при открытии файла), при выборе команды Open из меню File текущим станет каталог, где находится открываемый файл.
Группа Desktop file (Файл рабочей области) объединяет два переключателя, которые определяют местоположение файла TURBO.DSK.
Если выбран переключатель Current directory (Текущий каталог), файл TURBO.DSK создается в текущем каталоге.
Если выбран переключатель Config file directory (Каталог конфигурационного файла), TURBO.DSK создается в том же каталоге, где содержится конфигурационный файл TURBO.TP.
Пункт Editor
Открывает диалоговое окно Editor Options (Опции редактора) (рис. А. 51).
WИчМ'	[X] ' OUP Undo-
EX] ps‘ert	ГХГ	, bl ocks
EX1, uto indent mode л{. 1 О е.щмГ1%е. blddks
L 3* se tab tharaeters IXl -'yhtax bi.bhli ght £.] ptimaJ.Ti.ll .	, • £ j©<_k insert.cursor
£XJ aekspace>unindents £X1 Find re, t jst ru.rkor £ J ursxr through tabs
ighlight extensions
 PAS;  INC
Рис. A.51. Здесь можно задать опции редактора
Приложение А. Интегрированная среда
383
В этом окне имеется большая группа флажков и два поля ввода. Группа Editor options (Опции редактора) объединяет 13 флажков.
Если флажок Create backup files (Создавать резервные файлы) установлен, при каждом сохранении файла с исходным кодом система автоматически будет создавать резервный файл (с расширением .ВАК). Таким образом, под рукой всегда будет файл с последней версией исходи го кода (PAS-файл) и файл с предпоследней версией (ВАК-файл).
Если флажок Insert mode (Режим вставки) установлен, при вводе те ста в окне редактора существующий текст будет сдвигаться вправо. Если этот флажок сброшен, вновь вводимый текст заменяет старый (режим замены). Переключать режимы можно также клавишей <Ins>.
Если флажок Auto indent mode (Автоматический отступ) установлен, при нажатии клавиши <Enter> курсор переместится в следующей строке на ту же позицию, с которой начинается предыдущая строка. Если флажок сброшен, курсор переместится к началу строки.
Если флажок Use tab characters (Использовать символы табуляции) установлен, при нажатии клавиши <ТаЬ> в окне редактора вставляются коды табуляции (код 9 из таблицы ASCII — см. приложение Е). Если флажок сброшен, вместо кодов табуляции вставляются пробелы.
Если флажок Optimal fill (Оптимальное заполнение) установлен. Turbo Pascal при использовании автоматических отступов (опция Auto indent mode) будет вставлять минимальное количество пробелов или знаков табуляции. В результате строки в тексте программы будут получаться короче.
Если флажок Backspace unindents (Удаление отступов с помощью клавиши <Backspace>) установлен и если курсор расположен в пустой строке или на первом символе в строке, отличном от пробела, то нажатие клавиши <Backspace> приведет к перемещению курсора влево на позицию. соответствующую отступу предыдущей строки. Если флажок сброшен, нажатия клавиши <Backspace>, когда справа в строке нет символов, будут приводить к удалению пробелов по одному.
Если флажок Cursor through tabs (Перемещение курсора по символам табуляции) установлен, при нажатиях клавиш-стрелок вправо или влево курсор будет перемещаться по символам табуляции так, словно это простые пробелы — на одну позицию за раз. А если флажок сброшен, в этом случае курсор будет перемещаться скачками— каждый раз на столько позиций, сколько задано в поле Tab size (Размер табуляции) внизу диалогового окна.
Если флажок Group Undo (Отмена группы действий) сброшен, действия будут отменяться (с помощью команды Undo из меню Edit) по одному. Например, если вы введете несколько символов, а затем несколько раз инициируете команду Undo, символы будут удаляться с экрана по одному за раз. Если флажок установлен, при использовании команды Undo, за раз будут отменяться группы однотипных действий. Например, если
384
Turbo Pascal: учитесь программировать
вы введете несколько строк символов, нажимая клавишу <Enter> при переходе на новую строку, а затем несколько раз инициируете команду Undo, каждый раз с экрана будет удаляться либо строка символов, либо код конца строки.
Если флажок Persistent blocks (Устойчивое выделение) установлен и вы выделили фрагмент текста в окне редактора, а затем переместили курсор за пределы выделенного текста, выделение при этом сохранится. Если флажок сброшен, при перемещении курсора за пределы выделенного текста выделение снимается.	,
Если флажок Overwrite blocks (Замена выделенного текста) установлен и вы выделили фрагмент текста, а затем нажали какую-либо клавишу, введенный символ заменит выделенный текст. Если флажок сброшен, введенный символ окажется вставлен после выделенного фрагмента.
Если флажок Syntax highlight (Синтаксическое выделение) установлен, различные элементы в тексте программы (такие, как зарезервированные слова) будут выделены каждый своим цветом. (Указать, содержимое каких именно файлов должно отображаться с синтаксическим выделением, можно в поле Highlight extensions — см. ниже.)
Флажок Block insert cursor (Большой курсор в режиме вставки) определяет вид курсора в режиме вставки и в режиме замены (которые переключаются с помощью флажка Insert mode или клавиши <Ins>). Если флажок установлен, в режиме вставки курсор будет выглядеть как сплошной светящийся прямоугольник, служащий фоном одного символа, а в режиме замены— как символ подчеркивания. Если флажок сброшен, вид курсора, в зависимости от режима ввода, меняется на противоположный.
Если флажок Find text at cursor (Искать текст, на котором курсор) установлен, в поле Text to find (Текст для поиска) в диалоговых окнах, которые вызываются командами Find и Replace из меню Search, отобразится слово из окна редактора, на котором расположен курсор. Если флажок сброшен, в этом поле отобразится строка, задававшаяся для предыдущего поиска.
Поле ввода Tab size (Размер табуляции) позволяет задать, на сколько позиций будет перемещаться курсор при нажатии клавиши <ТаЬ>. Если значение здесь изменить, все символы табуляции, имеющиеся в текущем файле, будут преобразованы согласно новому значению.
Поле ввода Highlight extensions (Расширения файлов для синтаксического выделения) позволяет указать расширения файлов, содержимое которых должно отображаться в окне редактора Turbo Pascal с синтаксическим выделением. Если здесь не указать ни одного расширения, синтаксическое выделение окажется отключено. Для того Чтобы отключить синтаксическое выделение, можно также сбросить флажок Syntax highlight (см. выше).
Приложение А. Интегрированная среда	385
13—2016
Пункт Mouse
Открывает диалоговое окно Mouse options (Опции мыши), представленное на рис. А.52.
Рис. А.52. Здесь можно задать опции функционирования мыши
В этом диалоговом окне содержатся одна группа переключателей, один регулятор и один флажок.
Группа Ctrl+Right mouse button (<СЬг1>+щелчок правой кнопкой мыши) объединяет пять переключателей. Эта группа определяет действие, которое будет иметь место, если вы нажмете клавишу <Ctrl> и, не отпуская ее, щелкните правой кнопкой мыши.
Если выбран переключатель Nothing (Ничего), в случае нажатия клавиши <Ctrl> и щелчка правой кнопкой мыши не произойдет ничего.
Если выбран переключатель Topic search (Поиск темы), нажатие клавиши <Ctrl> и одновременный щелчок правой кнопкой мыши произведет действие, эквивалентное выбору пункта Topic Search из меню Help.
Если выбран переключатель Go to cursor (Перейти к курсору), нажатие <Ctrl> и щелчок правой кнопкой мыши произведет действие, эквивалентное выбору пункта Go to cursor из меню Run.
Если выбран переключатель Breakpoint (Контрольная точка), нажатие <Ctrl> и щелчок правой кнопкой вызовет действие, эквивалентное выбору Toggle Breakpoint из локального меню (см. раздел “Локальное меню” дальше).
Если выбран переключатель Evaluate (Вычисление), нажатие <Ctrl> и щелчок правой кнопкой вызовет действие, эквивалентное выбору Evalu-ate/modify из меню Debug.
Если выбран переключатель Add watch (Добавить выражение для наблюдения), нажатие <Ctrl> и одновременный щелчок правой кнопкой произведет действие, эквивалентное выбору Add Watch из меню Debug.
Регулятор Mouse double click (Двойной щелчок) позволяет задать скорость двойного щелчка мышью. Скорость регулируется бегунком. Если бегунок переместить в строну Fast (Быстро, т.е. влево), для нужного эффекта двойной щелчок потребуется делать быстрее (с меньшим промежутком времени между щелчками). Если бегунок переместить в строну
386
Turbo Pascal: учитесь программировать
Slow (Медленно, т.е. вправо), двойной щелчок можно будет делать медленнее. Известно, для того чтобы выделить строку в окне редактора Turbo Pascal, следует дважды на ней щелкнуть. Так вот, при перемещенном бегунке регулятора в крайнее левое положение (Fast) автору не удалось достаточно быстро дважды щелкнуть, чтобы выделить строку.
Флажок Reverse mouse buttons (Поменять функции кнопок мыши) позволяет кнопки мыши как бы переставить местами. Если этот флажок установить, правая кнопка станет функционировать так, как до этого функционировала левая, а левая будет функционировать как правая. (Замечание: функции кнопок поменяются не в момент установки флажка, а только после щелчка на кнопке ОК в диалоговом окне.) Данная опция предназначена для левшей. Такие люди обычно располагают мышь слева, но при этом им, как и всем остальным пользователям, хочется, чтобы основная кнопка мыши (та, которой мы чаще всего пользуемся) оказалась под указательным пальцем.
Пункт Startup
Открывает диалоговое окно Startup Options (Опции, вступающие в действие после перезагрузки среды), представленное на рис. А.53. Если все опции, о которых шла речь выше, вступают в силу после щелчка на кнопке ОК в диалоговом окне, то для опций, рассматриваемых в данном разделе, чтобы ввести их в действие, еще необходимо перезагрузить среду.
Т |	ta> screen save
[,- 3	save
‘CCA s,.w cbecKing
L J	set
a] toad «0Ж	< -
2 Use 'ё landed -йётёгу air-
fl |> di re, t<- ry ШИ
 > I	ul
irtdow iteao size di tor heap size ver1ay neap si ze
Рис. А.53. Отсюда задаются разного рода опции, которые вступают в действие только после перезагрузки среды Turbo Pascal
Это диалоговое окно содержит одну группу флажков и четыре поля ввода.
Группа (безымянная, поскольку объединяет разнородные опции) включает восемь флажков.
Если установить флажок Dual monitor support (поддержка двух мониторов) и щелкнуть на кнопке ОК, при условии, что ваш ПК оснащен необходимым оборудованием, новый сеанс работы с интегрированной средой Turbo Pascal откроется с поддержкой двух мониторов. Необходи
Приложение А. Интегрированная среда	387
13’
мое оборудование — это два видеоадаптера и два монитора, имеющиеся в системе.
Если установить флажок Graphics screen save (Сохранение графического экрана), а затем нажать кнопку ОК, в новом сеансе работы с интегрированной средой Turbo Pascal при запуске программ, в которых инициируется графический режим, графический экран будет сохраняться в оперативной памяти ПК.
Если установить флажок EGA/VGA palette save (Сохранение палитры EGA/VGA), а затем щелкнуть на кнопке ОК, в новом сеансе работы с интегрированной средой будет осуществляться сохранение цветовой палитры экрана, поэтому изменения этой палитры в отлаживаемой программе не будут влиять на вид рабочей области и открытых в ней окон.
Если ваш ПК оснащен видеоадаптером EGA или VGA, на флажок CGA snow checking (Устранение “снега” при использовании CGA) можно не обращать внимания, однако, если у вас адаптер CGA, данная опция позволит исключить эффект, известный как “снег", который имеет место при смене изображений на экране.
Опция LCD color set (Набор цветов для LCD41) предназначена для ПК, оснащенных экраном на жидких кристаллах.
Если флажок Load TURBO.TPL (Загружать TURBO.TPL) установлен, система будет загружать в оперативную память системную библиотеку TURBO.TPL. Однако, если оперативной памяти не хватает, от такой загрузки можно отказаться, сбросив данный флажок. В этом случае вам придется извлечь из TURBO.TPL (с помощью утилиты TPUMOVER) файл модуля SYSTEM.TPU и поместить его в каталог, который указан в поле Unit directories (команда Directories из меню Options). (Подробнее об утилите TPUMOVER вы сможете узнать из главы 8.)
Если установить флажок Use expanded memory (Использовать отображаемую память), среда Turbo Pascal сможет использовать отображаемую память EMS.
Если установить флажок Return to last dir (Вернуться в последний каталог), каждый используемый каталог будет сохраняться в установках интегрированной среды в качестве текущего. В результате при загрузке среды Turbo Pascal текущим окажется каталог, который использовался последним в предыдущем сеансе работы.
Поле ввода Window heap size (Объем памяти для окон) позволяет задать объем памяти, выделяемой для хранения окон, открытых в среде Turbo Pascal. Если вы не работаете со множеством окон сразу, значение в этом поле имеет смысл уменьшить.
Поле ввода Editor heap size (Объем памяти для редактора) позволяет задать объем памяти, выделяемой для хранения содержимого окон редактора Turbo Pascal.
41 LCD — liquid crystal display (дисплей на жидких кристаллах).
388	Turbo Pascal: учитесь программировать
В поле ввода Overlay heap size (Объем памяти для оверлеев) задается объем памяти, которую можно использовать для хранения оверлейных модулей.
Поле ввода Swap file directory (Каталог для свопинга) позволяет указать место для динамического обмена данными (свопинга — swapping), в котором может нуждаться среда Turbo Pascal. Очень удобно для динамического обмена данными использовать виртуальный диск (т.е. диск, эмулируемый в оперативной памяти ПК). По умолчанию для свопинга используется текущий каталог.
Пункт Colors
Открывает диалоговое окно Colors (Цвета), показанное на рис. А.54.
Рис. А.54. Отсюда можно раскрасить экран всеми цветами радуги
Это диалоговое окно позволяет определить, какого цвета должен быть тот или иной элемент на экране. В этом окне содержатся два списка с прокруткой и две палитры, а также область образца.
В списке Group (Группа) отображается перечень групп элементов, которые можно встретить на экране. Здесь представлены следующие группы:
Call stack	— окно Call stack;
Compiler	— окно компилятора;
Desktop	— рабочая область;
Dialogs	— диалоговые окна;
Editor	— окно редактора;
Help	— окно системы справки;
Menus	— меню;
Messages	— окно Messages;
Output	— окно Output;
Register	— окно Register (или окно CPU);
Приложение А. Интегрированная среда
389
Syntax	— синтаксические элементы;
Watches	— окно Watches.
При выборе той или иной группы в списке Item (Элемент) отображается перечень элементов, принадлежащих этой группе. Например, на рис. Л.54 выбрана группа Call stack, в которой, как свидетельствует список Item, содержатся семь элементов. Теперь, для того чтобы назначить цвета тому или иному элементу, достаточно выбрать этот элемент в списке Item, а затем подобрать для него подходящие цвета — в палитрах Foreground (Передний план) и Background (Фон). Результат можно наблюдать в области образца в правом нижнем углу экрана. По завершении, чтобы новые цвета вступили в действие, необходимо щелкнуть на кнопке ОК.
Пункт Open
Открывает диалоговое окно Open Options (Загрузить опции), представленное па рис. А.55.
Рис. А. 55. Здесь можно выбрать файл с настройками
Это диалоговое окно позволяет указать конфигурационный файл, в котором содержатся настройки среды. В поле Options file name (Файл с настройками) можно ввести имя нужного файла, либо соответствующий файл можно выбрать в списке с прокруткой Files (Файлы).
Пункт Save
Сохраняет все настройки среды, сделанные вами в диалоговых окнах, открываемых с помощью пунктов меню Options. В меню рядом с этим пунктом указано имя файла, в котором будут сохранены настрой ки. Обычно это тот файл, в котором настройки сохраняются по умолча
390
Turbo Pascal: учитесь программировать
нию (TURBO.TP), либо иной файл, который вы выбрали при инициировании команды Save As из меню Options (см. следующий раздел).
Пункт Save as
Открывает диалоговое окно Save Options As (Сохранить опции как) (рис. А.56).
В этом окне, которое ничем не отличается от окна Open Options, можно указать для сохранения настроек среды иной файл (и каталог), не тот в котором настройки сохраняются по умолчанию (TURBO.TP).
Рис. А.5в. Здесь можно указать файл для сохранения настроек
Меню Window
Меню Window (Окно) можно видеть на рис. А.57.
Данное меню содержит десять пунктов, разделенных на две группы, которые предназначены для работы с окнами, открытыми в рабочей области среды Turbo Pascal.
Рис. А.57. Команды для работы с информационными окнами
Пункт Tile
Команда Tile (Мозаикой) позволяет окна, открытые в рабочей области, расположить мозаикой (т.е. рядом одно с другим см. рис. А.58).
Приложение А. Интегрированная среда
391
Рис. А. 58. При таком способе размещения каждое окно видно полностью
При этом каждое окно видно целиком, но все окна очень уменьшаются в размерах. Для того чтобы одно из этих окон развернуть на весь экран, следует сделать его активным, а затем щелкнуть на кнопке со стрелкой в его правом верхнем углу. Чтобы вернуть окно к прежним размерам, нужно еще раз щелкнуть на этой кнопке.
Пункт Cascade
Команда Cascade (Каскадом) позволяет окна, открытые в рабочей области (за исключением диалоговых окон), расположить каскадом (рис. А. 59).
Рис. А.59. При таком способе размещения все окна имеют (почти) максимальные размеры
392
Turbo Pascal: учитесь программировать
При этом окна располагаются одно поверх другого, так что видны только их заголовки (за исключением окна, открытого последним, которое видно полностью). Для того чтобы какое-либо окно (из открытых) вывести на передний план, можно щелкнуть на его заголовке либо воспользоваться пунктом List (Список) этого же меню (см. дальше).
Пункт Close all
Команда Close all (Закрыть все) позволяет одним махом закрыть все информационные окна (но не диалоговые), открытые в рабочей области среды Turbo Pascal.
Пункт Refresh display
Вспомним, что в разделе “Пункт Debugger” (этот пункт содержится в меню Options) речь шла о том, что если выбран переключатель None (Никогда) группы Display swapping (Смена экрана), отладчик не переключает экраны вовсе. В этом случае вывод осуществляется в текущее окно редактора (поверх текста программы) Так вот, восстановить такой “испорченный” текст программы (т.е. очистить его от следов вывода) поможет пункт Refresh display.
Пункт Size/Move
Команда Size/Move (Изменение размеров/Перемещение) позволяет изменять размеры и перемещать окна на экране. После того как данная команда инициирована, для перемещения окна можно воспользоваться клавишами-стрелками. Причем можно достичь более быстрого перемещения по горизонтали, если нажимать клавиши-стрелки при нажатой клавише <Ctrl>.
Что касается изменения размеров окон, то для этого при нажатиях клавиш-стрелок следует держать нажатой клавишу <Shift>. После того как окно приняло нужные размеры и положение на экране, чтобы зафиксировать изменения, следует нажать клавишу <Enter>.
Для того чтобы инициировать команду Size/Move (и при этом обойтись и без меню), можно воспользоваться комбинацией клавиш <Ctrl+F5>. Переместить окно на экране можно также с помощью мыши, “ухватив” его за заголовок.
Пункт Zoom
Команда Zoom (Масштабирование) позволяет развернуть окно на весь экран, либо свернуть его до первоначальных размеров. Этого мож
Приложение А. Интегрированная среда
393
но достичь и с помощью клавиши <F5>, либо щелкая на кнопке со стрелкой в правом верхнем углу окна.
Пункт Next
Если открыть на экране несколько окон, команда Next (Следующее) позволит сделать активным следующее окно (имеется в виду следующее от окна, которое активно в настоящий момент). Этого можно достичь и с помощью клавиши <F6>-
Пункт Previous
Команда Previous (Предыдущее) сделает активным предыдущее окно.
Это можно сделать и с помощью комбинации клавиш <Shift+F6>.
Пункт Close
Позволяет закрыть активное окно. Это можно также сделать с помощью комбинации клавиш <Alt+F3> либо щелчком на кнопке в левом верхнем углу окна.
Пункт List
Данная команда открывает диалоговое окно Window List (Список окон), которое можно видеть на рис. А.60. Оно предназначено для управления (информационными) окнами, открытыми в среде Turbo Pascal.
В этом окне в списке с прокруткой содержится перечень открытых в настоящее время окон. Командная кнопка Delete (Удалить) позволяет удалить из перечня выделенное окно. При этом удаляемое окно закрывается.
Рис. А.60. Список открытых окон
394
Turbo Pascal: учитесь программировать
Меню Help
Мы уже имели дело с системой справки при изучении различных команд различных меню. Кроме того, в каждом диалоговом окне имеется кнопка Help, щелкнув на коей (или нажав клавишу <F1>). можно получить информацию по опции, на которой в этом диалоговом окне в данной время расположен курсор. Можно также в любом меню поместить курсор на каком-либо пункте, а затем нажать клавишу <fi'l>. В резуль-
тате отобразится (информационное) окно справочной системы с информацией по этому пункту. Теперь мы приступаем к изучению меню Help, предоставляющего непосредственный доступ к справочной системе. К сожалению, вся информация здесь предоставляется на английском языке.
Меню Help (Справка), последнее в строке меню, можно видеть на рис. А.61.
Это меню содержит команды, позволяющие получить доступ к информации справочной системы Turbo Pascal 7.0.
Рис. А.61. Команды для работы со справочной, системой
Пункт Contents
Открывает окно справочной системы, озаглавленное TURBO PASCAL HELP CONTENTS (Содержимое справочной системы Turbo Pascal), представленное на рис. А.62.
Рис. А. 62. Перечень возможностей справочной системы
Приложение А. Интегрированная среда
395
В этом окне содержится перечень тем. Если щелкнуть на какой-либо теме, в окне отобразится имеющаяся информация по данной теме.
Пункт Index
Открывает окно справочной системы, озаглавленное Turbo Help Index (Указатель справочной системы), представленное на рис. А.63.
Рис. А.63. Предметный указатель справочной системы
В этом окне содержится перечень терминов и условных обозначений, используемых в справочной системе. Если щелкнуть здесь на каком-либо пункте, в окне отобразится информация по выбранному пункту.
Открыть окно Turbo Help Index можно также с помощью комбинации клавиш <Shift+Fl>.
Пункт Topic search
Если в окне редактора поместить курсор на какой-либо оператор или зарезервированное слово, а затем выбрать пункт Topic search (Поиск информации по заданной теме), на экране отобразится окно справочной системы с информацией по этому оператору или зарезервированному слову.
На рис. А.64. представлено окно редактора Turbo Pascal с текстом программы, в котором курсор расположен на зарезервированном слове BEGIN. Затем (с помощью команды Topic search) здесь было открыто окно справочной системы с информацией по указанному зарезервированному слову.
396
Turbo Pascal: учитесь программировать
begi n
ilt fcdiV seatxfc. шийДл^иаЬиа l-.tsals "st tons ^tirrifiw_j4e1p --------------------------------------gre₽2msg.pas —--------------------— ------------1------
Wri teHeader while not E begi n ReadLnfLi
begi n if Copy Wri te else begi n
Vai (C if E end;
end;
end;
1. 132)));
Wri teEnd; end.
Fl Help on help Al-t^Fl PpevidUs topic >lv';t+Fl Help index E.*e Close help
Puc. A.64. Получить информацию no тому или иному .элементу программы проще простого
Пункт Previous topic
Предположим, вам пришлось в окне справочной системы просматривать информацию по нескольким темам подряд, и на каком-то этапе возникла необходимость вернуться к одной из первых тем. Проделать это можно с помощью команды Previous topic (Предыдущая тема).
Это же можно осуществить, воспользовавшись комбинацией клавиш <Alt+Fl>.
Пункт Using help
Если при обращении к справочной системе у вас возникли проблемы, воспользуйтесь командой Using help (Использование справки). В открывшемся окне содержится инструкция по применению справочной системе (т.е. "справка по справке”).
Пункт Files
Открывает диалоговое окно Install Help Files (Инсталляция файлов системы справки), позволяющее устанавливать (или инсталлировать) либо удалять уже установленные файлы справочной системы (рис. А.65).
Для установки новых файлов служит командная кнопка Add (Добавить). Для удаления установленных файлов предназначена кнопке Delete (Удалить).
Приложение А. Интегрированная среда
397
Рис. А.65. Установленные файлы справочной системы
Пункт Compiler directives
Данная команда отображает окно справочной системы, озаглавленное Compiler Directives List (Список директив компилятора), содержащее информацию (по-английски) по всем директивам компилятора.
Пункт Reserved words
Отображает окно справочной системы, озаглавленное Reserved Words (Зарезервированные слова), содержащее информацию (по-английски) по всем зарезервированным словам, используемым в Turbo Pascal 7.0.
Пункт Standard units
Отображает окно, озаглавленное Turbo Pascal's Standard Units (Стандартные модули Turbo Pascal), содержащее информацию (по-английски) по всем модулям, входящим в комплект поставки Turbo Pascal 7.0.
Пункт Turbo Pascal Language
Отображает окно, озаглавленное Language Elements (Элементы языка), содержащее информацию (по-английски) по всем элементам языка Turbo Pascal 7.0.
Пункт Error messages
Отображает окно, озаглавленное Error messages (Сообщения об ошибках), содержащее информацию (по-английски) по всем сообщениям об ошибках, которые могут появиться на экране при использовании Turbo Pascal 7.0.
398
Turbo Pascal: учитесь программировать
Пункт About
Отображает окно с информацией о пакете Turbo Pascal (номер версии и данные об авторских правах).
Локальное меню
Если в рабочей среде Turbo Pascal щелкнуть правой кнопкой мыши, отобразится так называемое локальное меню — средство быстрого доступа к наиболее используемым командам. Локальное меню является контекстно-зависимым — его содержимое зависит от того, какие окна были открыты в среде Turbo Pascal в момент вызова. На рис. А.66 представлены три варианта локального меню: для окна редактора (А), окна Watches (В) и окна справочной системы (С).
А
Рис. А.66. Вид локального меню зависит от ситуации, в которой оно было вызвано
Если вспомнить материал по соответствующим окнам, который имеется в предыдущих главах этой книги, нетрудно заметить, что команды, содержащиеся в этих локальных меню, наиболее полезны при работе с соответствующими окнами.
Команды редактора
В данном разделе представлены комбинации клавиш, позволяющие быстро выполнять различные команды редактора. Их условно можно разделить на четыре группы:
Приложение А. Интегрированная среда
399
	команды перемещения курсора;
	команды вставки и удаления;
	команды для работы с фрагментами текста;
	прочие команды.
Если речь идет о единственной клавише, то она здесь представлена так: <F3>. Это значит, что для выполнения соответствующей команды следует просто нажать указанную клавишу.
Если предлагается воспользоваться комбинацией клавиш, например <Alt+F>, придется сначала нажать клавишу <Alt>, затем, не отпуская ее, — клавишу <F>, затем отпустить обе клавиши.
Иногда клавиши, участвующие в комбинации, представлены через запятую, например, <Ctrl+Q, S>. Если вам встретится подобная команда, знайте, что следует нажать клавиши <Ctrl> и <Q>, затем отпустить обе клавиши, наконец, нажать <S>. Иными словами, если клавиши в комбинации объединяет знак сложения, это значит, что их следует нажимать вместе. Если клавиши в комбинации представлены через запятую, их следует нажимать по очереди.
Команды перемещения
курсора
При редактировании текста важно уметь быстро переместить курсор в нужное место на экране. Осуществить это вам помогут комбинации клавиш, представленные ниже.
Перемещение (направление и расстояние)	Комбинация клавиш
На позицию влево	<Ctrl+S> или «— >
На позицию вправо	<Ctrl+D> или <—»
На строку вверх	<Ctrl+E> или <Т>
На строку вниз	<Ctrl+X> или <>L>
На слово влево	<Ctrl+A> или < Ctrl+<—>
На слово вправо	<Ctrl+F> или <Ctrl+—»
Прокрутка вверх на одну строку	<Ctrl+W>
Прокрутка вниз на одну строку	<Ctrl+Z>
На страницу вверх	<Ctrl+R> или <PgUp>
На страницу вниз	<Ctrl+C> или <PgDn>
К началу строки	<Ctrl+Q, S> или <Home>
400
Turbo Pascal: учитесь программировать
В конец строки
Вверх окна
Вниз окна
К началу файла
В конец файла
К последней позиции курсора
К месту последней ошибки
<Ctrl+Q, D> или <End>
<Ctrl+Q, Е> или <Ctrl+Home>
CCtrl+X, S> или <Ctrl+End>
<Ctrl+Q, R> или <Ctrl+PgUp>
<Ctrl+Q, О или <Ctrl+PgDn>
<Ctrl+Q, P>
CCtrl+Q, W> „.
Команды вставки и удаления
Здесь перечислены комбинации клавиш, которые помогут вам удалять из текста отдельные символы и группы символов. Кроме того, благодаря этим командам, вы сможете переключать режимы ввода символов (вставки-замены) и вставлять в текст пустые строки.
Действие	Комбинация клавиш
Переключение режимов вставки	и замены	<Ctrl+V> или <lns>
Вставка пустой строки	<Ctrl+N>
Удаление строки	<Ctrl+Y>
Удаление всех символов от курсора и до конца строки <Ctrl+Q, Y>
Удаление символа слева	<Ctrl+H> или	<Backspace>
Удаление символа справа	<Ctrl+G> или	<Del>
Удаление слова справа	<Ctrl+T>
Команды для работы с выделенными фрагментами
Часто необходимо выполнить некоторое действие не только над отдельным символом, но и над группой символов— фрагментом текста. Для этого, прежде всего, соответствующий фрагмент необходимо выделить. Выделять, копировать, перемещать, удалять, а также осуществлять другие операции над фрагментами текста вы сможете с помощью следующих комбинаций клавиш.
Действие	Комбинация клавиш
Пометить начало фрагмента	<Ctrl+K, В>
Пометить конец фрагмента	<Ctrl+K, К>
Выделить одно слово справа от курсора	<Ctrl+K, Т>
Приложение А. Интегрированная среда
401
Копировать выделенный фрагмент (в местоположение курсора, не помещая его при этом в буфер обмена) Переместить выделенный фрагмент(в местоположение курсора, не помещая его при этом в буфер обмена)
Удалить выделенный фрагмент
Считать фрагмент из файла на диске
Записать выделенный фрагмент в файл на диске
Скрыть/показать выделение фрагмента
Печатать выделенный фрагмент
Сместить фрагмент вправо
Сместить фрагмент влево
Перейти к началу выделенного фрагмента
Перейти в конец выделенного фрагмента
Выделить строку
Копировать выделенный фрагмент в буфер обмена
Вырезать выделенный фрагмент в буфер обмена Вставить содержимое буфера обмена в местоположение курсора
<Ctrl+K, О
<Ctrl+K, V>
<Ctrl+K, Y> или <Ctrl+Del>
<Ctrl+K, R>
<Ctrl+K, W>
<Ctrl+K, H>
<Ctrl+K, P>
<Ctrl+K, l>
<Ctrl+K, U>
<Ctrl+Q, B>
<Ctrl+Q, K>
<Ctrl+K, L>
<Ctrl+lns>
<Shift+Del>
<Shift+lns>
Прочие команды
В эту категорию попали комбинации клавиш, которые не удалось от-
нести ни к одной из предыдущих категорий. Действие Активизировать строку меню Сохранить файл Открыть файл Закрыть активное окно Вставка символа табуляции Включить-выключить табуляцию Включить-выключить автоотступ Создать закладку42(0-9) Перейти к закладке (0-9)	Комбинация клавиш <F10> или <Ctrl+K, D> < Ctrl+K, S> или <F2> <F3> <Alt+F3> <Ctrl+l> или <Tab> <Ctrl+O, T> <Ctrl+O, l> <Ctrl+K, n> (n = 0..9) <Ctrl+Q, n> (n = 0..9)
42 Закладка — место в тексте, помеченное особым образом. Закладка не видна и никак не влияет на работу программы. Всего в одном файле допускается п=1О закладок (О..9).
402
Turbo Pascal: учитесь программировать
Справка по слову, на котором курсор
Открыть окно Find
Открыть окно Replace
Повторить последний поиск
<Ctrl+F1>
<Ctrl+Q, F> CCtrl+Q, A> <Ctrl+L>
Приложение А. Интегрированная среда
403

Приложение Б
Модуль SYSTEM
11оскольку многие процедуры и функции модуля SYSTEM рассмотрены в предыдущих главах, а оставшиеся подпрограммы достаточно просты и не нуждаются в обширных описаниях и обилии примеров, автор не счел нужным посвящать им специальную главу (как подпрограммам модулей CRT, DOS и GRAPH). Краткие описания этих процедур и функций содержатся в данном приложении.
Управление выполнением программы
Процедура Break
Осуществляет принудительный выход из цикла.
Заголовок:
Procedure Break;
Если цикл организован с помощью оператора FOR, WHILE или REPEAT, применение процедуры Break приводит к передаче управления следующему (после тела цикла) оператору. Это напоминает действие оператора GOTO, осуществляющего переход к метке, находящейся сразу после тела цикла. При вызове процедуры Break вне цикла FOR, WHILE или REPEAT имеет место ошибка.
Процедура Continue
Осуществляет переход к следующей итерации цикла.
Заголовок:
Procedure Continue
Если цикл организован с помощью оператора FOR, WHILE или REPEAT, применение процедуры Continue прерывает текущую итерацию и инициирует переход к следующей итерации. При вызове процедуры Continue вне цикла FOR, WHILE или REPEAT имеет место ошибка.
Процедура Exit
Осуществляет выход из текущего блока программы.
Заголовок:
Procedure Exit;
Если текущим блоком является тело программы, обращение к процедуре Exit инициирует завершение программы.
406
Turbo Pascal: учитесь программировать
Процедура Най
|кН11Ш«н>х»'| 1Ч.1Н7,,|Пг;|,и/.	ри. ЛИЙ И	•«- '- < *' »' •
рмОННИНОИ I tit ТКМ*
141 fi.ittiiltitf
I ЛГ Mll< «ик — ffrf .fiu. w	f. ffaC.,1MWp ог.ДерХГЛПГИЙ < ^'.V№.
Hint lipin рамцц
процедура RunError
Ml raitanjiHhaer 0MnOjlim(W прпп?аммы и генерирует лгпиСку vcs?m.~ яи 1И41Кмненим
< Jar (UIGIUik;
Procedure AunError[(Errorcode ; fiytej];
1 Де I* rron ode — необязательный параметр. содержащий клдлтпибии
Преобразование типов
Функция Chr
Возвращает значение символьного типа, соответствующее указанному коду' из таблицы ASCH.
3ai оловок:
Function Chr(x : Byte) : Char;
где X— кол символа из таблицы ASCII.
Например, выражение Chr (104) имеет значение ' D'.
функция High
Возвращает наибольшее значение из диапазона, указанного в каче  гве параметра функции.
Загсазовок:
Func-ion з-S* х
где X —параметр. Яфеделяющий диапазон.
Возвращаем, v. \ к " * значение принадюжи г тому ке гит , ч го и ип нарамегра.1
В качествеriapa.MeipaXможегуказываться идеигнфиклгор гнил или -^ременной. ,^М р’ е‘‘-,и Параметр X принадлежи г одномч из но-рядком тш^ф якни,, oo3Bpm.m.
ии "’и	™ '"‘ч- тит
V 1Н
Поило*ение Ь. Мс
тек
чение наибольшего индекса. Если параметр X принадлежит строковому типу, функция возвратит объявленную длину строки. Если X— открытый массив или строковый параметр, функция возвратит значение типа Word, соответствующее числу элементов в открытом массиве или строковом параметре, минус единица.
Функция Low
Возвращает наименьшее значение из диапазона, указанного в качестве параметра функции.
Заголовок:
Function Low(x);
гдеХ— параметр, определяющий диапазон.
(Возвращаемое функцией значение принадлежит тому же типу, что и тип параметра.)
В качестве параметрах может указываться идентификатор типа или переменной. Например, если параметр X принадлежит одному из порядковых типов, функция возвратит наименьшее значение, допустимое для данного типа (-32768 — для Integer, FALSE — для Boolean, О — для Byte и т.п.). Если X представляет собой массив, функция возвратит значение наименьшего индекса. Если параметр X принадлежит строковому типу, функция возвратит О. Функция также возвратит О, если X— это открытый массив или строковый параметр.
Функция Ord
Возвращает порядковый номер для значения, принадлежащего одному из порядковых типов.
Заголовок:
Function Ord(x) : Longlnt;
где X — выражение, принадлежащее одному из порядковых типов.
Возвращаемое значение принадлежит типу Longlnt и является порядковым номером данного значения среди значений своего типа.
Например, выражение Ord( 'D') имеет значение 104, поскольку именно этот код соответствует символу “D” в таблице ASCII.
Однако если в качестве аргумента функции Ord служит целочисленное значение, то функция возвратит само это значение. Например, оператор writein (ord (44)) выведет на экран число 44.
Применение функции Ord к логическим значениям дает следующие результаты: ord(false)=0; ord(true)=l; (всего два значения).
Функция Round
Округляет (согласно правилам округления) значение вещественного типа до ближайшего значения целочисленного типа.
408
Turbo Pascal: учитесь программировать
Заголовок:
Function Round(х : Real) : Longlnt;
где X — выражение, принадлежащее вещественному типу.
Если округленное значение оказывается за пределами диапазона игачений, допустимых для типа Longlnt, в этом случае фиксируется лпибка времени выполнения.
Функция Trunc
Превращает значение вещественного типа в целочисленное значение путем отбрасывания дробной части.
Заголовок:
Function Trunc(х : Real) : Longlnt;
где X — исходное выражение вещественного типа.
Если полученное целочисленное значение оказывается за пределами диапазона значений, допустимых для типа Longlnt, фиксируется ошибка времени выполнения.
В чем разница между функциями Round и Trunc? Например, выражение Round(3.77) вернет значение 4 (здесь действуют правила округления), а выражение Trunc(3.77) вернет значение 3 (здесь дробная часть просто отбрасывается).
Работа с переменными порядковых типов
Процедура Dec
Уменьшает значение переменной.
Заголовок:
Procedure Dec(Var x[;N : Longlnt]);
где X — переменная, принадлежащая одному из порядковых типов;
N— необязательный параметр целочисленного типа, задающий величину. на которую требуется уменьшить X.
Значение X уменьшается на 1, если параметр N не определен, или на N в противном случае. Например, выражения Dec( 'D') и Dec( ' D', 3) имеют значения 'С'и 'А' соответственно.
Процедура Inc
Увеличивает значение переменной.
Приложение Б. Модуль SYSTEM
409
Заголовок:
Procedure Inc(Var x[;N : Longlnt]);
где X — переменная, принадлежащая одному из порядковых типов.
N — необязательный параметр целочисленного типа, задающий величину, на которую требуется увеличить X:
Значение X увеличивается на 1, если параметр N не определен, или на N в противном случае. Например, выражения Dec('A') и Dec('A',3) имеют значения'В' и'D' соответственно.
Функция Odd
Проверяет, является ли параметр нечетным числом.
Заголовок:
Function Odd(x : Longlnt) : Boolean;
где X — число, проверяемое на нечетность.
Если X— нечетное число, то выражение Odd(x) имеет значение TRUE.
Функция Pred
Возвращает значение соответствующего порядкового типа, предшествующее значению параметра.
Заголовок:
Function Pred(x);
где X— выражение, принадлежащее одному из порядковых типов.
Результат представляет собой выражение того же типа, что и X. Например: Pred(3)=2; Pred('R') = ’Q'; Pred(true)=false.
Однако следует помнить, что функцию Pred нельзя применять к первому из диапазона допустимых для данного типа значений (-32768 для Integer, FALSE для Boolean, О для Byte и т.п.).
Функция Succ
Возвращает значение, которое следует за значением параметра.
Заголовок:
Function Succ(x);
где X — выражение, принадлежащее одному из порядковых типов.
Результат представляет собой выражение того же типа, что и X, например. Succ(3)=4; Succ('R')='S'; Succ(false)=true.
Однако следует помнить, что функцию Succ нельзя применять к последнему значению диапазона допустимых для данного типа значений (32767 — для Integer, TRUE — для Boolean, 255 — для Byte и т.п.).
4И0
Turbo Pascal: учитесь программировать
Математические функции
Функция ADS
Возвращает абсолютную величину параметра.
Заголовок:
Function Abs(x);
где X — выражение вещественного или целочисленного типа.
Возвращаемое значение принадлежит тому же типу, что и параметр, и представляет собой абсолютную величину X.
Функция АгсТап
Возвращает арктангенс параметра.
Заголовок:
Function АгсТап(х : Real) : Real;
Функция Cos
Возвращает косинус параметра.
Заголовок:
Function Cos(x : Real) : Real;
где X — угол, заданный в радианах.
Функция Ехр
Возвращает экспоненциальное значение параметра.
Заголовок:
Function Ехр(х : Real) : Real;
Возвращаемое значение представляет собой число е (основание натуральных логарифмов), возведенное в степень X.
Функция Frac
Возвращает дробную часть параметра.
Заголовок:
Function Fracfx : Real) : Real;
Функция Int
Возвращает целую часть параметра.
Заголовок:
Function Int(x : Real) : Real;
Иными словами, x=Int(x)+Frac(x).
Приложение Б. Модуль SYSTEM
411
Чем функция Int отличается от функции Trunc {см. раздел “Преобразование типов”)? Напомним, функция Trunc превращает вещественное значение в целочисленное путем отбрасывания дробной части. Так вот, функция Int возвращает целую часть параметра, однако возвращаемое значение принадлежит типу Real (т.е. является вещественным), а функция Trunc, по сути, возвращает то же число, что и Int, однако, в виде целочисленного значения (типа Longlnt).
Функция Ln
Возвращает натуральный логарифм ар1умента.
Заголовок:
Function Ln(x : Real) : Real;
Функция Pi
Возвращает значение Pi (Pi = 3.1415926535897932385).
Заголовок:
Function Pi : Real;
Например, площадь круга можно вычислить с помощью выражения Pi*R*R, где R — радиус.
Функция Sin
Возвращает синус параметра.
Заголовок:
Function Sin(x : Real) : Real;
где X — угол, заданный в радианах.
В Turbo Pascal нет встроенной функции, вычисляющей тангенс. Тем не менее тангенс можно вычислить с помощью выражения Sin(x)/Cos(x).
Функция Sqr
Возвращает квадрат параметра.
Заголовок:
Function Sqr(x);
где X — вещественное, или целочисленное выражение;
Результат принадлежит тому же типу, что и X.
Функция Sqrt
Возвращает квадратный корень аргумента.
Заголовок:
Function Sqrt(x : Real) : Real;
412
Turbo Pascal: учитесь программировать
Работа со строками
Функция Length
Возвращает текущую длину строки.
Заголовок:
Function Length(s : String) : Integer;
где S — строковое значение.
Функция Pos
Ищет подстроку в строке.
Заголовок:
Function Pos(SubStr, s: String):Byte;
где SubStr — искомая подстрока;
S — строка, в которой производится поиск.
Функция возвращает целочисленное значение, соответствующее индексу первого символа SubStr внутри S. Если подстрока SubStr не найдена, то Pos возвращает нуль.
Функция Сору
Возвращает подстроку, содержащуюся в строке.
Заголовок:
Function Copyfs : String; Index, Count: Integer) : String;
где S — строка, из которой извлекается подстрока;
Index — номер элемента строки, с которого начинается подстрока;
Count — число элементов подстроки.
Функция Сору возвращает извлеченную из строки S подстроку, содержащую Count символов, начиная с символа с номером Index.
Функция Concert
Объединяет несколько строк.
Заголовок:
Function ConcatfSl [, S2,..., Sn] : String) : String;
где Sl-Sn — объединяемые строки;
Из главы 4 мы уже знаем, что объединять строки можно с помощью конкатенации. Поэтому выражение
Concat('Это строка, ','которая ','служит примером.')
имеет то же значение, что и переменная А:
а:= 'Это строка, '+'которая '+'служит примером.’
Приложение Б. Модуль SYSTEM
413
Процедура Vai
Преобразует строковое значение в числовое.
Заголовок:
Procedure Val(s; Var v; Var Code : Integer);
где S — строка цифр:
V— возвращаемая переменная типа Real или Integer.
Code — номер позиции в строке, в которой при преобразовании произошла ошибка; если ошибки не было, параметр Code возвращает нуль.
Если параметр V имеет целочисленное значение, параметр S представляет собой просто строку цифр. Если параметр V имеет вещественное значение, параметр S представляет собой строку цифр с десятичной точкой. Например, в выражении Val( '12345' ,v,Code) параметр V вернет значение 12345. Однако в выражении Val( '12.345' ,v,Code) параметр V вернет значение 1.2345000000Е+01.
Процедура Str
Преобразует числовое значение в строку цифр.
Заголовок:
Procedure Strfx [:Size [: Dec ]]; Var s : String);
где X — преобразуемое число;
Size и Dec— необязательные параметры, представляющие собой спецификатор ширины поля и спецификатор числа знаков после десятичной точки. Эти параметры имеют тот же смысл, что и аналогичные параметры процедуры Wtite (см. в главе 5 описание процедуры Write для текстовых файлов);
S — возвращаемая строка.
Процедура Insert
Вставляет подстроку в строку.
Заголовок:
Procedure Insertfsl : String; Var s2 : String; Index : Integer);
где SI — вставляемая подстрока;
S2 — возвращаемая строка, содержащая подстроку;
Index — позиция в строке S2, куда вставляется подстрока.
Если возникающая в результате строка оказывается чересчур длинной, все, что имеется в ней после 255-го символа, отбрасывается.
Процедура Delete
Удаляет подстроку из строки.
414
Turbo Pascal: учитесь программировать
Заголовок:
Procedure Delete(Var s : String; Index : Integer; Count : Integer);
где S — строка, из которой удаляется подстрока;
Index— номер позиции в строке, с которой начинается удаляемая подстрока;
Count — число символов в удаляемой подстроке.
Управление динамической памятью
Эти подпрограммы уже рассмотрены в главе 6.
Работа с адресами
Функция Assigned
Определяет, имеет указатель или процедурная переменная значение NIL.
Заголовок:
Function Assigned(Var р) : Boolean;
где Р— идентификатор переменной типа Pointer или процедурного типа.
Если Р имеет значение NIL, возвращается значение TRUE; иначе возвращается FALSE.
Функция CSeg
Возвращает текущее значение регистра CS.
Заголовок:
Function CSeg : Word;
Возвращенный функцией результат представляет собой адрес сегмента, в котором содержится программа, вызвавшая функцию CSeg.
Функция DSeg
Возвращает текущее значение регистра DS.
Заголовок:
Function DSeg : Word;
Возвращенный функцией результат представляет собой адрес сегмента, в котором содержатся данные.
Приложение Б. Модуль SYSTEM
415
Функция Ofs
Возвращает значение, соответствующее смещению адреса указанного объекта.
Заголовок:
Function Ofs(x) : Word;
где X —идентификатор переменной любого типа или имя подпрограммы.
Функция Ptr
Возвращает указатель на объект, для которого заданы сегмент и смещение.
Заголовок:
Function Ptr(Seg, Ofs : Word) : Pointer;
где Seg— выражение типа Word, значение которого соответствует сегменту;
Ofs— выражение типа Word значение которого соответствует смещению.
Функция Seg
Возвращает сегмент адреса заданного объекта.
Заголовок:
Function Seg(x) : Word;
где X— идентификатор переменной любого типа или имя подпрограммы.
Функция SPtr
Возвращает текущее значение регистра SP.
Заголовок:
Function SPtr : Word;
Возвращаемый результат представляет собой смещение указателя стека внутри сегмента стека.
Функция SSeg
Возвращает текущее значение регистра SS.
Заголовок:
Function SSeg : Word;
Возвращаемый результат представляет собой адрес сегмента стека.
416
Turbo Pascal: учитесь программировать
Ввод-вывод и работа с файлами и каталогами
Эти процедуры и функции уже рассмотрены в главе 5.
Прочее
Сюда вошли процедуры и функции модуля SYSTEM, которые не удалось отнести ни к одной из предыдущих категорий.
Процедура Exclude
Исключает элемент из множества.
Заголовок:
Procedure Exclude(Var s : Set Of t; i : t);
где S — множественная переменная;
. I — выражег ше, тип которого совместим с базовым типом множества S.
Здесь элемент I исключается из множества S. Выражения S:=S-(I) и Exclude(S,I) эквивалентны, однако процедура Exclude генерирует более эффективный код.
Процедура FillChar
Заполняет определенное количество последовательных байтов заданным значением.
Заголовок:
Procedure FillCharfVar х; Count : Word; Value);
где X— идентификатор переменной любого типа;
Count — количество заполняемых байтов;
Value — заполняющее значение (типа Byte или Char).
Например, последовательность операторов
FillChar(x,10,'W');
WriteLn(x);
выведет на экране десять символов “W”, если X— переменная строкового или регулярного типа. (Напомним, переменная регулярного типа — это массив).
При использовании процедуры FillChar проверка диапазона не проводится. Иными словами, если в приведенном примере значение параметра Count превышает количество элементов в переменной строкового или регулярного типа (X), заполненными оказкутся только имеющиеся
Приложение Б. Модуль SYSTEM	Д']
14-2016
элементы. Однако, если Count окажется меньше числа элементов, заполнятся только первые Count элементов.
Функция Hi
Возвращает значение старшего байта параметра.
Заголовок:
Function Hi(x) : Byte;
где X— выражение типа Integer или Word.
Как известно, значения типа Integer или Word занимают в памяти по 2 байта. Так вот, если значение одного из этих типов передать функции Hi, функция возвратит содержимое его старшего байта, не учитывая при этом знак параметра.
Процедура Include
Добавляет в множество новый элемент.
Заголовок:
Procedure Include(Var s : Set Of t; i : t);
где S — множественная переменная.
I — выражение, тип которого совместим с базовым типом множества S:
Здесь элемент I добавляется в множество S. Выражения S:=S+(I) и Include(S,I) эквивалентны, однако процедура Include генерирует более эффективный код.
Функция Lo
Возвращает значение младшего байта параметра.
Заголовок:
Function Lo(x) : Byte;
где X — выражение типа Integer или Word;
Как известно, значения типа Integer или Word занимают в памяти по 2 байта. Если значение одного из этих типов в качестве параметра передать функции Lo, она возвратит содержимое его младшего байта, не учитывая при этом знак параметра.
Процедура Move
Копирует байты из одной переменной в другую.
Заголовок:
Procedure Move(Var From, Tu; Count : Word);
где From — переменная, из которой копируются байты;
418
Turbo Pascal: учитесь программировать
Tu43 — переменная, в которую копируются байты;
Count — число копируемых байтов.
При использовании процедуры Move проверка на соответствие числа копируемых байтов и размеров переменный From и Tu не проводится. Поэтому, если это только возможно, всегда следует примерять процедуру SizeOf для определения размеров соответствующих переменных.
Приведем пример фрагмента программы, в которой используются процедуры Move и SizeOf:	* ,
var
х: array[1..2O] of Char;
у: string[20];
begin
if SizeOf(x)<=SizeOf(у)then
Move(x, y, SizeOf(x))
else WriteLn('He помещается')
end.
Функция ParamCount
Возвращает значение, соответствующее числу параметров, переданных программе через командную строку.
Заголовок:
Function ParamCount : Word;
Функция ParamStr
Возвращает определенный параметр командной строки.
Заголовок:
Function ParamStr(Index : Word) : String;
где Index — номер параметра, значение которого должна возвратить функция.
Если значение Index превышает число параметров (т.е. значение, возвращаемое функцией ParamCount), то ParamStr возвратит пустую строку.
Если значение Index равно О (ParamStr(O)), то ParamStr возвратит путь и имя файла (.ЕХЕ-файла) выполняемой программы.
Функция Random
Возвращает случайное число.
Заголовок:
43 п	«
Присвоить этой переменной имя То (которое по смыслу соответствовало бы подразумеваемому действию) нельзя, поскольку это зарезервированное слово, которое нельзя использовать в качестве имен переменных.
Приложение Б. Модуль SYSTEM	4^9
14
Function Random[(Range : Word)];
где Range — необязательный параметр, задающий диапазон для случайных чисел.
Если параметр Range (который должен принадлежать типу Word) не задан, это функция вернет случайное число (принадлежащее типу Real) из диапазона 0..1. Если параметр Range задан, функция вернет случайное число (целое) из диапазона О..Range.
Если значение Range задать равным О, то функция постоянно будет возвращать О.
Перед использованием функции Random генератор случайных чисел непременно требуется инициализировать. Для этого можно воспользоваться процедурой Randomize (см. далее) либо присвоить переменной RandSeed (которая определена в модуле SYSTEM) некоторое значение.
Вот пример использования функции Random и процедуры Randomize:
var i:integer;
begin
Randomize;
for i:=0 to 50 do
Write (Random(lOO),' ');
end.
Данная программа выводит на экран 50 случайных чисел из диапазона О.. 100.
Процедура Randomize
Инициализирует встроенный генератор случайных чисел, используя произвольное значение (взятое из системных часов).
Заголовок:
Procedure Randomize;
Функция Swap
Меняет местами старший и младший байты параметра.
Заголовок:
Function Swap(x);
где X— выражение типа Integer или Word.
Функция TypeOf
Возвращает указатель на таблицу виртуальных методов объекта.
Заголовок:
Procedure TypeOf(х) : Pointer
X — идентификатор объектного типа либо экземпляра объекта.
420
Turbo Pascal: учитесь программировать
Процедура TypeOf применима только к объектным типам, имеющим таблицу виртуальных методов; применение TypeOf к иными объектным типам приводит к ошибке.
Функция UpCase
Преобразует символ нижнего регистра (если это строчная буква латинского алфавита) в символ верхнего регистра.
Заголовок:
Function UpCase(Ch : Char) : Char;
где Ch — преобразуемое выражение типа Char.
Иными словами, данная функция преобразует строчные буквы в прописные. Если параметр Ch не принадлежит диапазону a'.-'z', то функция возвращает значение параметра без изменений. (Последнее касается и строчных букв кириллицы.)
Приложение Б. Модуль SYSTEM
421
ю
приложение В
^Список всех ДК процедур  и функций
Здесь представлен (в алфавитном порядке) список всех процедур и функций, рассматриваемых в этой книге. Бывает так. что имя подпрограммы помнится (поскольку эти имена мнемонические, они нередко ассоциируются с соответствующим действием, особенно у знающих английский язык), но в каком модуле эта подпрограмма содержится, вспомнить не удается. Если такое случилось с вами, найти описание нужной подпрограммы вам поможет эта таблица. Здесь для каждой подпрограммы указаны ее модуль и глава, в которой содержится искомая информация. Если это именно глава, в соответствующей колонке указан ее номер. Если это приложение, в таблице оно обозначено соот-ветствующей буквой.
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
Abs	функция	SYSTEM	Б
Addr	функция	SYSTEM	6
Append	процедура	SYSTEM	5
Arc	процедура	GRAPH	11
АгсТап	функция	SYSTEM	Б
Assign	процедура	SYSTEM	5
AssignCrt	процедура	CRT	10
Assigned	функция	SYSTEM	Б
Bar	процедура	GRAPH	11
Bar3D	процедура	GRAPH	11
BlockRead	процедура	SYSTEM	5
BlockWrite	процедура	SYSTEM	5
Break	процедура	SYSTEM	Б
ChDir	процедура	SYSTEM	5
Chr	функция	SYSTEM	Б
Circle	процедура	GRAPH	11
ClearDevice	процедура	GRAPH	11
ClearViewPort	процедура	GRAPH	11
Close	процедура	SYSTEM	5
CloseGraph	процедура	GRAPH	11
ClrEol	процедура	CRT	10
ClrScr	процедура	CRT	10
Concat	функция	SYSTEM	Б
Continue	процедура	SYSTEM	Б
Copy	функция	SYSTEM	Б
424
Turbo Pascal: учитесь программировать
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
Cos	функция	SYSTEM	Б
'CSeg	функция	SYSTEM	Б
Det	процедура	SYSTEM	Б
Delay	процедура	CRT	10
Delete	процедура	SYSTEM	Б
DelLine	процедура	CRT ...	10
DetectGraph	процедура	GRAPH	11
DiskFree	функция	DOS	9
DiskSize	функция	DOS	9
Dispose	процедура	SYSTEM	6
DosExitCode	функция	DOS	9
DosVersion	функция	DOS	9
DrawPoly	процедура	GRAPH	11
DSeg	функция	SYSTEM	Б
Ellipse	процедура	GRAPH	11
EnvCount	функция	DOS	9
EnvStr	функция	DOS	9
EoF	функция	SYSTEM	5
EoLn	функция	SYSTEM	5
Erase	процедура	SYSTEM	5
Exclude	процедура	SYSTEM	Б
Exec	процедура	DOS	9
Exit	процедура	SYSTEM	Б
Exp	функция	SYSTEM	Б
FExpand	функция	DOS	9
FilePos	функция	SYSTEM	5
RleSize	функция	SYSTEM	5
FillChar	процедура	SYSTEM	Б
FillEllipse	процедура	GRAPH	11
RHPoly	процедура	GRAPH	11
RndRrst	процедура	DOS	9
FindNext	процедура	DOS	9
FloodRII	процедура	GRAPH	11
Приложение В. Сп ^сок всех процедур и функций	425
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
Flush	процедура	SYSTEM	5
Frac	функция	SYSTEM	Б
FreeMem	процедура	SYSTEM	6
FSearch	функция	DOS	9
FSplit	процедура	DOS	9
GetArcCoords	процедура	GRAPH	11
GetAspectRatio	процедура	GRAPH	11
GetBkColor	функция	GRAPH	11
GetCBreak	процедура	DOS	9
GetColor	функция	GRAPH	11
GetDate	процедура	DOS	9
GetDefaultPalette	функция	GRAPH	11
GetDir	процедура	SYSTEM	5
GetDriverName	функция	GRAPH	11
GetEnv	функция	DOS	9
GetFAttr	процедура	DOS	9
GetFillPattern	процедура	GRAPH	11
GetFillSettings	процедура	GRAPH	11
GetFTime	процедура	DOS	9
GetGraphMode	функция	GRAPH	11
Getlmage	процедура	GRAPH	11
GetLineSettings	процедура	GRAPH	11
GetMaxColor	функция	GRAPH	11
GetMaxMode	функция	GRAPH	11
GetMaxX	функция	GRAPH	11
GetMaxY	функция	GRAPH	11
GetMem	процедура	SYSTEM	6
GetModeName	функция	GRAPH	11
GetModeRange	процедура	GRAPH	11
GetPalette	процедура	GRAPH	11
GetPaletteSize	функция	GRAPH	11
GetPixel	функция	GRAPH	11
GetTextSettings	процедура	GRAPH	11
426
Turbo Pascal: учитесь программировать
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
GetTime	процедура	DOS	9
GetVerify	процедура	DOS	9
GetViewSettings	процедура	GRAPH	11
GetX	функция	GRAPH	11
GetY	функция	GRAPH	11
GoToXY	процедура	CRT	10
GraphErrorMsg	функция	GRAPH	11
GraphResult	функция	GRAPH	11
Halt	процедура	SYSTEM	Б
Hi	функция	SYSTEM	Б
High	функция	SYSTEM	Б
HighVideo	процедура	CRT	10
ImageSize	функция	GRAPH	11
Inc	процедура	SYSTEM	Б
Include	процедура	SYSTEM	Б
InitGraph	процедура	GRAPH	11
Insert	процедура	SYSTEM	Б
InsLine	процедура	CRT	10
InstallUserDriver	функция	GRAPH	11
InstallUserFont	функция	GRAPH	11
Int	функция	SYSTEM	Б
Intr	процедура	DOS	9
lOResult	функция	SYSTEM	Б
Keep	процедура	DOS	9
KeyPressed	функция	CRT	10
Length	функция	SYSTEM	Б
Line	процедура	GRAPH	11
LineRel	процедура	GRAPH	11
LineTo	процедура	GRAPH	11
Ln	функция	SYSTEM	Б
Lo	функция	SYSTEM	Б
Low	функция	SYSTEM	Б
LowVideo	процедура	CRT	10
Приложение В. Список всех процедур и функций
427
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
Mark	процедура	SYSTEM	6
MaxAvail	функция	SYSTEM	6
MemAvail	функция	SYSTEM	6
MkDir	процедура	SYSTEM	5
Move	процедура	SYSTEM	Б
MoveRel	процедура	GRAPH	11
MoveTo	процедура	GRAPH	11
MsDos	процедура	DOS	9
New	процедура	SYSTEM	6
NormVideo	процедура	CRT	10
NoSound	процедура	CRT	10
Odd	функция	SYSTEM	Б
Ofs	функция	SYSTEM	Б
Ord	функция	‘ SYSTEM	Б
OutText	процедура	GRAPH	11
OutTextXY	процедура	GRAPH	11
PackTime	процедура	DOS	9
ParamCount	функция	SYSTEM	Б
ParamStr	функция	SYSTEM	Б
Pi	функция	SYSTEM	Б
PieSlice	процедура	GRAPH	11
Pos	функция	SYSTEM	Б
Pred	функция	SYSTEM	Б
Ptr	функция	SYSTEM	Б
Putlmage	процедура	GRAPH	11
PutPixel	процедура	GRAPH	11
Random	функция	SYSTEM	Б
Randomize	процедура	SYSTEM	Б
Read	процедура	SYSTEM	Б
ReadKey	функция	CRT	10
ReadLn	процедура	SYSTEM	Б
Rectangle	процедура	GRAPH	11
RegisterBGIDriver	функция	GRAPH	11
428
Turbo Pascal: учитесь программировать
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
RegisterBGIFont	функция	GRAPH	11
Release	процедура	SYSTEM	6
Rename	процедура	SYSTEM	5
Reset	процедура	SYSTEM	5
RestoreCrtMode	процедура	GRAPH	11
Rewrite	процедура	SYSTEM''	5
RmDir	процедура	SYSTEM	5
Round	функция	SYSTEM	Б
RunError	процедура	SYSTEM	Б
Sector	процедура	GRAPH	11
Seek	процедура	SYSTEM	5
SeekEof	функция	SYSTEM	Б
SeekEoln	функция	SYSTEM	Б
Seg	функция	SYSTEM	Б
SetActivePage	процедура	GRAPH	11
SetAIIPalette	процедура	GRAPH	11
SetAspectRatio	процедура	GRAPH	11
SetBkColor	процедура	GRAPH	11
SetCBreak	процедура	DOS	9
SetColor	процедура	GRAPH	11
SetDate	процедура	DOS	9
SetFAttr	процедура	DOS	9
SetFillPattern	процедура	GRAPH	11
SetFillStyle	процедура	GRAPH	11
SetFTime	процедура	DOS	9
SetGraphMode	процедура	GRAPH	11
SetlntVec	процедура	DOS	9
SetLineStyle	процедура	GRAPH	11
SetPalette	процедура	GRAPH	11
SetRGBPalette	процедура	GRAPH	11
SetTextBuf	процедура	SYSTEM	Б
SetTextJustify	процедура	GRAPH	11
SetTextStyle	процедура	GRAPH	11
Приложение В. Список всех процедур и функций
429
Имя подпрограммы	Вид подпрограммы	Модуль	Глава
SetTime	процедура	DOS	9
SetUserCharSize	процедура	GRAPH	11
SetVerify	процедура	DOS	9
SetViewPort	процедура	GRAPH	11
SetVisualPage	процедура	GRAPH	11
SetWriteMode	процедура	GRAPH	11
Sin	функция	SYSTEM	Б
SizeOf	функция	SYSTEM	6
Sound	процедура	CRT	10
SPtr	функция	SYSTEM	Б
Sqr	функция	SYSTEM	Б
Sqrt	функция	SYSTEM	Б
SSeg	функция	SYSTEM	Б
Str	процедура	SYSTEM	Б
Succ	функция	SYSTEM	Б
Swap	функция	SYSTEM	Б
SwapVectors	процедура	DOS	9
TextBackground	процедура	CRT	10
TextColor	процедура	CRT	10
TextHeight	функция	GRAPH	11
TextMode	процедура	CRT	10
TextWidth	функция	GRAPH	11
Trunc	функция	SYSTEM	Б
Truncate	процедура	SYSTEM	5
UnPackTime	процедура	DOS	9
UpCase	функция	SYSTEM	Б
Vai	процедура	SYSTEM	Б
WhereX	функция	CRT	10
WhereY	функция	CRT	10
Window	процедура	CRT	10
Write	процедура	SYSTEM	Б
WriteLn	процедура	SYSTEM	Б
430
Turbo Pascal: учитесь программировать
I 1риложение Структурная схема программы
В различных главах книги при изучении соответствующих тем шла речь о таких разделах программы, как заголовок, разделы описания типов, переменных, меток, констант, подпрограмм и тело программы. Однако при этом информация, в общем-то относящаяся к одной теме, оказалась распылена по нескольким главам. Поэтому автор счел, что в данной книге окажется нелишним специальное приложение со структурной схемой программы, на которой представлены все возможные разделы, а также кратким изложением соответствующей информации.
Итак, представим схему программы:
program ххх; {заголовок необязателен}
const
Раздел описания констант
label
Раздел описания меток
type
Раздел описания типов
var
Раздел описания переменных
| Описания подпрограмм
begin
Тело программы end.
В первой строке схемы находится заголовок программы. Заголовок начинается зарезервированным словом PROGRAM, за которые следует имя программы, которое ей присвоил автор. Завершается заголовок точной с запятой. В одной из глав уже шла речь о том, что в Turbo Pascal заголовок не является обязательным элементом программы.
После заголовка на схеме представлены разделы описаний констант, типов, меток и переменных. Причем Turbo Pascal вовсе не предписывает порядок, в котором должны следовать эти разделы. Вот пример простейшей программы:
label 1,2;
const а=2;
var с:real;
type b=integer;
begin
end.
432
Turbo Pascal: учитесь программировать
(Правда, эта “программа" не выполняет никаких действий, однако ее можно запустить или откомпилировать как любую другую программу.) Так вот, упомянутые четыре раздела (которые начинаются с зарезервированных слов CONST, TYPE, LABEL и VAR) можно расположить в этой программе в любом порядке. Однако, если в одном из этих разделов объявлен элемент программы, на который имеется ссылка в другом разделе (например, в разделе описания переменных объявляется переменная с типом, объявленным в разделе описания типов), это дписание, на которое существует ссылка, должно предшествовать ссылающемуся описанию.
Также Turbo Pascal вовсе не предписывает, что в программе должно быть не более одного раздела описаний типов, меток, констант или переменных и что все соответствующие описания должны быть собраны в едином разделе. Иными словами, ничто не мешает при необходимости создать в программе два раздела описаний меток или два раздела описаний типов, например.
После разделов описаний меток, типов, констант и переменных идут описания подпрограмм (если в данной программе используются подпрограммы). Описания подпрограмм следуют одно за другим, причем, если одна подпрограмма вызывается из другой, первая должна быть описана раньше.
После описаний подпрограмм начинается тело программы (или ее раздел операторов). Оно всегда открывается зарезервированным словом BEGIN и завершается словом END. (с точкой).
Приложение Г. Структурная схема программы
433
1
^Приложение Д
Ресурсы Internet, посвященные Turbo Pascal
Данное приложение предназначено для читателей, имеющих доступ к Internet. Здесь перечислены адреса ресурсов информационной супермагистрали, где изучающие язык программирования Turbo Pascal найдут для себя много полезного. Соответствующие Web-страницы содержат тексты программ и файлы модулей, документацию и разного рода руководства, файлы драйверов и шрифтов — и все это можно загрузить (или, как говорят пользователи, “скачать”) на свой компьютер. Кроме того, если у вас возникли вопросы, а обратиться не к кому, к вашим услугам Web-страницы с посвященными Turbo Pascal форумами, где вы ваши вопросы можете просто ввести с клавиатуры. В Internet-сообществе обязательно найдется кто-то, кто знает ответ на ваш вопрос и рад вам помочь.
•	http://be-club.narod.ru/upload/library/pascal.html— архивные файлы, которые можно загрузить на свой ПК (документация, руководства, модули, программы);
•	http://garbo.uwasa.fi/pc/turboobj.html— программы на Turbo Pascal, созданные на основе ООП:
•	http://garbo.uwasa.fi/pc/turbopas.html— начальные сведения о программировании на Turbo Pascal;
•	http://huizen.dto.tudelft.nl/deBrui jn/programs/pascal.htm — программы и модули;
•	http://infobase.hypermart.net/pascal/programs.htm— множество модулей и различных программ;
•	http://infocity.kiev.ua/main.phtml?r=pascal.php3— литература по Turbo Pascal (тексты, которые можно загрузить на свой ПК):
•	http://mph.phys.spbu.ru:8080/~nemnugin/pascal.html— обширная информация, посвященная программированию на Turbo Pascal;
•	http://pasc.al.ru/www/exampl.htm— страница, посвященная Turbo Pascal (примеры программ, форум);
•	http://pascal.sources.ru/ — исходные тексты программ, FAQ, форум, документация и многое другое;
•	http://p-gilza.chat.ru/turbo/turbo2.htm—программы на Turbo Pascal;
•	http://prog.agava.ru/lib/pascal/— различные руководства по Turbo Pascal, форум;
•	http://study.tsu.tmn.ru/homepages/mvorobyeva/Pascal/Utilits.htm — описание (по-русски) утилит, поставляемых с Turbo Pascal 7.0 (TPUMOVER, MAKE, TOUCH, CREP, и BINOBJ);
•	http://tp7.hotmail.ru/—узел, посвященный программированию на Turbo Pascal (коды, FAQ и прочее);
•	http://www.cit.ac.nz/smac/pascal/default.htm—учебные материалы по Pascal;
•	http://www.dickmann.org/pascal/misc.htm — множество программ;
436
Turbo Pascal: учитесь программировать
http://ww.freepascal.org - Web-страница, посвященная Pascal;
http://ww.freepascal.org/contrib/db.php3— множество доступных для загрузки модулей;
http://ww.geocities.com/~franzglaser/tp.html— множество различных материалов по Turbo Pascal;
http://ww.geocities.com/Area51 / Vault/9912Z16bit.htm — страница, посвященная Turbo Pascal (игры, программы, драйверы, шрифты);
http://ww.karelia.ru/psu/Chairs/IMO/pascal/— обучающий комплекс по языку программирования Pascal (Петрозаводский Государственный Университет);
http: //ww.Ils. se/~mux/area9.htm — множество библиотек модулей для Turbo Pascal;
http://ww.pascal-central.com/plinks.html— каталог ссылок на Web-страницы, группы новостей, списки рассылок и FTP-узлы, посвященные Turbo Pascal;
http://ww.programmersheaven.com/zone24/cat298/— множество ZIP-файлов с различным содержимым, доступных для загрузки; кроме того, ссылки на другие Web-узлы, посвященные Turbo Pascal;
http://ww.sote.hu/kszerv/kszerve/idk/idk/tp.html— страница для программирующих на Turbo Pascal;
http://ww.taoyue.com/tutorials/pascal/contents.html — интерактивное руководство по Pascal;
•	http://ww.uwasa.fi/~ts/garbinfo/garb2030.html— программы, драйверы и различные материалы по программированию на Turbo Pascal.
•	http://ww.tubopower.com. — странице Turbo Power Software Company— одного из ведущих производителей инструментальных средств.
Помните, что Internet— это живой, постоянно изменяющийся организм. Что-то здесь отмирает, а взамен появляется еще больше нового. Возможно, когда вы будете читать эту кншу, по указанному адресу не окажется какой-то информации либо упомянутая здесь страница уже прекратила существование. Не беда, стоит лишь поискать, и вы обнаружите массу новых ресурсов Internet, посвященных языку программирования Turbo Pascal.
Приложение Д. Ресурсы Internet, посвященные Turbo Pascal 437
риложение Е
Таблица ASCII
В данном приложении приводится таблица ASCII (American Standard Code for Information Interchange — Американский стандартный код для информационных обменов). Стандарт ASCII включает 128 символов с кодами О.. 127. Эти символы и коды представлены в табл. Е. 1 (в каждой ячейке таблицы слева приведен десятичный код и справа соответствующий этому коду символ).
Таблица Е. 1. Основная таблица ASCII
0 NUL	16 OLE	32	48 0	64 @	80 P	96 •	112 p
1 SOX	17 DC1	33 !	49 1	65 A	81 Q	97 a	из q
2 STX	18 DC2	34 "	50 2	66 в	82 R	98 b	114 r
3 ЕТХ	19 DC3	35 #	51 3	67 C	83 S	99 c	115 S
4 EOT	20 DC4	36 $	52 4	68 D	84 T	100 d	116 t
5 ENQ	21 NAC	37 %	53 5	69 E	85 U	101 e	117 U
6 АСК	22 SYN	38 &	54 6	70 F	86 V	102 f	118 v
7 BEL	23 ETB	39 '	55 7	71 G	87 W	юз g	119 W
8 BS	24 CAN	40 (	56 8	72 H	88 X	104 h	120 X
9 TAB	25 EM	41 )	57 9	73 |	89 Y	105 i	121 у
Ю LF	26 SUB	42 *	58 :	74 J	90 Z	106 j	122 z
11 VT	27 ESC	43 +	59 ;	75 К	91 [	107 k	123 {
12 FF	28 FS	44 ,	60 <	76 L	92 \	108 |	124 |
13 CR	29 GS	45 -	61 =	77 M	93 ]	109 m	125 }
14 SO	30 RS	46 .	62 >	78 N	94 "	110 П	126 ”
15 SI	31 US	47 /	63 ?	79 0	95 .	111 о	127 □
Первые 32 (О..31) кода управляющие (т.е., если генерировать один из них, будет выполнена соответствующая команда). Именно поэтому рядом с данными кодами в таблице присутствуют не символы, а мнемонические имена команд. Всем остальным кодам соответствуют символы (при генерации этих кодов на экран выводятся соответствующие символы).
Как указывалось выше, стандарт ASCII включает только 128 символов с кодами О.. 127. Однако набор символов IBM PC состоит из 256 символов. В силу этого имеется еще одна таблица, подобная приведенной выше, которую часто называют расширением основной таблицы ASCII (иными словами, коды и символы, содержащиеся в этой таблице, в полном смысле слова стандартом не являются). При этом символы, соответствующие кодам 128..255, на разных ПК могут отличаться. Расширение основной таблицы ASCII обычно составляют символы псевдографики, буквы национальных алфавитов и иные символы.
440
Turbo Pascal: учитесь программировать
Расширение таблицы ASCII, соответствующее знакогенератору IBM PC, можно видеть в табл. Е. 2.
Таблица Е.2. Знакогенератор IBM PC
128 £	144 Е	160	a	176 1	192	L	208 JL	224 а	240 =
129 U	145 ге	161	i	177 s	193	JL	209 T	225 6	241 ±
1зо ё	146 R	162	6	178 H	194		. 2Ю -Jr	226 Г	242 >
131 a	147 6	163	u	179 |	195	F	211 IL	227 п	243 <
132 a	148 б	164	n	180 -|	196		212 1=	228 £	244 [
133 a	149 О	165	ft	181 =|	197	+	213 F	229 о	245 J
134 a	150 U	166	a	182 J	198	h	214 r	230 р	246 -?
135 Q	151 U	167	о	183 ц	199	IF	215 f	231 т	247 «
136 ё	152 ¥	168	C	184 =|	200	IL	216 f	232 ф	248 •
137 ё	153 б	169	r~	185 1	201	If	217 J	233 0	249 •
138 ё	154 U	170	—i	186 II	202	JL	218 r	234 Q	250 
139 I	155 С	171	4	187 =fl	203	if	219 |	235 б	251
140 1	156 £	172	4	188 =U	204	IF	220 H	236 ~	252 >>
141 i	157 ¥	173	i	189 Л	205		221 |	237 0	253 2
142 А	158 Ёв	174	«	190 J	206	JL 1Г	222 |	238 £	254 
143 А	159 S	175	»	191 i	207		223 	239 П	255 □
Для русскоязычных пользователей подходит расширение таблицы ASCII, известное как кодовая таблица 866 (см. табл. Е. 3).
Таблица Е.З. Знакогенератор с кириллицей
(Кодовая таблица 866)
128 129	L	144 -И- 145 =j=	160 а		176 I 177 1	1	192 j	193	L	208 JL 209 у	224 р 225 С	240 Ё	
			161	В						241	ё
130	Т	146 IT	162	Г	178 |	j 194	Т	210 1Г	226 Т	242	е
131		147 И-	163	П	179	195	J-	211 И-	227 у	243	е
132		148 1=	164	z	180 -	196		212 1=	228 ф	244	I
133		149 f=	165	о	181 =	197		213 р	229 X	245	1
134		150 r	166	р	182	198	=	214 г	230 Ц	246	—>
135		151 -	167	т	183 -|	।	199		215 -	231 Ч	247	<—
136	|L	152 = =	168	ф	184 =	200		216 = =	232 Ш	248	г
137	IF	153 -	169	е	185 J	201	IF	217 	233 Щ	249	т
138	JL	154 r	170	Q	186 |	202	JL	218 г	234 Ъ	250	4-
139		155 |	171	б	187 =|	1	203		219 1	235 Ы	251	±
140	1г	156 p	172	©о	188 J	1	204	1г	220 р	236 Ь	252	№
141		157 1	173	0	189 J	1	205			237 Э	253	п
142	JL тг	158 J	174	£	190	206	JL тг	222 J	238 Ю	254	
143	JL	159 	175	П	191	207	JL	223 	239 Я	255	□
Приложение Е. Таблица ASCII
441
Предметный указатель
IDE, 336
м
MS DOS, 127
Б
библиотеки модулей. 203
3
заголовок,18
зарезервированные слова, 19;
31
И
инкапсуляция, 319
К
клавиша
быстрая, 341
горячая, 343
комментарии, 32
константы, 34
типизированные, 182
м
меню, 342
Compile, 360
Debug, 363
Edit, 351
File, 345
Help, 395
Options, 373
Run, 358
Search, 353
Tools, 371
Window, 391 локальное, 399 метод, 319
виртуальный, 326 деструктор, 330 конструктор, 329 модуль, 190
CRT, 192
DOS, 192
GRAPH, 193
OVERLAY, 193
PRINTER, 192
SYSTEM, 192
TURBO3, 193 заголовок, 194 использование, 199 компиляция, 197 раздел
инициирующий, 197 интерфейсный, 195 реализации, 196
структура, 193
н
наследование, 323
О
окно диалоговое, 338 информационное, 337 редактора, 337
ООП, 318
442
Предметный указатель
оператор, 38
CASE. 42
FOR, 51
IF. 39
REPEAT. 48
WHILE. 45
WITH. 60: 104 перехода. 57 присваивания,38 простой, 38 пустой, 59 составной,38 структурированный, 38 условный, 39 цикла. 45
операция DIV, 28 MOD, 28 логическая, 29 сравнения, 27 описание
опережающее, 75
п
амять динамическая, 158 переменные, 33 подпрограмма, 62 параметры, 68 значения, 70 переменные, 70 стандартная, 76
поле объекта, 319 полиморфизм, 329 процедура, 63
Append, 149
Arc, 290
Assign, 126 AssignCrt, 244 Bar, 294 Bar3D, 295 BlockRead, 151 BlockWrite, 152
Break. 406
ChDir, 14Q
Circle, 289 ClearDevice, 276 ClearViewPort, 276 Close, 141
CloseGraph, 264 CIrEol, 250 ClrScr, 250
Continue, 406 Dec, 409
Delay, 252
Delete. 414
DelLine, 251 DetectGraph. 257 Dispose, 171 DrawPoly, 287 Ellipse, 292 Erase, 141 Exclude, 417 Exec, 228 Exit, 406
FillChar, 417 FillEllipse, 298 FillPoly, 297 FindNext, 223 FloodFill, 293 Flush, 149 FreeMem, 171
FSplit. 225
GetArcCoords, 291 GetAspectRatio, 276 GetCBreak, 232 GetDate, 217 GetDir, 141 GetFAttr, 224 GetFillPattern, 272 GetFillSettings, 272 GetFTime. 219 Getlmage, 313 GetLineSettings, 285 GetMem. 171 GetModeRange, 262 GetPalette, 267
443
оедметный указатель
GetTextSettings, 310 GetTime, 217 GetVerify, 233 GetViewSettings, 275 GoToXY, 248 Halt, 407 HighVideo. 247 Inc, 409 Include, 418 InitGraph, 254 Insert, 414 InsLine, 251 Intr, 211 Keep, 228 Line, 281 LineRel, 282 LineTo, 281 LowVideo, 247 Mark. 172 MaxAvail, 172 MkDir, 140 Move, 418 MoveRel, 274 MoveTo, 273 MsDos, 213 New. 173 NoSound, 251 Odd, 410 OutText, 302 OutTextXY. 302 PackTime, 220 PieSlice, 300 Putlmage, 313 PutPixel, 280 Randomize, 420 Read, 143; 145 ReadLn, 146 Rectangle, 287 Release, 174 Rename, 140	RunError, 407 Sector, 299 Seek, 133 SerFTime, 219 SetActivePage, 311 SetAllPalette, 269 SetAspectRatio, 278 SetBkColor, 267 SetCBreak, 233 SetColor, 265 SetDate, 217 SetFAttr, 225 SetFillPattern, 271 SetFillStyle, 269 SetGraphMode, 260 SetlntVec, 215 SetLineStyle, 283 SetPalette, 268 SetRGBPalette, 268 SetTextBuf. 148 SetTextJustify, 305 SetTextStyle, 303 SetTime, 218 SetUserCharSize, 307 SetVerify, 234 SetViewPort, 274 SetVisualPage, 311 SetWriteMode, 286 Sound, 251 Str, 414 SwapVectors, 229 TextBackground, 245 TextColor, 245 TextMode, 244 Truncate. 134 UnpackTime, 219 Vai, 414 Window, 249 Write, 143; 146 WriteLn, 148
Reset, 130 RestoreCrtMode, 259 Rewrite, 131 RmDir, 140	P рабочая область, 336
444	Предметный указатель
рекурсия, 72
С
строка меню, 342 подсказки, 344
таблица ASCII, 53; 440 типы данных, 26; 78
Boolean, 29
Char, 28
Integer, 27
POINTER, 159
Real, 27
вещественные, 80
интервальный (диапазон), 87
комбинированный (запись), 102
логический, 85 множественный, 110 перечислимый, 86 порядковые, 82 приведение, 119 простые, 79
регулярный (массив), 93 символьный, 84 совместимость, 117 строковый, 89
структурированные, 93 целочисленные, 82
У
указатель, 159
нетипизированный. 159
типизированный, 159 управление
выводом на экран, 243
звуком, 251
клавиатурой,238
Ф
файл, 122
INPUT, 144
OUTPUT, 144
виды, 123
имя, 128
маркер конца, 124
открытие, 130
текстовый, 143
типизированный, 142 указатель текущей позиции,
125
функция, 65
Abs, 411
Addr, 170
ArcTan, 411
Assigned, 415
Chr, 407
Concat, 413
Copy, 413
Cos, 411
CSeg, 415
DiskFree, 221
DiskSize, 221
DosExitCode, 229
DosVersion, 234
DSeg, 415
EnvCount, 231
EnvStr, 231
EoF, 138
EoLn, 149
Exp, 411
FExpand, 226
FilePos, 136
FileSize, 136
Frac, 411
FSearch, 227
GetBkColor, 267
GetColor, 266
GetDefaultPalette, 269
GetDriverName, 261
GetEnv, 232
GetGraphMode, 260
Предметный указатель
445
GetMaxColor, 266
GetMaxMode, 261
GetMaxX, 273
GetMaxY, 273
GetModeName, 260
GetPaletteSize, 269
GetPixel, 280
GetX, 273
GetY, 273
GraphErrorMsg, 259
GraphResult, 258
Hi, 418
High, 407
ImageSize, 313
InstallUserDriver, 264
InstallUserFont, 310
Int, 411
lOResult, 133
Key Pressed, 240
Length, 413
Ln, 412
Lo, 418
Low, 408
MemAvail, 173
Ofs, 416
Ord, 408
ParamCount, 419
ParamStr, 419
Pi, 412
Pos, 413
Pred, 410
Ptr, 416
Random, 419
ReadKey, 240
RegisterBGIDriver, 315
RegisterBGIFont, 316
Round, 408
SeekEof, 150
SeekEoln, 150
Seg, 416
Sin, 412
SizeOf. 175
SPtr, 416
Sqr, 412
Sqrt, 412
SSeg, 416
Succ, 410
Swap, 420
TextHeigh, 309
TextWidth, 309
Trunc, 409
TypeOf, 420
UpCase, 421
WhereX, 248
WhereY, 248
Э
экземпляр объекта, 320
446
Предметный указатель
Научно-популярное издание
Олег Анисимович Меженный
Turbo Pascal: учитесь программировать
Литературный редактор Верстка Художественный редактор Технический редактор Корректоры
Л. И. Лесько
А .В. Говдя
С.А. Чернокозинский
ГН Горобец
Л.А. Гордиенко, Л. В. Коровкина
Издательский дом “Вильямс” 101509, г. Москва, ул. Лесная, д. 43, стр. I Изд. лиц. ЛР № 090230 от 23.06.99 Госкомитета РФ по печати
Подписано в печать 04.07.2001. Формат 60 х 90/16.
Гарнитура Times. Печать офсетная.
Усл. печ. лист. 27,0. Уч.-изд. лист. 19,5. Тираж 5000 экз. Заказ № 2016.
Отпечатано с диапозитивов в АООТ “Типография «Правда»” 191119, С.-Петербург, ул. Социалистическая, 14.
TURBO
PASCAL
Учитесь программировать
В этой книге*
*	Подробное освещение таких тем языка программирования Turbo Pascal, как операторы, подпрограммы, типы данных, файлы, указатели, модули, объектно-ориентирс тонное программирование
•	Примеры программ, тексты которых содержатся на Web-узле издательства "Диалектика", откуда их можно загрузить на свой компьютер
•	Подробные сведения о ресурсах модулей поставляемых в составе пакета Turbo Pascal 7.0
•	Исчерпывающая информация о среде разработчика Turbo Pascal 7.0
•	Перечень ресурсов Internet, где изучающие язык программирования Turbo Pascal найдут для себя много полезного
•	И многое другое
Категория: ПК, программирование, Turbo Pascal Уровень: Для начинающих пользователей
,Р|дЦДЛЕКПН1КД
http7/www.dlalektlka.com
ОБ АВТОРЕ
О. А. Меженный имеет дело с вычислительной техникой свыше 20 лет Из них 7 лет (или около того) он переводит книги о компьютерах. На каком-то этапе, вместо перевода чужих книг, он решил написать собственную. Благо, такую возможность любезно предоставило издательство "Диалектика"