1
5
1
-
http://books.altspu.ru/files/original/1/1/_[650].png
167b34274d867f7086a61c48282586f9
http://books.altspu.ru/files/original/1/1/Abramkin_Programmirovanie_v_srede_Turbo_Pascal[protection].pdf
02255134417ec998ee9c04da2f9fd33d
PDF Text
Text
Оглавлен ие
�Оглавлен ие
Об издании
Основной титульный экран
Дополнительный титульный экран непериодического издания – 1
Дополнительный титульный экран непериодического издания – 2
�Оглавлен ие
Министерство образования и науки Российской Федерации
Федеральное государственное бюджетное образовательное учреждение высшего образования
«АЛТАЙСКИЙ ГОСУДАРСТВЕННЫЙ ПЕДАГОГИЧЕСКИЙ УНИВЕРСИТЕТ»
Г.П. АБРАМКИН, Ю.С. ЕФРЕМОВ, О.В. ТОКАРЕВА
ПРОГРАММИРОВАНИЕ
в среде Турбо Паскаль
Учебное пособие
Барнаул
ФГБОУ ВО "АлтГПУ"
2015
Об издании - 1, 2, 3.
ISBN 978–5–88210–774–0
�Оглавлен ие
ББК 74
УДК 37
А16
Абрамкин, Г.П.
Программирование в среде Турбо Паскаль [Электронный ресурс] : учебное пособие
Абрамкин, Ю.С. Ефремов, О.В. Токарева. – Барнаул : АлтГПУ, 2015.
ISBN 978–5–88210–774–0
/ Г.П.
Рецензенты:
Овчаров А.В. – доктор пед. наук, зав. кафедрой теоретической физики и математики АлтГПУ;
Шулиманова З.Л. – доктор физ.-мат. наук, зав. кафедрой физики и химии Российской открытой
академии транспорта Московского государственного университета путей сообщения.
Текстовое (символьное) электронное издание.
Деривативное электронное издание.
Системные требования:
Intel Celeron 2 ГГц ; ОЗУ 512 Мб ; Windows XP/Vista/7/8 ; SVGA монитор с разрешением 1024х768.
Об издании - 1, 2, 3.
�Оглавлен ие
Электронное издание создано при использовании программного обеспечения Sunrav BookOffice.
Объём издания - 7 514 КБ.
Размещено на сайте: 01.06.2015
Федеральное государственное бюджетное образовательное учреждение высшего образования
«Алтайский государственный педагогический университет» (ФГБОУ ВО «АлтГПУ»)
ул. Молодежная, 55, г. Барнаул, 656031
Тел. (385-2) 36-82-71, факс (385-2) 24-18-72
е-mail: rector@altspu.ru, http://www.altspu.ru
Об издании - 1, 2, 3.
�Оглавлен ие
Оглавление
Лабораторная работа № 1. Знакомство со средой Турбо Паскаль.
Как начать работу с Турбо Паскалем
Функциональные клавиши
Текстовый редактор
Основные приемы работы в среде Турбо Паскаля
Работа с файлами
Прогон и отладка программы
Справочная служба Турбо Паскаля
Практическая работа в среде Турбо Паскаль 7.0
1. Запуск среды
2. Первое знакомство. Основное меню
3. Работа в редакционном окне. Создание программы
4. Сохранение программы.
5. Компиляция программы.
6. Выполнение программы.
7. Отладка программы.
Лабораторная работа № 2. Составление линейных программ.
Контрольные задания
Лабораторная работа № 3. Типы данных. Функции преобразования типа.
Контрольные задания
Лабораторная работа № 4. Операции отношений. Логические операции.
Контрольные задания
Лабораторная работа № 5. Условный и составной операторы.
Контрольные задания
Лабораторная работа № 6. Оператор выбора.
Контрольные задания
Лабораторная работа № 7. Циклы.
Контрольные задания
Лабораторная работа № 8. Массивы.
Контрольные задания
Приложение
Лабораторная работа № 9. Строковый тип данных.
Контрольные задания
Лабораторная работа № 10. Процедуры и функции.
Контрольные задания
Лабораторная работа № 11. Множества.
Вопросы и упражнения
Контрольные задания
�Оглавлен ие
Лабораторная работа № 12. Записи.
Вопросы и упражнения
Контрольные задания
Лабораторная работа № 13. Файлы.
Стандартные файлы
Файлы последовательного доступа
Файлы произвольного доступа
Текстовые файлы
Процедуры и функции обработки текстового файла
Файлы без типа
Контрольные задания
Лабораторная работа № 14. Модули.
Контрольные задания
Лабораторная работа № 15. Динамические структуры данных.
Контрольные задания
Лабораторная работа № 16. Процедуры подготовки к работе в графическом режиме.
Контрольные задания
Лабораторная работа № 17. Рисование графических примитивов и фигур.
Система координат. Текущий указатель.
Линии и их стили.
Коэффициент сжатия изображения.
Окружности, эллипсы, дуги.
Контрольные задания
Лабораторная работа № 18. Управление цветами и шаблонами заливки (заполнения).
Контрольные задания
Лабораторная работа № 19. Битовые графические операции.
Контрольные задания
Лабораторная работа № 20. Управление видеостраницами. Графические окна. Вывод текста.
Контрольные задания
Лабораторная работа № 21. Управление клавиатурой.
Контрольные задания
Лабораторная работа № 22. Основные понятия объектно-ориентированного программирования.
Задания для самостоятельной работы
Лабораторная работа № 23. Элементы Turbo Vision.
Задания для самостоятельной работы
Лабораторная работа № 24. Окна.
Задания для самостоятельной работы
Лабораторная работа № 25. Интерьер.
�Задания для самостоятельной работы
Лабораторная работа № 26. Скроллинг.
Задание для самостоятельной работы
Лабораторная работа № 27. Диалоговые окна.
Управление диалоговыми окнами
Статический текст
Кнопки
Создание кластеров
Строка ввода
Установка и получение данных
Другие элементы управления
Задание для самостоятельной работы
Приложение
Встроенный ассемблер
Сообщения и коды ошибок
Библиографический список
Оглавлен ие
�Оглавлен ие
Лабораторная работа № 1
ЗНАКОМСТВО СО СРЕДОЙ ТУРБО ПАСКАЛЬ
Система программирования Турбо Паскаль представляет собой единство двух в известной степени
самостоятельных начал: компилятора с языка программирования Паскаль (язык назван в честь
выдающегося французского математика и философа Блеза Паскаля (1623–1662)) и некоторой
инструментальной программной оболочки, способствующей повышению эффективности создания
программ. Для краткости условимся в дальнейшем называть реализуемый компилятором язык
программирования Паскаль языком Турбо Паскаль, а разнообразные сервисные услуги,
предоставляемые программной оболочкой – средой Турбо Паскаля.
Среда Турбо Паскаля – это первое, с чем сталкивается любой программист, приступающий к
практической работе с системой. Если по каким-либо причинам Вы не собираетесь писать
собственные программы, можно пропустить эту главу, в которой приводятся минимальные сведения
об основных приемах работы в среде Турбо Паскаля.
�Оглавлен ие
Как начать работу с Турбо Паскалем
Система Турбо Паскаль довольно значительна по объему. Она поставляется на нескольких
дистрибутивных дискетах и устанавливается на жесткий диск. При развертывании системы на
жестком диске обычно создается отдельный каталог с именем BP (или TP, TURBO, PASCAL и т.п.), в
который помещаются все файлы с дистрибутивных дискет. Для вызова Турбо Паскаля необходимо
отыскать в древовидной структуре каталогов ПК этот каталог и в нем файл с именем TURBO. EXE.
Этот файл содержит готовую к работе диалоговую систему программирования Турбо Паскаль. В
него входят минимально необходимые части Турбо Паскаля (текстовый редактор, компилятор,
компоновщик, загрузчик). Для нормальной работы в диалоговой среде понадобятся также основная
библиотека, располагающаяся в файле TURBO.TPL, и справочная служба (файл TURBO.HLP). В
принципе, этих файлов достаточно для написания, компиляции и исполнения большинства примеров,
содержащихся в этой книге.
Пусть перечисленные файлы располагаются в каталоге BP на диске C. Тогда для вызова Турбо
Паскаля следует дать команду
C:\BP\BIN\TURBO.
По этой команде операционная система MS–DOS поставит на исполнение программу из файла
TURBO.EXE: загрузит программу в оперативную память и передаст ей управление.
Не рекомендуется работать с системой, назначив в качестве каталога по умолчанию (текущего каталога)
тот, в котором хранятся перечисленные выше файлы (этот каталог будем называть системным).
Во-первых, в таком случае можно ошибочно стереть какой-либо из файлов системы
программирования и тем самым нарушить ее работоспособность, а во-вторых, этот каталог очень
скоро за-полнится другими файлами, прямо не относящимися к Турбо Паскалю. Существует и еще
одна причина, по которой нежелательно работать в системном каталоге. Дело в том, что Турбо
Паскаль имеет свойство «запоминать» свою настройку в двух файлах с именами TURBO.TP и
TURBO.PCK. При вызове система начинает поиск этих файлов в текущем каталоге. Если этот каталог
– Ваш индивидуальный, система всякий раз будет настраиваться так, как Вы этого хотите. Если эти
файлы не обнаружены в Вашем каталоге (а при первом обращении к Турбо Паскалю так оно и будет),
система продолжит поиск в системном каталоге, а не найдя их там, настроится стандартным образом.
Впоследствии можно сохранить настроечные файлы в своем каталоге и тем самым избавить себя от
необходимости перенастройки системы всякий раз при обращении к ней.
После успешного вызова системы экран ПК приобретает вид, показанный на рис. 1.
�Оглавлен ие
Рис.1. Вид экрана после вызова Турбо Паскаля
Сразу же скажем, что для выхода из Турбо Паскаля следует нажать клавишу Alt и, не отпуская ее, –
клавишу с латинской буквой X, после чего можно отпустить обе клавиши.
Верхняя строка содержит «меню» возможных режимов работы Турбо Паскаля, нижняя – краткую
справку о назначении основных функциональных клавиш. Вся остальная часть экрана принадлежит
окну редактора, очерченному двойной рамкой и предназначенному для ввода и коррекции текста
программ. В его верхней строке приводятся имя того дискового файла, откуда был прочитан текст
программы (новому файлу присваивается имя NONAME00.PAS), два специальных поля,
используемых при работе с устройством ввода «мышь» (эти поля выделены квадратными скобками), и
цифра 1 – номер окна. В Турбо Паскале можно работать одновременно с несколькими программами
(или частями одной крупной программы), каждая из которых может располагаться в отдельном окне
редактора, Среда позволяет использовать до девяти окон редактора одновременно.
Кроме окна (окон) редактора, в Турбо Паскале используются также окна: отладочного режима,
вывода результатов работы программы, справочной службы, стека, регистров. По желанию они могут
вызываться на экран поочередно или присутствовать на нем одновременно.
�Оглавлен ие
Функциональные клавиши
Функциональные клавиши используются для управления средой Турбо Паскаля. Они обозначаются F1,
F2, ..., F12 и располагаются в самом верхнем ряду клавиатуры. С каждой из этих клавиш связывается
некоторая команда меню. Действие почти всех функциональных клавиш можно модифицировать
тремя особыми клавишами: Alt (от ALTernative – дополнительный), Ctrl (ConTRoL – управление) и
Shift (SHIFT – сдвиг). Эти клавиши используются подобно клавише временной смены регистра на
пишущей машинке: нужно нажать на одну из них и затем, не отпуская ее, нажать функциональную
клавишу. В дальнейшем такое совместное нажатие двух клавиш будем обозначать знаком +. Например,
Alt+F3 означает, что вместе с клавишей Alt необходимо нажать клавишу F3, Ctrl+F9 – вместе с Ctrl
нажимается клавиша F9 и т.д.
Ниже приводятся команды, которые передаются среде Турбо Паскаля функциональными клавишами
и некоторыми их комбинациями с клавишами Ctrl и Alt:
F1 – обратиться за справкой к встроенной справочной службе (Help – помощь);
F2 – записать редактируемый текст в дисковый файл;
F3 – прочитать текст из дискового файла в окно редактора;
F4 – используется в отладочном режиме: начать или продолжить исполнение программы и
остановиться перед исполнением той ее строки, на которой стоит курсор;
F5 – распахнуть активное окно на весь экран;
F6 – сделать активным следующее окно;
F7 – используется в отладочном режиме: выполнить следующую строку программы; если в строке есть
обращение к процедуре (функции), войти в эту процедуру и остановиться перед исполнением первого
ее оператора;
F8 – используется в отладочном режиме: выполнить следующую строку программы; если в строке есть
обращение к процедуре (функции), исполнить ее и не прослеживать ее работу;
F9 – компилировать программу, но не выполнять ее;
F10 – перейти к диалоговому выбору режима работы с помощью главного меню;
Ctrl+F9 – выполнить прогон программы: компилировать программу, находящуюся в редакторе,
загрузить ее в оперативную память и выполнить, после чего вернуться в среду Турбо Паскаля;
Alt+F5 – сменить окно редактора на окно вывода результатов работы (прогона) программы.
Описание некоторых функциональных клавиш.
Во-первых, Вам понадобятся команды Ctrl+F9 для проверки работы Вашей программы и Alt+X для
выхода из Турбо Паскаля. Клавиши F2 и F3 помогут Вам в работе с Вашими каталогами и файлами.
Командой ALT+F5 Вы в любой момент сможете просмотреть данные, выданные на экран в результате
прогона программы.
�Оглавлен ие
Текстовый редактор
Текстовый редактор среды Турбо Паскаля предоставляет пользователю удобные средства создания и
редактирования текстов программ. Признаком того, что среда находится в состоянии редактирования,
является наличие в окне редактора курсора – небольшого мигающего прямоугольника. Режим
редактирования автоматически устанавливается сразу после загрузки Турбо Паскаля. Из режима
редактирования можно перейти к любому другому режиму работы Турбо Паскаля с помощью
функциональных клавиш или выбора нужного режима из главного меню. Если среда находится в
состоянии выбора из меню, курсор исчезает, а в строке меню появляется цветной указатель прямоугольник, выделяющий одно из кодовых слов. Для перехода от состояния выбора режима из
главного меню в состояние редактирования нужно нажать клавишу Esc (ESCape – ускользать,
убегать), а для перехода к выбору из главного меню – F10.
Рассмотрим основные приемы работы с текстовым редактором.
Для создания текста программы нужно ввести этот текст с помощью клавиатуры ПК подобно тому, как
это делается при печатании текста на пишущей машинке. После заполнения очередной строки следует
нажать на клавишу Enter, чтобы перевести курсор на следующую строку (курсор всегда показывает то
место на экране, куда помещается очередной вводимый символ программы).
Окно редактора имитирует длинный и достаточно широкий лист бумаги, фрагмент которого виден в
окне. Если курсор достиг нижнего края, осуществляется прокрутка окна редактора: его содержимое
смещается вверх на одну строку и снизу появляется новая строка листа. Если курсор достиг правой
границы экрана, окно начинает по мере ввода символов смещаться вправо, показывая правый край
листа. Размеры листа по горизонтали и вертикали ограничиваются только общим числом символов в
файле, которых не должно быть больше 64535, однако компилятор Турбо Паскаля воспринимает
строки программы длиной не более 126 символов.
Окно можно смещать относительно листа с помощью следующих клавиш:
PgUp – на страницу вверх (PaGe UP – страницу вверх);
PgDn – на страницу вниз (PaGe DowN – страницу вниз);
Ноmе – в начало текущей строки (HOME – домой);
End – в конец текущей строки (END – конец);
Ctrl+PgUp – в начало текста;
Ctrl+PgDn – в конец текста.
Клавишами перевода курсора (эти клавиши помечены соответствующими стрелками и располагаются
в правой части клавиатуры) его можно смещать по экрану. При достижении курсором границ окна оно
смещается на строку или на символ.
Если Вы ошиблись при вводе очередного символа, его можно стереть с помощью клавиши,
обозначенной стрелкой влево (клавиша Backspace располагается над клавишей Enter). Клавиша Del
(от DELete – стирать) стирает символ, на который в данный момент указывает курсор, а команда
Ctrl+Y – всю строку, на которой располагается курсор.
Следует помнить, что редактор Турбо Паскаля вставляет в конце каждой строки невидимый на
экране символ - разделитель. Этот символ вставляется клавишей Enter, а стирается клавишами
Backspace или Del. С помощью вставки/стирания разделителя можно «разрезать»/«склеить» строки.
�Оглавлен ие
Чтобы «разрезать» строку, следует подвести курсор к нужному месту и нажать клавишу Enter, чтобы
«склеить» соседние строки, нужно установить курсор в конец первой строки (для этого удобно
использовать клавишу End) и нажать клавишу Del или установить курсор в начало следующей строки
(клавишей Home) и нажать клавишу Backspace.
Нормальный режим работы редактора – режим вставки, в котором каждый вновь вводимый символ
как бы «раздвигает» текст на экране, смещая вправо остаток строки. Следует учитывать, что
«разрезание» и последующая вставка пропущенных строк возможны только в этом режиме. Редактор
может также работать в режиме наложения новых символов на существующий старый текст: в этом
режиме новый символ заменяет собой тот символ, на который указывает курсор, а остаток строки
справа от курсора не смещается вправо. Для перехода к режиму наложения нужно нажать клавишу Ins
(INSert – вставка), если нажать эту клавишу еще раз, вновь восстановится режим вставки. Признаком
того, в каком режиме работает редактор, является форма курсора: в режиме вставки курсор похож на
мигающий символ подчеркивания, а в режиме наложения он представляет собой крупный мигающий
прямоугольник, заслоняющий символ целиком.
И еще об одной возможности редактора. Обычно редактор работает в режиме автоотступа. В этом
режиме каждая новая строка начинается в той же позиции на экране, что и предыдущая. Режим
автоотступа поддерживает хороший стиль оформления текстов программ: отступы от левого края
выделяют тело условного или составного оператора и делают программу более наглядной. Отказаться
от автоотступа можно командой Ctrl+O I (при нажатой клавише Ctrl нажимается сначала клавиша O,
затем О отпускается и нажимается клавиша I), повторная команда Ctrl+O I восстановит режим
автоотступа.
Ниже перечислены наиболее часто используемые команды текстового редактора Турбо Паскаля.
Смещение курсора
PgUp – на страницу вверх;
PgDn – на страницу вниз;
Ноmе – в начало строки;
Ctrl+PgUp – в начало текста;
Ctrl+PgDn – в конец текста.
Команды редактирования
Backspace – стереть символ слева от курсора;
Del – стереть символ, на который указывает курсор;
Ctrl+Y – стереть строку, на которой располагается курсор;
Enter – вставить новую строку, разрезать старую;
Ctrl+O L – восстановить текущую строку (действует, если курсор не покидал измененную строку).
�Оглавлен ие
Работа с блоком
Ctrl+К В – пометить начало блока;
Ctrl+К К – пометить конец блока;
Ctrl+К H – отменить выделение;
Ctrl+K Y – стереть блок;
Ctrl+К С – копировать блок;
Ctrl+К V – переместить блок;
Ctrl+K W – записать блок в дисковый файл;
Ctrl+K R – прочитать блок из дискового файла;
Ctrl+K P – напечатать блок.
�Оглавлен ие
Основные приёмы работы в среде Турбо Паскаля
Работа с файлами
Прогон и отладка программы
Справочная служба Турбо Паскаля
Практическая работа в среде Турбо Паскаль 7.0
1. Запуск среды
2. Первое знакомство. Основное меню
3. Работа в редакционном окне. Создание программы
4. Сохранение программы.
5. Компиляция программы.
6. Выполнение программы.
7. Отладка программы.
�Оглавлен ие
Работа с файлами
Как уже говорилось, сразу после запуска Турбо Паскаля среда автоматически переходит в режим
редактирования текста, в котором можно подготовить новую программу или исправить
существующую.
Основной формой хранения текстов программ вне среды являются файлы. После завершения работы с
Турбо Паскалем можно сохранить текст новой программы в дисковом файле с тем, чтобы
использовать его в следующий раз. Для обмена данными между дисковыми файлами и редактором
среды предназначены клавиши F2 (запись в файл) и F3 (чтение из файла). Если Вы создаете новую
программу, то среда еще не знает имя того файла, в который Вы захотите поместить текст этой
программы, и поэтому она присваивает тексту стандартное имя NONAME00.PAS (NO NAME – нет
имени). Для сохранения текста программы в файле нужно нажать на клавишу F2. В этот момент среда
проверит имя и, если это – стандартное имя NONAME, спросит, нужно ли его изменять: на экране
появится небольшое окно запроса с надписью в верхней части:
Save file as
(Сохранить в файле с именем)
Ниже надписи располагается поле для ввода имени файла, в котором можно написать любое имя и
нажать клавишу Enter, текст будет сохранен в файле. Если в имени файла опущено расширение, среда
присвоит файлу стандартное расширение *.PAS.
Если завершена работа с Турбо Паскалем (командой Alt+X), но не сохранен текст программы на
диске, на экране появится окно с запросом:
NONAME00.PAS has been modified. Save?
(Файл NONAME00.PAS был изменен. Сохранить?)
В ответ следует нажать Y (Yes – да), если необходимо сохранить текст в файле, или N (No – нет), если
сохранять текст не нужно.
�Оглавлен ие
Прогон и отладка программы
После подготовки текста программы можно попытаться исполнить ее, т.е. откомпилировать
программу, связать ее (если необходимо) с библиотекой стандартных процедур и функций, загрузить в
оперативную память и передать ей управление. Вся эта последовательность действий называется
прогоном программы и реализуется командой Ctrl+F9.
Если в программе нет синтаксических ошибок, то все действия выполняются последовательно одно за
другим, при этом на экране сообщается о количестве строк откомпилированной программы и объеме
доступной оперативной памяти. Перед передачей управления загруженной программе среда очищает
экран (точнее, выводит на экран окно прогона программы), а после завершения работы программы
вновь берет управление компьютером на себя и восстанавливает на экране окно редактора.
Если на каком-либо этапе среда обнаружила ошибку, она прекращает дальнейшие действия,
восстанавливает окно редактора и помещает курсор на ту строку программы, при компиляции или
исполнении которой обнаружена ошибка. При этом в верхней строке редактора появляется
диагностическое сообщение о причине ошибки. Все это позволяет очень быстро отладить программу,
т.е. устранить в ней синтаксические ошибки и добиться правильной ее работы.
Если ошибка возникла на этапе работы программы, простое указание того места, где она обнаружена,
может не дать нужной информации, так как ошибка может явиться следствием неправильной
подготовки данных. Например, если ошибка возникла при извлечении корня из отрицательного числа,
будет указан оператор, в котором осуществлялась сама операция извлечения корня, хотя ясно, что
первопричину ошибки следует искать где-то раньше, там, где соответствующей переменной
присваивается отрицательное значение. В таких ситуациях обычно прибегают к пошаговому
исполнению программы с помощью команд, связанных с клавишами F4, F7 и F8. Пока еще не
накоплен достаточный опыт отладки, можно пользоваться одной клавишей F7, после нажатия на
которую среда осуществит компиляцию, компоновку (связь с библиотекой стандартных процедур и
функций) и загрузку программы, а затем остановит прогон перед исполнением первого оператора.
Строка программы, содержащая этот оператор, будет выделена на экране указателем (цветом). Теперь
каждое новое нажатие на F7 будет вызывать исполнение всех операций, запрограммированных в
текущей строке, и смещение указателя к следующей строке программы. В подозрительном месте
программы можно просмотреть значения нужных Вам переменных или выражений. Для этого можно
действовать следующим образом. Установите курсор в то место текущей строки, где написано имя
интересующей Вас переменной, нажмите Ctrl+F4. На экране откроется диалоговое окно, состоящее из
трех полей. В верхнем поле будет стоять имя переменной. После этого нажмите на клавишу Enter,
чтобы получить в среднем поле текущее значение этой переменной. Если перед командой Ctrl+F4
курсор стоял на пустом участь строки или указывал на другую переменную, верхнее поле также
окажете пустым или будет содержать имя этой другой переменной. В этом случае следует ввести с
помощью клавиатуры интересующее Вас имя в верхнем поле и нажать клавишу Enter. Кстати, таким
образом можно вводить н только имена прослеживаемых переменных, но и выражения с их участием
– среда вычислит и покажет значение этого выражения.
�Оглавлен ие
Справочная служба Турбо Паскаля
Неотъемлемой составной частью среды Турбо Паскаля являете встроенная справочная служба. Если
Вы достаточно хорошо владеет английским языком, у Вас не будет проблем при работе с Турбо
Паскалем в затруднительной ситуации достаточно нажать на клавишу F1 и на экране высветится
необходимая справка. Эта справка зависит от текущего состояния среды (такую справочную службу
называют контекстно-зависимой). Например, если нажать на F1 в момент, когда среда обнаружила
ошибку в программе, в справке будут сообщены дополнительные сведения о причинах появления этой
ошибки и рекомендации по ее устранению.
Существуют четыре способа обращения к справочной службе непосредственно из окна редактора:
F1 – получение контекстно-зависимой справки;
Shift+F1 – выбор справки из списка доступных справочных сообщений
Ctrl+F1 – получение справки о нужной стандартной процедуре функции, о стандартной константе или
переменной;
Alt+F1 – получение предыдущей справки.
При использовании команды Shift+F1 на экране появляется справочное окно, содержащее
упорядоченный по алфавиту список стандартных процедур, функций, констант и переменных, для
которых можно получить справочную информацию. В этот момент клавишами смещения курсоре
следует передвинуть указатель в окне к нужному слову и нажать клавиша Enter, чтобы получить
справку.
Эту же справку можно получить и другим способом: напечатать не экране имя стандартной процедуры
(функции, константы, переменной) или подвести курсор к имеющемуся уже в тексте программы
стандартному имени и нажать Ctrl+F1. Среда проанализирует ближайшее окружение курсора,
выделит стандартное имя и даст нужную справку.
Доступ к справочной службе возможен и через главное меню Турбо Паскаля.
Во многих случаях справка содержит пример небольшой программы, иллюстрирующей
соответствующие возможности Турбо Паскаля, Не торопитесь запоминать или записывать на бумаге
этот текст, его можно «вырезать» из справки и перенести в окно редактора. Для этого после вызова
нужной справки нажмите клавишу Alt и, не отпуская ее, – клавишу с латинской буквой E – на экране
раскроется дополнительное меню . Затем клавишами смещения курсора подведите указатель (светлый
прямоугольник) в меню к строчке Copy examples (копировать примеры) и нажмите клавишу Enter –
текст примера скопируется во внутренний буфер редактора. Для извлечения примера из буфера следует
нажать клавишу Esc, чтобы выйти из справочной службы, подвести курсор к свободной строке в окне
редактора и дать команды Shift+Ins (копирование содержимого буфера в виде блока в текст
программы) и Ctrl+K H (убрать выделение блока цветом).
�Оглавлен ие
Практическая работа в среде Турбо Паскаль 7.0
1. Запуск среды
2. Первое знакомство. Основное меню
3. Работа в редакционном окне. Создание программы
4. Сохранение программы.
5. Компиляция программы.
6. Выполнение программы.
7. Отладка программы.
�Оглавлен ие
1. Запуск среды
Для запуска среды достаточно, находясь в каталоге, содержащем систему Турбо Паскаля (файл
TURBO.EXE), в ответ на подсказку DOS набрать TURBO и нажать клавишу Enter. При этом
запустится программа TURBO.EXE, которая и вызовет среду. Для выхода из среды наберите Alt + X.
�Оглавлен ие
2. Первое знакомство. Основное меню
При входе в интегрированную среду Турбо Паскаля 7.0 на экране появляется окно, в верхней
части которого высвечивается полоса с надписями - заголовками секций меню, перечисляющими
услуги, предоставляемые средой:
File
Edit
Se arch
Run
Compile
De bug
Tools
Options
Window
He lp
Вход в меню осуществляется одновременным нажатием клавиш Alt и клавиши с буквой, выделенной в
заголовке нужной секции меню. Например, для входа в секцию File необходимо нажать Alt–F. Другим
способом входа в меню является нажатие функциональной клавиши F10 с последующим
перемещением в нужную позицию меню с помощью курсора (вправо или влево). Выбранная позиция
меню подсвечивается. При нажатии клавиши Enter подсвеченная секция меню раскрывается в виде
окна, содержащего дальнейшую детализацию меню.
Например, если в меню оказывается подсвеченной секция Edit, то при нажатии клавиши Enter
раскрывается следующее окно:
Undo
Alt+BkSp
Redo
Cut
Shift+Del
Copy
Ctrl+Ins
Paste
Shift+ Ins
Clear
Ctrl+Del
Show clipboard
Комбинации клавиш, указанные справа от названия действия, определяют способ прямого входа в
меню для выполнения указанного действия.
Например, для выполнения действия «Copy» можно, находясь в меню, с помощью курсора «наехать»
на нужную позицию, подсветив ее, и нажать клавишу Enter. Другим способом является использование
клавиш. Не входя в меню, можно выполнить операцию «Copy», нажав клавиши Ctrl+Ins.
Для выхода из меню достаточно нажать клавишу Esc.
�Оглавлен ие
3. Работа в редакционном окне. Создание программы
Нажмите F10, чтобы войти в полосу меню, а затем «наедьте» курсором на позицию File, нажмите
Enter (либо наберите Alt+F). Раскрывается секция меню File:
New
Open
F3
Save
F2
Save as
Save all
Change dir
Print
Printer Setup
Dos shell
Exit
Alt+X
Выберите строку New, нажмите клавишу Enter. На экране раскрывается пустое окно, озаглавленное
NONAME00.PAS. Это имя, данное средой по умолчанию Вашей будущей программе. Если Вы
повторите операцию, раскроется еще одно окно, но уже с именем NONAME01.PAS. Таким образом
можно раскрыть достаточное число редакционных окон. Для переключения окон достаточно,
удерживая нажатой клавишу Alt, нажать клавишу с цифрой – окна пронумерованы. Например, для
возврата в первое окно нужно набрать Alt+1.
Итак, перед Вами пустое окно, в левом верхнем углу которого мигает курсор. При наборе текста с
помощью клавиатуры курсор будет перемещаться. Приступите к вводу текста программы, нажимая
Enter в конце каждой строки:
Program Summa;
Var
A,B,Sum: integer;
Begin
Wtite ('Введите два числа: ');
Readln(A,B);
Sum:= A+B;
Writeln ('Cyммa paвна ', Sum);
Writeln ('Нажмите Enter ');
Readin;
End.
�Оглавлен ие
Примечание. Не забывайте про точку с запятой, а за последним End поставьте точку. Для удаления
ошибочно набранного текста используйте Backspace, а для передвижения внутри окна редактора
используйте клавиши со стрелками.
�Оглавлен ие
4. Сохранение программы.
Для сохранения программы на диске выберите команду Save as из меню File. Турбо Паскаль открывает
диалоговый окно Save File As для переименования файла и сохранения его в другом каталоге
(директории) или на другом диске.
Диалоговое окно содержит входной бокс, список файлов, информационную панель, стандартные
переключатели Ok, Cancel, Help и список предыстории. Переключение между элементами окна
осуществляется клавишей Tab.
Во входном боксе Save file as записывается имя, под которым Вы собираетесь запомнить файл (либо
файловая маска для бокса Files).
В нашем случае надо набрать SUMMA.PAS и нажать Enter. Рассмотрим детальнее остальные
элементы диалогового бокса.
Бокс Files содержит имена файлов в текущем каталоге (директории), в соответствии с маской,
установленной в боксе Save file as.
Например, если в боксе Save file as записано *.PAS, то в боксе Files появятся имена всех файлов
каталога, содержащие расширение .PAS.
Список предыстории добавляет ко входному боксу все имена, которые появлялись в нем во время
последних вызовов диалогового окна. В список предыстории можно войти в том случае, если справа
от входного бокса Save file as видите стрелку «вниз». Для входа в список следует нажать курсор «вниз».
Этот список используется для повторного вхождения в текст, в который Вы уже входили.
Выбор нужного элемента осуществляется курсором, при этом подсвечивается выбранная позиция.
Затем следует нажать клавишу Enter. Выбранное имя файла попадает во входной бокс Save file as.
Если выбор не сделан, для выхода из списка предыстории нажмите клавишу Esc. Информационная
панель отображает путевое имя выбранного файла, его имя, дату, время создания и размер.
Переключатель Оk служит для подтверждения выполненных действий.
Кнопка Cancel отменяет все действия и выводит из диалогового окна.
Кнопка Help выводит окно с подсказкой.
�Оглавлен ие
5. Компиляция программы.
Для компиляции программы выберите опцию Compile в основном меню, для чего нажмите F10, С.
Секция содержит подменю:
Compile
Alt+F9
Make
F9
Build
Destination Memory (Disk)
Primary file …
Clear primary file
Infortation …
Команды меню Compile используются при компиляции и реализации операций Make и Build.
Команда Compile компилирует файл в активном редакционном окне. При компиляции или
выполнении команды Make на экране высвечивается бокс состояния с результатами. После
завершения компиляции или команды Make для ликвидации окна статуса компиляции достаточно
нажать любую клавишу.
При обнаружении ошибки в верхней части редакционного окна появляется сообщение.
Команда Make включает встроенный Project Manager для создания файла .ЕХЕ.
Файлы рекомпилируются в соответствии со следующими правилами:
Если Compile/Primary File содержит в списке первичный файл, он компилируется, в противном
случае компилируется последний файл, загруженный в редактор. Турбо Паскаль проверяет все файлы,
от которых зависит компилируемый файл.
Если исходный файл для данного модуля (Unit) модифицировался после того, как объектный код
(.TPU) файла был создан, модуль перекомпилируется.
Если интерфейс для данного модуля изменен, все другие модули, от него зависящие,
перекомпилируются.
Если модуль использует .OBJ file и он новее, чем .TPU file данного модуля, модуль
перекомпилируется.
Если модуль включает Include file и он новее, чем .TPU file данного модуля, модуль
перекомпилируется.
Команда Build перестраивает все файлы независимо от их новизны. Команда идентична команде
Make, но не является условной (Make перестраивает только файлы, не являющиеся текущими).
Команда Destination Memory (Disk) определяет место запоминания выполняемого кода в памяти или
на диске (как файл .ЕХЕ).
Устанавливая Destination Disk, Вы увеличиваете память, доступную среде для компиляции и отладки
�Оглавлен ие
программы.
При установке Destination Memory при выходе из среды код исчезает.
Замечание. Даже если Destination установлена в память, любые модули, рекомпилированные с
помощью Make или Build, хранят свои обновленные файлы .TPU на диске.
При установке Destination на диск Турбо Паскаль создает файл .ЕХЕ, имя которого выводится из
двух имен следующим образом:
имя первичного файла
или
если не определено первичное имя, то назначается имя файла в активном редакционном окне.
Турбо Паскаль запоминает результирующий .ЕХЕ в том же каталоге, что и исходный файл или в
каталоге, заданном в установке ЕХЕ & TPU Directory меню Options/Directories.
Переустановка команды Destination происходит нажатием клавиши Enter (установка Destination
Memory сменится на Destination Disk и наоборот).
Итак, выполните команду Compile. После начала компиляции в центре экрана появляется окно с
информацией о процессе компиляции. Если во время компиляции не обнаружено ошибок, в этом окне
появится сообщение "Compile successful: Press any key" (компиляция успешна: нажмите любую
клавишу). Окно остается на экране до тех пор, пока Вы не нажмете клавишу.
Как уже было сказано, при обнаружении ошибки, Турбо Паскаль останавливает процесс
компиляции, устанавливает курсор на ошибку в редакционном окне и выдает сообщение об ошибке.
Нажатие любой клавиши убирает сообщение, а нажатие Ctrl+Q W обеспечивает его показ до тех пор,
пока Вы не измените файл или не перекомпилируете его.
Сделав исправления, сохраните обновленный файл и заново скомпилируйте его.
Однако, для запоминания файла на этот раз нет необходимости вызывать диалоговое окно Save as,
достаточно нажать клавишу F2.
�Оглавлен ие
6. Выполнение программы.
Для запуска программы выберите секцию Run в основном меню. Секция содержит подменю:
Run
Ctrl+F9
Step over
F8
Trace into
F7
Go to cursor
F4
Program reset
Ctrl+F2
Parameters …
Команды меню Run позволяют запускать программу на выполнение, начинать и заканчивать сеанс
отладки. Команда Run запускает Вашу программу на выполнение. При этом используются любые
параметры, передаваемые ей командой Run/Parameters.
Если исходный код модифицировался после последней компиляции, компилятор автоматически
сделает Make и свяжет программу.
Если отладка программы Вами не планируется, установите [х] Standalone в диалоговом окне Debugger
меню Options/Debugger до начала компиляции и сборки.
Если программа компилируется с установкой [х] Integrated в диалоговом боксе Debugger,
результирующий исполняемый код будет содержать отладочную информацию, действующую на
команду Run следующим образом:
1. Если Вы не модифицировали исходный код после последней компиляции, команда Run заставляет
Вашу программу выполняться до точки прерывания или до конца, если точки прерывания не
установлены.
2. Если Вы модифицировали исходный код после последней компиляции и:
- если Вы не делаете пошагового прогона программы, компилятор перекомпоновывает Вашу
программу и устанавливает ее для работы с самого начала;
- если Вы уже делаете пошаговый прогон, используя ко-манды меню Run/Step Over или
Run/Trace Into, Турбо Паскаль спрашивает у Вас, хотите ли Вы перестроить программу,
- если Вы отвечаете Yes, компилятор делает Make и Link и устанавливает программу на
работу с самого начала,
- если Вы отвечаете No, Ваша программа выполняется до следующей точки прерывания (или
до конца, если такой точки нет).
Команда Program reset останавливает текущую отладку, освобождает память, занятую программой и
закрывает все файлы, используемые программой.
Команда Go to cursor пускает программу от места останова (подсвеченная строка исходного текста в
редакционном окне) до строки, возле которой установлен курсор. Если курсор находится на строке, не
содержащей выполняемых операторов, Турбо Паскаль высвечивает предупреждение. Эта команда
�Оглавлен ие
может инициировать отладку. Команда не устанавливает постоянной точки прерывания, но позволяет
программе останавливаться на уже установленных постоянных точках, встречающихся до строки,
помеченной курсором. Если это произойдет, необходимо снова воспользоваться командой Go to
cursor. Удобно использовать эту команду для предварительной установки run bar (подсвеченной
строки, на которой остановлена отладка).
Команда Trace into пускает Вашу программу построчно (оператор за оператором). При достижении
процедуры команда начинает пооператорное выполнение процедуры (в отличие от команды Step
Over, выполняющей процедуру за один шаг).
Команда Step Over выполняет следующий оператор в текущей процедуре, не трассируя вызовы
процедур низшего уровня, даже если они доступны отладчику, т.е. ее следует использовать для
пооператорного выполнения текущей процедуры без ухода в другие процедуры.
Команда Parameters выводит диалоговое окно, в котором вводятся аргументы текущей программы
(точно так, как это делается в DOS).
Program Parameters
Parameter
Ok
Cancel
Help
Итак, Вы в меню Run. Выберите команду Run. Вы попадете в окно пользователя, появится сообщение:
Введите два числа:
Наберите два любых целых числа с пробелом между ними и нажмите Enter. Появится следующее
сообщение:
Сумма равна
а за ним – сумма двух чисел. В следующей строке появится сообщение:
Нажмите клавишу Enter
Программа будет ожидать нажатия клавиши Enter. Для наблюдения за выводом из своей программы,
выберите команду User Screen в меню Debug (или нажмите Alt+F5).
�Оглавлен ие
7. Отладка программы.
Продемонстрируем использование интегрированного отладчика, встроенного в среду Турбо
Паскаля 7.0.
Интегрированный отладчик позволяет перемещаться по строкам программы, одновременно наблюдая
за изменением значений переменных.
Для начала сеанса отладки, выберите команду Trace Into меню Run (или нажмите F7). Run bar
(подсвеченная полоса) устанавливается на первой строке (в данном случае Begin).
Первое нажатие клавиши F7 инициализирует сеанс отладки. Теперь нажмите F7, чтобы начать
выполнение программы. Следующая выполнимая строка – оператор Write. Нажмите F7 снова.
Появится экран пользователя. Это произойдет потому, что утверждение Readln ожидает ввода двух
чисел. Наберите два целых числа, разделенные пробелом. Нажмите Enter. Вы вернетесь назад в
редакционное окно, с run bar на операторе присваивания. Нажмите F7 и выполните оператор
присваивания. Теперь полоса запуска находится на операторе Writeln. Нажмите F7 дважды. Теперь Вы
должны выполнить Readln. Нажмите F7, посмотрите вывод своей программы и затем нажмите Enter.
Нажмите F7 и Вы выйдете из программы.
Для того чтобы наблюдать за значениями объявленных переменных, войдите в секцию меню Debug.
Breakpoints
Clear stack
Ctrl+F3
Register
Watch
Output
User screen
Alt+F5
Evaluate/modify …
Ctrl+F4
Add watch
Add breakpoints
Выберите команду Add Watch из нижней части меню.
Команда Add watch помещает наблюдаемое выражение в окно Watches. При выборе Add Watch
отладчик открывает диалоговое окно Add Watch.
Во входном боксе Watch expression высвечивается выражение по умолчанию (то, на которое
указывает курсор в редакционном окне). Для поиска и выбора другого выражения (из числа уже
использовавшихся) можно открыть список предыстории. Если Вы вводите допустимое выражение,
нажав клавишу Enter или задействовав Ok, отладчик добавляет выражение и его текущее значение в
окно Watches.
�Оглавлен ие
Add Watch
Watch Expression
Ok
Cancel
Help
Если окно Watches является активным, для введения нового выражения для наблюдения нужно
нажать клавишу Ins.
Наберите А в окне ввода Watch Expression и нажмите Enter. A появится в окне Watches вместе со
своим текущим значением. Теперь используйте команду Add Watch для добавления В и Sum в окно
Watches.
Выберите Trace Into в секции Run (или нажмите F7) для того, чтобы сделать шаг в своей программе. В
окне Watches появятся А = 0, В = 0, Sum = 0. Когда после ввода чисел Вы нажмете Enter и вернетесь в
редакционное окно, значения А и В изменятся на введенные Вами. После выполнения оператора
вычисления суммы изменится и значение Sum.
Итак, Вы умеете пользоваться средой для основных действий. Легко, но не обольщайтесь.
Профессиональное овладение средой потребует от Вас некоторых дополнительных усилий.
Действительно, меню содержит более 80 команд (мы с Вами рассмотрели только некоторые из них),
большая часть открывает диалоговые окна.
Так, секция Options позволяет провести оптимальную настройку самой среды, секция Edit содержит
команды передачи фрагментов из одного окна в другое либо внутри одного окна. Секция Search
обеспечивает поиск и замену фрагментов. Секция Window позволяет изменять размер окон, а также
способ их выдачи на экран. Наконец, секция Help поможет разобраться во всех тонкостях
использования среды.
�Оглавлен ие
Лабораторная работа № 2
СОСТАВЛЕНИЕ ЛИНЕЙНЫХ ПРОГРАММ
Линейная программа, как правило, составляется для вычисления значения некоторого выражения.
Операция вычисления заданного выражения и запись в память полученного значения выполняются с
помощью оператора присваивания. Оператор присваивания имеет вид
<идентификатор>:= <выражение>;
где идентификатор – имя переменной или функции; знак «:=» – знак операции присваивания (читается
«присвоить»), его не следует путать с операцией отношения «=» (читается «равно»). Оператор
присваивания позволяет заменить текущее значение переменной, стоящей слева, новым значением,
задаваемым выражением, стоящим справа. Например, после выполнения оператора
х:= х + n;
текущее значение переменной х изменится на величину n.
Переменная (или функция) и выражение в операторе присваивания могут быть любого типа, но
обязательно идентичного. Допускается использование переменной типа Real c выражением типа
Integer.
Приведем примеры операторов присваивания:
Start:= 1;
x0:= 0;
sum:= Numb1+ Numb2;
i:= i+ 2;
x1:= (–b+sqrt(b*b–4*а*с))/(2*а);
fun:= false;
arr[2,3]:= m;
Str:= 'Turbo Pascal';
Рассмотрим более подробно понятие выражения. Выражения строятся из операндов (констант,
переменных, функций), знаков операций и круглых скобок. Константы, переменные и функции
должны быть либо описаны в программе, либо иметь стандартные имена (см. табл. 1). Для
вычисления числового значения используются арифметические выражения. При этом возможны
следующие знаки арифметических действий: + (сложение), - (вычитание), * (умножение), / (деление),
DIV (деление целых чисел), MOD (остаток от деления целых чисел).
Порядок выполнения операций в арифметическом выражении определяется их приоритетом:
операции умножения, деления, DIV, MOD выполняются перед операциями сложения и вычитания.
Например, при вычислении выражения 2+3*4 получим результат, равный 14. Операции одинакового
приоритета (*, /, DIV, MOD) и (+, -) выполняются в порядке их написания слева направо. Например,
a/b*с соответствует записи
.
�Оглавлен ие
Выражение, заключенное в скобки, вычисляется в первую очередь. Например, значение выражения
(2+3)*4 равно 20.
Промежуточные результаты вычислений арифметических выражений не должны выходить из
допустимой области значений целых и вещественных чисел. В арифметическом выражении допустимо
присутствие данных вещественного и целого типа. Но не рекомендуется в одном выражении
использовать данные различных типов, это приводит к дополнительным затратам машинного времени
на преобразование типов и возможны потери в точности. Если один из операндов операций
сложения, вычитания или умножения вещественный, а второй – целый, то последний перед
выполнением операции автоматически преобразуется к вещественному типу и результат будет
вещественным числом. При выполнении операции деления оба операнда, если они целые,
преобразуются к вещественному типу, результат операции всегда – вещественное число. Например,
при вычислении выражения 2/5 результат равен 0.4 (вещественный). Следовательно, результат
выражения будет целым числом, если все операнды в нем целого типа и операция деления
отсутствует. Для иллюстрации сказанного рассмотрим выражение
(6 + 4) * (1 + 0.1).
Сначала вычисляется выражение в первой скобке, т.е. 6 + 4 = 10 (целое). Во вторых скобках
величина 0.1 является вещественной, поэтому перед сложением другой операнд преобразуется к
вещественному типу 1.0. В результате получим 1.0 + 0.1 = 1.1 (вещественное). В операции
умножения теперь участвует целый операнд 10 и вещественный 1.1, целый операнд преобразуется в
вещественный, в результате имеем
10.0 * 1.1 = 11.0 (вещественное). Результат имеет вещественный тип, хотя в данном выражении
дробная часть равна нулю. В примере используются числа, однако все сказанное справедливо и в
случае использования переменных, имеющих те же значения.
Приведем пример записи на языке Turbo Pascal выражения вида
.
Программная запись будет иметь вид:
(а + 12.55 * b)/(c2 – 1.87Е3) + GAMMA.
В качестве операнда в выражении, кроме констант и переменных, можно использовать стандартные
функции. Аргументы функций обязательно заключаются в круглые скобки. В качестве аргументов
можно употреблять константы, переменные и выражения. Приоритет вычисления стандартных
функций выше, чем приоритет выполнения арифметических операций. В таблице 1 приведены
арифметические стандартные функции. Например, выражение
имеет следующую программную запись:
exp(abs((2*sin(4*x)+x)/(3*sqr(x)))).
Для возведения переменной х в некоторую степень а, т.е. нахождения , используется известное
равенство
.
�Оглавлен ие
Тогда выражение на языке Pascal должно быть записано в виде:
ехр(а*ln(х)).
Для вычисления loga b и lg b используют известные соотношения
log a b
ln b
ln b
; lg b
0, 4343 ln b
ln a
ln10
Таблица 1
Функция
Назначение
Тип аргум.
Тип результ.
abs(х)
абсолютное значение аргумента
I, R*
I, R
arctan(x)
арктангенс аргумента
R
R
cos(x)
косинус аргумента
R
R
exp(х)
ех
R
R
In(х)
натуральный логарифм
R
R
sin(x)
Синус аргумента
R
R
sqr(х)
квадрат аргумента
I, R
I, R
R
R
-
-
sqrt(х)
Pi
= 3.1415926535897932385
frac(x)
дробная часть числа
R
R
int(x)
целая часть числа
R
R
Random
равномерное псевдослучайное число 0 ? i ? 1
R
R
Random(х)
равномерное псевдослучайное число 0 ? i ? x
R
R
Randomize
инициализация датчика псевдослучайных чисел
Составим простейшую линейную программу вычисления площади поверхности и объема круглого
конуса, имеющего радиус основания R=12,54 см и длину образующей L=28,48 см. При вычислении
используем равенства:
,
где Н – высота конуса, определяемая по формуле
.
�Оглавлен ие
Пример 1
Program Conus;
Var
r, l, h, s, v: real;
Begin
write('Введите l='); readln(l);
write('Введите r='); readln(r);
s:= Pi*sqr(r) + Pi*r*l;
h:= sqrt(l*l – r*r);
v:= Pi*sqr(r)*h/3;
writeln('Параметры конуса');
writeln('r=', r, 'l=', l, 'h=', h);
writeln('Поверхность конуса s= ', s);
writeln('Объем конуса v= ', v);
readln;
End.
B программе используется предопределенная константа Pi (
). Начинается программа
с описания переменных. В операторной части программы (после Begin) следуют процедуры ввода
(read, readln) и вывода (write, writeln). Процедура read позволяет присвоить переменным r и l
введенные с клавиатуры числовые значения. В первом операторе присваивания вычисляется значение
переменной S – полной поверхности конуса, во втором – высота конуса (используется стандартная
функция извлечения квадратного корня sqrt); в третьем – объем конуса. Далее следуют процедуры
вывода на печать текстов, заключенных в апострофы, и значений переменных R, L, Н. Для печати
значений переменных в процедуре writeln указываются их имена, заключенные в апострофы. Конец
программы обозначается служебным словом End, после которого ставится точка (End.).
В языке Turbo Pascal отсутствуют операторы ввода–вывода. Их роль играют процедуры Read,
Readln, Write, Writeln, работа которых базируется на устройствах MS–DOS.
Процедура чтения Read обеспечивает ввод числовых данных, символов, строк для последующей их
обработки операторами программы. Ее формат:
Read (FV, х1, x2, ..., хn);
где FV – имя устройства, откуда вводятся данные; х1, ..., хn – список идентификаторов вводимых
переменных. По умолчанию FV равно CON (консоль), поэтому при вводе данных с клавиатуры FV
можно не указывать.
Например:
Read(х,у);
{Вводятся значения переменных х и у}
Read(А);
{Вводится значение переменной А}
�Оглавлен ие
Вводимые значения набираются на клавиатуре минимум через один пробел и высвечиваются на
экране. После набора данных для одной процедуры Read нажимается клавиша ввода (Enter).
Единственным отличием процедуры Readln от процедуры Read является то, что после считывания
значений всех переменных для одной процедуры Readln данные для следующей процедуры Readln
будут считываться с начала новой строки.
В процедурах Read и Readln параметры можно не указывать:
Read;
Readln;
В обоих случаях вводится и отражается на экране произвольная строка символов. Ввод прекращается
нажатием <Enter>.
Процедура вывода Write производит вывод числовых данных, символов, строк и булевских
значений. Формат:
Write(FV, y1, y2, ..., yn);
где FV – имя устройства, на которое осуществляется вывод.
По умолчанию FV равно CON (при выводе CON – экран); у1 , у2 , ..., уn – выражения,
результаты выполнения которых выводятся на экран, константы, имена переменных.
Процедура Writeln аналогична процедуре Write, но после выполнения происходит переход в
начало следующей строки.
Например:
Write(55+66);
Write('Сумма 5 + 6 = ',5 + 6);
Writeln(x, y, Sum);
Форматированный вывод. В процедурах вывода на экран имеется возможность указать константу (или
выражение), определяющую ширину поля вывода. Это значение указывается через двоеточие сразу
после имени выводимой единицы:
Write(55+55:10,22:6);
{результат:.......110....22}
(под число 110 отводится поле в десять позиций, под число 22 – в шесть).
Вещественные значения могут выводиться в форматах как с плавающей точкой, так и фиксированной
точкой. В первом случае указывается только ширина поля, во втором дополнительно фиксируется
количество символов в дробной части.
Например:
Write(655.04:15)
{результат: 6.550400000Е+02}
Write(655.04:8:4)
{результат: 655.0400}
Форматированный вывод позволяет оформлять выводимые данные в таблицы.
I – integer (целый); R – real (вещественный).
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Составьте программы на языке Turbo Pascal для вычислений по формулам:
1)
;
2)
;
;
3)
4)
;
5)
6)
;
;
;
7)
;
8)
9)
;
10)
;
11)
;
12)
13)
14)
15)
16)
17)
18)
�Оглавлен ие
19)
20)
21)
22)
23)
24)
25)
26)
27)
28)
29)
30)
2. Вычислить значения выражений:
1)
3)
5)
7)
9)
11)
13)
15)
17)
19)
21)
23)
25)
27)
29)
20 div 6;
29 div 3;
44 div 9;
33 div 5;
3 div 7;
1 div 4;
12 div 5;
22 div 6;
19 div 4;
21 div 5
23 div 7;
25 div 9;
27 div 11;
29 div 13;
31 div 17;
20
29
44
33
3
1
12
22
19
20
19
21
23
25
27
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
6;
3;
9;
5;
7;
4;
5;
6;
4;
7
6;
8;
9;
11;
13;
2)
4)
6)
8)
10)
12)
14)
16)
18)
20)
22)
24)
26)
28)
30)
25 div 7;
17 div 4;
99 div 5;
15 div 9;
5 div 8;
1 div 2;
2 div 5;
6 div 9;
3 div 7;
7 div 9
9 div 11;
11 div 13;
13 div 15;
15 div 17;
17 div 19;
25
17
99
15
5
1
2
6
3
5
7
9
11
13
15
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
mod
7;
4;
5;
9;
8;
2;
5;
9;
7;
9;
11;
13;
15;
19;
21.
�3. Вычислить значения выражений:
1) – a mod b + a div be;
2)
3) – ab div b mod c;
4)
5) c – b div (a + b) mod c;
6)
7) a mod be + a div c;
8)
9) kn div a mod c;
10)
11) – ab mod cbc div a;
12)
13) k mod abc – c div ab;
14)
15) (k + b) mod kb div a + c;
16)
17) ab div cb mod abc;
18)
19) k div abc + ab mod kc;
20)
21) a mod b div c mod a;
22)
23) k mod (ab)c – c div a mod b;
24) b div ab mod c + b + c mod a;
25) k mod n + c + (a – b) div k;
26) (ab) mod (a + b) + ab mod cb;
27) (a + b) mod ab – a mod b div c;
28) k mod na – (k + a) div (b + k);
29) a mod b + c + (a + b) div ka;
30) a + b mod c + (a + b) div c.
Оглавлен ие
a mod b + ac div c
k mod n – k div c – 1;
a div be mod (ab);
ab mod ca div ba;
a + b div (ab) + a mod b;
a mod b – (b – a) div cb;
kab div kab + a mod kb;
a mod (a + b) c div ab;
a + b mod kc + k div ab;
nk div n – kn mod k + a;
a – b mod ca + ca div b;
�Оглавлен ие
Лабораторная работа № 3
ТИПЫ ДАННЫХ. ФУНКЦИИ ПРЕОБРАЗОВАНИЯ ТИПА
Любая константа, переменная, значение функции или выражения в Turbo Pascal характеризуется
своим типом. Тип любого из этих объектов определяет множество допустимых значений, которые
может иметь объект, а также множество допустимых операций, которые применимы к объекту. Turbo
Pascal характеризуется разветвленной структурой типов данных (рис.1).
Рис.1. Структура типов данных
Среди типов, используемых в языке, есть стандартные (предопределенные) типы и типы,
определяемые программистом.
Стандартные типы не требуют предварительного определения. Все другие типы должны быть
определены либо в разделе объявления типов, либо в разделе объявления переменных. В данной
работе будут описаны только простые типы данных.
Все простые типы, за исключением вещественных, называются порядковыми типами.
Для величин порядковых типов определены три стандартные функции: Odd, Pred, Succ.
Функция Odd(х) проверяет величину х на нечетность. Аргументом функции является величина типа
Longint*, результат равен True, если аргумент нечетный, и False – если четный.
Функция Pred(х) определяет предыдущее значение рассматриваемой величины (например, Pred(2)
равно 1).
Функция Succ(х) определяет последующее значение рассматриваемой величины (например,
Succ(2) равно 3).
�Оглавлен ие
Функцию Pred(х) нельзя применять к первому элементу последовательности, а функцию Succ(х) –
к последнему.
Целые типы. В Turbo Pascal имеется пять стандартных целых типов: Shortint, Integer,
Longint, Byte, Word. Характеристика типов приведена в таблице 1.
Таблица 1
Тип
Диапазон
Формат
Shortint
–128..128
8–битовый знаковый
Integer
–32768..32767
16–битовый знаковый
Longint
–2147483648..2147483647
32–битовый знаковый
Byte
0..255
8–битовый беззнаковый
Word
0..65535
16–битовый беззнаковый
Над целыми числами определены операции: *, +, –, div, mod. При использовании процедур и
функций с целочисленными параметрами следует руководствоваться «вложенностью» типов, т.е.
везде, где может использоваться Word, допускается использование Byte (но не наоборот). В Longint
«входит» Integer, который, в свою очередь, включает в себя Shortint.
В таблице 2 содержится перечень встроенных процедур и функций, применимых к целочисленным
типам:
Таблица 2
Обращение
Тип результата
Действие
abs(х)
х
возвращает модуль х
chr(b)
char
возвращает символ, код которого равен b
dec(vx[,i])
как у vx
уменьшает значение vx на i,при отсутствии i – на 1
inc(vx[,i])
как у vx
увеличивает значение vx на i, при отсутствии i – на 1
odd(i)
boolean
возвращает True, если аргумент нечетное число; False, если четное
random
real
возвращает псевдослучайное число, равномерно распределенное на
интервале 0 ≤ x <1
random(n)
integer
возвращает псевдослучайное число, равномерно распределенное на
интервале 0 ≤ x < n
sqr (х)
как у параметра
возвращает квадрат аргумента
где b, w, i, l – обозначения соответственно типа Byte, Word, Integer, Longint; х – выражения
любого из этих типов; vx – переменная; в квадратных скобках указан необязательный параметр.
При использовании разных целых типов в одном выражении они приводятся к базовому типу.
Например, при использовании Integer и Shortint базовым будет тип Integer.
�Оглавлен ие
Логический тип. Стандартный логический тип Boolean представляет такой тип данных, когда
параметр может принимать два значения True и False. При этом справедливы следующие условия:
false < true;
ord(false) = 0;
ord(true) = 1;
succ(false) = true;
pred(true) = false.
Литерный (символьный) тип. Значением символьного типа Char является множество всех символов
ПЭВМ. Каждому символу ПЭВМ предписывается целое число в диапазоне 0..255. Это число есть код
внутреннего представления символа, его возвращает функция Ord. Для кодировки используется код
ASCII (American Standard Code for Information Interchange). Первая половина символов с кодами 0..127
соответствует стандарту ASCII. Вторая половина символов с кодами 128..255 не ограничена жесткими
рамками стандарта и может меняться на ПЭВМ разного типа. Во второй половине хранятся символы
национальных алфавитов, в том числе и русского языка. Символы с кодами 0..31 относятся к
служебным кодам.
К типу Char применима встроенная функция Chr(b), которая преобразует выражение типа Byte в
символ и возвращает последний в качестве своего значения.
Перечисляемый тип. Перечисляемый тип определяется набором идентификаторов, с которыми могут
совпадать значения параметров. Список идентификаторов указывается в круглых скобках,
идентификаторы разделяются запятыми. Объявление типа должно быть сделано в разделе объявлений,
и ему должно предшествовать кодовое слово Type. Между значениями перечисляемого типа и
порядковыми номерами этих значений устанавливается следующее соотношение: первое значение в
списке получает порядковый номер 0, второе – 1 и т.д. Максимальная мощность перечисляемого типа
– 256 значений.
Пример 1
Type
Operaс=(plus,minus,mult,divide);
Color=(black,white,blue,green,yellow,red,grey);
Month=(jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec);
Логический и литерный типы являются частными случаями перечисляемого типа, например:
Type
Boolean = (false, true);
Тип–диапазон. В любом порядковом типе можно выделить подмножество значений, определяемое
минимальным и максимальным значениями. Такое подмножество определяет тип–диапазон.
Объявление типа должно быть сделано в разделе объявлений типов.
�Оглавлен ие
Пример 2
Type
Digit = –100..100;
Day = 1..31;
Ch = 'a'..'z';
Как видно из примеров, границы типа–диапазона разделяются специальным символом – двумя
последовательными точками (в отличие от принятого троеточия).
Вещественные типы. В Turbo Pascal имеется пять стандартных вещественных типов: Real,
Single, Double, Extended, Соmр. Характеристики этих типов приведены в таблице 3.
Таблица 3
Тип
Диапазон
Число значащих цифр
Размер в байтах
Real
2.9*10 – 39..1.7*1038
11 – 12
6
Single
1.5*10 – 45..3.4*1038
7–8
4
Double
5.0*10 –324..1.7*10308
15 – 16
8
Extended
3.4*10 – 4951..1.1*104932
19–20
10
Comp
–263 + 1..263– 1
19–20
8
Тип Comp фактически является типом целых чисел увеличенного диапазона, однако порядковым
типом не является.
Доступ к типам Single, Double и Extended возможен только при особых режимах компиляции.
Эти типы рассчитаны на аппаратную поддержку арифметики с плавающей точкой и для их
эффективного использования в состав ПЭВМ должен входить арифметический сопроцессор, что требует
настройки компилятора.
Тип Real, который используют, не задумываясь, многие программисты при разработке
вычислительных программ на Turbo Pascal, самый медленный из всех вещественных типов.
Для работы с вещественными данными могут использоваться встроенные математические функции
abs(х), arctan(x), cos(х), sin(х), exp(х), In(х), random, sqr(х), sqrt(х), а также
функции fгас(х) и int(x).
Функция fгас(х) выделяет дробную часть х, а функция int(x) – целую часть х, где х – выражение
любого вещественного типа. Результат имеет тип и знак аргумента. Например,
frac(3.14159) возвращает 0.14159,
int(3.14159) возвращает 3.0
Функции преобразования типа. Эти функции предназначены для преобразования типов величин,
например, символа в целое число, вещественного числа – в целое и т.д. К ним относятся следующие
функции.
Chr(х) – преобразование ASCII–кода в символ. Аргумент функции должен быть целого типа в
�Оглавлен ие
диапазоне (0..255). Результатом является символ, соответствующий данному коду.
Ord(х) – преобразование любого порядкового типа в целый тип. Аргументом функции может быть
величина любого порядкового типа (логический, литерный, перечисляемый). Результатом является
величина типа Longint.
Round(х) – округление вещественного числа до ближайшего целого. Аргумент функции – величина
вещественного типа, а результат – округленная до ближайшего целого величина типа Longint.
Trunc(х) – получение целой части вещественного числа. Аргумент функции – величина
вещественного типа, а результат – целая часть этого числа. Тип результата Longint.
Пример 3
х:= 21.53;
trunc(x) = 21,
round(x) = 22;
х:= –2.7;
trunc(x) = –2,
round(x) = –3.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Определить тип (целый или вещественный) выражения:
1) 1 + 0.0;
4) sqr(5.0);
7) succ(–2);
2) 20/4;
5) sqrt(16);
8) trunc(–3.14);
3) sqr(4);
6) sin(0);
9) round(6.88).
2. Чему равно?
1) trunc(5.61);
6) round (–17.96);
2) trunc (–5.61);
7) frac(Pi);
3) round(17.16);
8) frac(–Pi);
4) round(17.96);
9) int(Pi);
5) round(–17.16);
10) int(–Pi).
Проверить правильность ответов, составив соответствующую программу.
3. Чему равно?
1) chr(65);
6) ord('''');
2) chr(97);
7) ord(chr(49));
3) ord('A');
8) chr(ord('*'));
4) ord('a');
9) pred('B');
5) chr(7);
10) succ('B').
4. Вычислить значения выражений:
1) succ(round(a/b)) – pred(n);
2) ord('z') – ord('a') + 1.
5. Дано действительное число х. Получить целую часть числа х, затем число х, округленное до
ближайшего целого, затем х без дробных цифр.
6. Используя типы Color и Month (пример 1), определить порядковые номера значений green,
black, mar, dec, а также succ(nov) и pred(feb).
7. Используя типы Day и Ch (пример 2), определить порядковые номера значений 'a', 'z', 1, 31.
8. Составить программу "датчик случайных чисел", генерирующую случайное число в диапазоне 0 ≤
i < 1 и 0 ≤ i < n, а также в диапазоне a ≤ i ≤ b.
9. Составить программу, проверяющую на четность вводимое число.
�Оглавлен ие
Лабораторная работа № 4
ОПЕРАЦИИ ОТНОШЕНИЙ. ЛОГИЧЕСКИЕ ОПЕРАЦИИ
Операции отношений предназначены для сравнения двух разных величин (величины должны быть сравнимых
типов). Результат сравнения имеет логический (Boolean) тип (Табл. 1). Все операции обладают одним и тем
же приоритетом. Каждая из операций должна соединять два операнда.
Операнды этих операций (константы, переменные, функции, выражения, не содержащие отношений) могут быть
вещественного, целого или логического (булевского) типа. Результат операции отношения равен True, если
отношение удовлетворяется для значений входящих в него операндов, и False – в противном случае.
Указанные два слова являются единственно возможной парой значений стандартного типа Boolean.
Таблица 1
Операции отношений
Операция
Действие
Выражение
Результат
=
Равно
А=В
True, если А равно В
<>
не равно
А <> В
True, если А не равно В
>
Больше
А>В
True, если А больше В
<
Меньше
А<В
True, если А меньше В
>=
больше или равно
А >= В
True, если А больше или
равно В
<=
меньше или равно
А <= В
True, если А меньше или
равно В
Например, значение 5 < 2 есть False (ложно), а 0 <= 15 – True (истинно). В сравнении с
арифметическими операциями (*, /, div, mod, +, –) операции отношений имеют меньший приоритет
(см. табл. 2), т.е., например, значение отношения 2*5 <= 17 div 3 есть False, а отношения 7+3>16 –
4*3 – True.
Следует помнить, что к операндам вещественного типа не следует применять операцию отношения «=» (равно),
условие может не выполняться за счет неточного представления действительных чисел в памяти ЭВМ и
неизбежных ошибок округления при вычислении выражений вещественного типа. Поэтому отношение а1 = а2
следует заменить отношением abs (a1 – а2) < е, где е – некоторая малая величина, характеризующая
допустимую погрешность округления.
Таблица 2
Приоритет операций
Приоритет
Тип операций
Операции
1
Унарные операции
Not
2
Операции типа умножения
*, /, Div, Mod, And
3
Операции типа сложения
+, *, Or, Xor
4
Операции отношений
=, 0, <, >, <=, >=
Turbo
Pascal
Логические операции. Помимо операций отношения в языке
существуют 4 логических
операции, применимые только к операндам целого и логического типа. Если операнды – целые числа, то
результат логической операции тоже целое число. Логические операции над логическими данными дают
результат логического (Boolean) типа.
Имеется одна унарная операция Not (исключение) и три бинарных операции And (и), Or (или), Xor
(исключающее или) (Табл. 3).
�Оглавлен ие
В Turbo Pascal булевское выражение – это выражение типа Boolean, т.е. такое, вычисление которого
дает один из двух результатов: True (истина) и False (ложь). Элементами булевских выражений могут быть
булевские константы (True или False), переменные и опять-таки выражения.
Рассмотрим пример:
Var
х, у, z: real;
b: Boolean;
x:= 4; у:= 0; z:= 1;
b:= (x<у–1) or (у+z>=x) and (z<>0);
В этом примере присутствуют две булевские операции – And и Or. Операция And, как более приоритетная,
выполняется первой. Операндами And служат два булевских выражения (у+z>=x) и (z<>0). Первое дает
False, второе – True. Следовательно, результатом операции And будет False. Затем выполняется Or с
операндами (x<у*1) и False. И то и другое равно False, поэтому операция Or дает False.
Таблица 3
Логические операции
Операция
Действие
Выражение
Not
Логическое
отрицание
Not A
And
Or
Xor
Логическое и
Логическое или
Исключающее
или
A and В
A or В
А xor В
А
В
Результат
True
False
False
True
True
True
True
True
False
False
False
True
False
False
False
False
True
True
True
True
False
True
False
True
True
False
False
False
True
True
False
True
False
True
False
True
True
False
False
False
Поскольку логические операции имеют более высокий приоритет, чем операции отношения, в сложных
логических выражениях необходимо расставлять скобки. Если, например, A, В, C и D имеют тип Integer,
�Оглавлен ие
то выражение
А = В and С < D
вызовет сообщение об ошибке. Правильным будет выражение
(А = В) and (C < D).
С помощью скобок можно изменить порядок вычислений. Например, выражение
1
6
4
2
5
3
(–3>=5) or not (7<9) and (0<=3)
имеет значение False. Цифрами вверху показан порядок выполнения операций: результат выполнения
операции 1 – False, операции 2 – True, операции 3 – True, операции 4 – False, операции 5 – False,
операции 6 – False.
Следует иметь в виду, эти две логические операции могут быть записаны подряд, если второй из них является
операция Not, например:
x1 and not x2.
В языке программирования Turbo Pascal нельзя записать двустороннее неравенство 1 < x < 2. Вместо
этого необходимо воспользоваться логическим выражением (x > 1) and (x < 2).
Нельзя также записать x = у = z. Такой же смысл имеет логическое выражение (x = у) and (x =
z). Если необходимо написать условие, заключающееся в том, что x лежит в диапазоне от –2 до + 2, его
можно записать в виде
not((х<–2) and (х>2)) или (х >=–2) and (x<=2).
Более сложным является условие, которое истинно, если точка лежит внутри единичного круга с центром в
начале координат
sqr(x)+ sqr(y) < 1.
Приме р 1. Определить принадлежность некоторого действительного числа х одному из двух отрезков [а,
b] или [c, d]. Если х принадлежит одному из этих отрезков, то переменной q присвоить значение True. в
противном случае – False.
Program Primer1;
Var
a, b, c, d, x: real;
q: Boolean;
Begin
write ('Введите x, a, b, c, d ==>');
readln (x, a, b, c, d);
q:=(a<=x) and (x<=b) or (c<=x) and (x<=d);
writeln ('Число принадлежит* ', q);
End.
Приме р 2. Составить программу, позволяющую определить, находится ли точка с произвольно заданными
�Оглавлен ие
координатами в заштрихованной области. Если точка принадлежит заштрихованной области, то переменной q
присвоить значение True, в противном случае – False.
Program Primer2;
Var
x,y: real;
q,b: Boolean;
Begin
write('Введите x,y ==>'); readln(x,y);
b:=(sqr(x)+sqr(y)<=1) and (abs(x)+abs(y)>=1);
q:=((x<0) and b) or ((x>=0) and not b));
writeln ('Точка принадлежит* ', q);
End.
Приме чание
В Turbo Pascal имеются два вида вычисления логических выражений: полное вычисление и
укороченное вычисление. Полное вычисление означает, что вычисляется каждый операнд, даже если
известен результат всего выражения. Предположим, что дано выражение A and В, где А и В – некоторые
логические выражения (операнды). При полном вычислении в любом случае вычисляются и значения А, и
значения В, а уж затем формируется значение всего выражения. При укороченном вычислении, если
величина А = False, выражение В не вычисляется, т.к. его значение не влияет на результат, который в
любом случае будет False.
Выбор вида вычисления осуществляется с помощью директивы компилятора $В. В случае директивы
{$В–} (этот вариант выбирается по умолчанию) производится укороченное вычисление. В случае
директивы {$В+} производится полное вычисление.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Вычислить значения выражений:
1) k mod 7 = k div 5 – 1
при k = 15;
2) odd(trunc(10•p))
при p = 0.182;
3) not odd(n)
при n = 0;
4) (x•y <> 0) and (y > x)
при x = 2; y = 1;
5) (x•y <> 0) or (y > x)
при x = 2; y = 1;
6) (a < b) and (x + a < b) or (с < m) or e
x = 8.7; e = true;
при a = 2.5; b = 7.8; с = 17.3; m = 5;
7) (a < 3) and (b = a+ 6) or not (c = 4)
при a=2; b=8; c=5;
8) t and (р mod 3=0)
при t = true; p = 101010;
9) a or (not b)
при а = false; b = true;
10) (2–a > b) or not (c = b) and (d – 1 <= e)
при a = 2; b = 4; c = 7; d = 4; e = 3;
11) not ((a = b) and (c2 <= 100) or (d <> e div 8))
при a = 6; b = 7; с = 3; d = 2; e = 16;
12) not (a = b) and (c2 <= 100) or (d <> e div 8)
при a=1; b=18; c=6; d=42; e=8
13) p and q or r
при p = true; q = true; r = false;
14) p and q or r
при p = true; q = false; r = true;
15) p and q or r
при p = false; q = false; r = false;
2. Вычислить следующие выражения при а = true, b = false, с = true, p = true, q = false:
1) a or b and not a;
2) (a or b) and not a;
3) not a and b;
4) not (a and b);
5) not (pred(c) = false) or (ord (c) = 1);
6) not a and not b or not c;
7) a and b < a or not b;
8) (ord (succ (false)) > 0) or (ord (false) <0)
9) a and b or not a;
10) (a = c) or (b = c) and (p > q);
11) (pred(q) = b) or (p > q);
12) (a = p) or (p = q) and not p;
13) (a > b) or not p and (b > c);
14) (a = q) and not ((a > b) and (p > q));
15) succ(pred(c = q)) and (ord(p = q)=1));
�Оглавлен ие
16) (a > b) and (p > q) or (a = p);
3. Даны значения переменных: a=10; b=20; t = true; f = false. Какими будут значения
выражений:
1) (t and f) or not (t or f);
2) t or f or (a > b);
3) not (not (not (a < b)));
4) not (a < 15) or not (b < 30);
5) (a < 5) and (b > 5) and (a < 20) and (b < 30);
6) (a < 5) and (b > 5) and (a < 10) and (b < 30);
7) (a < 5) and (b > 5) and (a < 20) or (b < 30);
8) (a < 5) and (b > 5) and (a < 10) or (b < 30);
9) not (pred(t) = false) or (ord(f) <> 1);
10) not (not (a = b));
11) not (not (not (a = b)));
12) (ord(succ (f)) > 0) or (ord(t) =1);
13) (a < 5) and (b > 5) or (a < 20) and (b < 30);
14) (a < 5) and (b > 5) or (a < 10) and (b < 30);
15) (a < 5) and (b > 5) xor (а < 20) and (b < 30);
16) (a < 5) and (b > 5) xor (a < 10) and (b < 30)?
4. Составить программу, позволяющую определить, находится ли точка с произвольно заданными
координатами в заштрихованной области. Если точка принадлежит заштрихованной области, то
переменной q присвоить значение True, в противном случае – False.
1
2
3
4
5
6
7
8
�Оглавлен ие
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
�Оглавлен ие
29
30
31
32
33
34
35
36
37
38
39
40
�Оглавлен ие
Лабораторная работа № 5
УСЛОВНЫЙ И СОСТАВНОЙ ОПЕРАТОРЫ
Условный оператор позволяет выбирать одно из двух действий, причем выбор делается во время выполнения
программы. Существует два вида условного оператора:
1) if B then S1
{если В то S1}
2) if B then S1 else S2
{если В то S1 иначе S2}
где В – выражение булевского типа; S1 и S2 – отдельные операторы или операторы, сгруппированные вместе
при помощи операторных скобок begin .. end. Такой оператор называется составным.
Составной оператор представляет собой группу из произвольного числа операторов, отделенных друг от
друга точкой с запятой и ограниченную операторными скобками begin .. end.
В качестве выражений булевского типа используются отношения. В общем случае отношения – это два
выражения, разделенные одним из знаков =, <>, >=, <=, <, >.
Для условного оператора первого вида, если выражение В принимает значение True, выполняется оператор S1,
стоящий после then. Если же выражение B принимает значение False, то этот оператор не выполняется.
Например:
if x > у then x:= 2.5.
Если значение x > у, то выполнится оператор x:= 2.5 и переменная х примет значение 2.5; если же
значение х <= у, т.е. выражение х > у ложно, то оператор х:= 2.5 не выполнится и значение х не
изменится.
Для условного оператора второго вида, если выражение В принимает значение True, выполняется оператор S1,
стоящий после then, a S2 не выполняется. Если выражение В принимает значение False, то выполняется
оператор S2, стоящий после else, a S1 не выполняется. Например:
if х > у then х:= 2.5 else y:= 0.0.
При этом, если х больше у, т.е. выражение х > у истинно, х присваивается значение 2.5, а у останется без
изменения. Если же значение х <= у, т.е. выражение х > у ложно, то у присваивается значение 0.0, а
значение х не изменится.
Следует помнить, что условный оператор управляет только одним оператором, поэтому, если требуется
произвести более одного действия, необходимо использовать составной оператор. Например, необходимо
присвоить целым переменным значения 1 и 5, если параметр а < 0, и нули в противном случае.
Оператор If запишется следующим образом:
if а < 0 then
begin
х:= 1;
y:= 5
end
else
begin
х:= 0;
�Оглавлен ие
y:= 0
end;
На операторы, стоящие после then и else, не наложены ограничения. Особый интерес представляет случай,
когда эти операторы являются условными. Рассмотрим возможные варианты:
1. В условном операторе первого вида if B1 then S1 оператор S1 может быть условным оператором
первого вида, тогда будем иметь следующую конструкцию:
if B1 then if B2 then S1.
В этом случае оператор определяется однозначно.
В условном операторе первого вида оператор S1 может быть условным оператором второго вида, тогда будем
иметь следующую конструкцию:
if B1 then if B2 then S1 else S2.
B этом случае возникает вопрос: какому then соответствует else? Для обеспечения однозначности в Turbo
Pascal принято соглашение о том. что каждому else соответствует предыдущий свободный then.
2. В условном операторе второго вида If B1 then S1 else S2 в качестве операторов S1 и S2 также
могут использоваться условные операторы как первого, так и второго вида. Рассмотрим следующий случай: S1
– условный оператор первого вида, S2 – не является условным оператором. Будем иметь конструкцию:
if B1 then begin if B2 then S1 end else S2;
Легко видеть, что в этом случае оператор S1 необходимо заключить в операторные скобки. Их отсутствие
привело бы к конструкции, рассмотренной выше. Рассмотрим примеры использования условного оператора.
Приме р 1 . Составить программу вычисления
Program Primer;
Var
х, у: real;
Begin
write('х:= '); readln(х);
if
х <= 0
then y:= 0
else y:= x* x* x;
writeln(y: 6: 2);
readln;
End.
Приме р 2. Даны действительные числа а, b, с (а <> 0). Составить программу, выясняющую,
имеет ли уравнение ах2 + bх + с = 0 действительные корни. Если действительные корни имеются, то найти
их. В противном случае ответом должно служить сообщение, что действительных корней нет.
Program Korni;
Var
�Оглавлен ие
a,b,c,x1,x2,d: real;
Begin
write('a,b,c:= '); readln(a,b,c);
d:= sqr(b)–4*a*c;
if d<0 then writeln('действительных корней нет')
else
begin
d:= sqrt(d);
a:= 2*a;
x1:= (–b+d)/a;
x2:= (–b–d)/a;
writeln('x1 = ',x1: 6: 2,'x2 = ',x2: 6: 2)
end
End.
Приме р 3. Даны действительные числа х, у, z. Составить программу, вычисляющую max(x, y,
z).
Вариант 1.
Program Max;
Var
х, у, z, m: real;
Begin
readln (x, y, z);
if х > у then if х > z then m:= х
else m:= z
else if y > z then m:= y
else m:= z;
writeln ('max = ', m: 6: 3);
readln;
End.
Вариант 2.
Program Max;
Var
х, y, z, m: real;
Begin
�Оглавлен ие
readln (x, y, z);
if (х > y) and (х > z) then m:= х
else if y > z then m:= y
else m:= z;
writeln ('max = ', m: 6: 3);
readln;
End.
Вариант 3.
Program Max;
Var
х, y, z. m: real;
t: boolean;
Begin
readln (x, y, z);
t:= (х > y) and (х > z);
if t then m:= х
else if y > z then m:= y
else m:= z;
writeln ('max = ', m: 6: 3) ;
readln;
End.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Написать программы для вычисления значений функций:
1.
1
3
x 0;
3x 2 , если
f (x )
x
2sin(cos 4 x ), если x 0.
2.
2
x ln(x ), если x 0;
f (x)
3
если x 0.
1 x ,
3.
ln( x 1),
f (x) x
2x
e x e ,
4.
x
x
e e ,
f ( x) 2
sin x,
если
если
x 0;
x 0.
если
x 0;
если
x 0.
5.
если
1.9 x 3,
f ( x)
tg 2 x
cos
x
e
,
если
x 0;
x 0.
6.
4x ,
f ( x ) arctg x,
x
,
4
если
x 1;
если 1 x 1;
если
x 1.
7.
если
x 1;
0,
f ( x ) arcctg x, если 1 x 2;
25 x 2 , если
x 2.
8.
x 2 3x 2, если - 5 x 3;
1
f ( x)
x 3,
если
x 5;
x
3x
x 3.
e x , если
9.
ln( x 2), если 0 x 3;
f ( x ) x 3 x 2 , если
x 3;
x2 ,
3.
если
x
10.
x 3 1,
2
f ( x ) x 7,
lg( x 2 2),
11.
e 2 x x 2 1,
f ( x)
4
x ,
если
x 2;
если
если
2 x 1;
x 1.
если
x 0;
если
x 0.
�Оглавлен ие
12.
x e x ,
f ( x) 2
x sin( x ),
если
x 0;
x 0.
13.
e x 1,
f (x)
x 1,
14.
e x 1 ,
f ( x)
7
2
cos 3 x x ,
если
x 0;
если
x 0.
15.
sin x cos 2 x,
f ( x)
2x
x e ,
если
x 0;
если
x 0.
16.
lg(1 x 2 ),
f ( x ) 1 x 3 x 5,
4,
17.
sin x
,
если
x 1;
x
3
f ( x) x e x,
если - 1 x 1;
lg(x 3 7 x ), если
x 1.
18.
ln( e x 1), если 0 x 3;
f ( x ) 3x 2 2 x 3 , если
x 3;
2x
4
x 0.
e x , если
19.
cos x 1
,
ex
1
f ( x ) ln x 2 ,
x
3x 2 x ,
если
если
x 0;
если
x 0.
если 0 x 5;
если x 5;
если
x 0.
если
x 1;
если 0 x 1;
если
x 0.
20.
x2
, если x 1;
f ( x ) ln x
6
x 1 если x 1;
21.
x x 2 ,
f ( x) 2
x 1,
22.
23.
x 3 sin x,
f ( x)
x 1,
ln( x 2),
f (x)
x
2 cos x 3 ,
если
если
x 0;
x 0.
если
если
если
если
x 0;
x 0.
x 0;
x 0.
�Оглавлен ие
24.
ln( x 2 4),
f ( x) x2
x,
10
25.
cos x
,
x
f ( x) x
e 2 x ,
26.
x,
если
x 0.5;
f ( x ) cos x, если 0 x 0.5;
sin 2 x 2 , если
x 0.
27.
x 2 1, если
x 2;
f ( x ) lg( x 1), если 0 x 2;
x 0.
sin x, если
28.
ln( x 2 ), если
x ;
2
f ( x ) sin x x , если 0 x ;
2
x 0.
x 0.1, если
29.
x 3 1 x 2 , если
x 1;
4 2
f ( x ) x 9, если 0 x 1;
2
x 0.
x 0.1, если
если
x 0;
если
x 0.
если
x 0;
если
x 0.
2. Решить следующие задачи:
1) Даны действительные числа х, у, z. Составить программу, вычисляющую max(2x, y, 4z).
2) Даны действительные числа х, у, z. Составить программу, вычисляющую min(5x, 2y, 3z).
3) Даны действительные числа х, у, z. Составить программу, вычисляющую max(х + у + z,
xyz).
4) Даны действительные числа х, у, z. Составить программу, вычисляющую min2(x + у + z/2,
xyz) + 1.
5) Даны действительные числа х, у, z. Составить программу, вычисляющую min(x2 + у2, у2 +
z2).
6) Даны действительные числа х, у. Составить программу, вычисляющую z = max(х, у) при х
0 и z = min(x, у) при х > 0.
7) Даны действительные числа х, у (х <> у). Меньшее из этих двух чисел заменить их
полусуммой, а большее – их удвоенным произведением.
8) Даны действительные числа х, у, z. Составить программу, меняющую значения переменных так,
чтобы оказалось х у z.
9) Даны действительные числа х, у, z. Составить программу, вычисляющую u = max(x, z)/
min(y, z).
10) Даны действительные числа х, у. Составить программу, вычисляющую z = max(x, y)/
�Оглавлен ие
min(x, y).
11) Даны три действительных числа. Составить программу, выбирающую из них те, которые
принадлежат интервалу [1, 3] или [5, 7].
12) Даны три действительных числа. Составить программу, выводящую их среднее геометрическое,
если все они неотрицательны.
13) Даны три действительных числа. Составить программу, возводящую в квадрат те из них, значения
которых неотрицательны.
14) Даны три действительных положительных числа а, b, с. Составить программу, выясняющую,
существует ли треугольник со сторонами а, b, с.
15) Даны три действительных числа а, b, с. Составить программу, удваивающую эти числа, если
а b с, и заменяющую их абсолютными значениями, если это не так.
16) Из четырех чисел а, b, c и d одно отлично от трех других, равных между собой. Присвоить
номер этого числа переменной n.
17) Даны целые числа а, b, с и d. Составить программу, печатающую те из них, которые делятся на
3.
18) Даны целые числа а, b, с и d. Составить программу, печатающую те из них, которые делятся на
5.
19) Дана упорядоченная тройка чисел х,
наименьшего числа.
у,
z. Составить программу, печатающую номер
20) Дана упорядоченная тройка чисел
наибольшего числа.
у,
z. Составить программу, печатающую номер
х,
21) Дана упорядоченная четверка чисел а, b, c и d. Составить программу, печатающую номера
положительных чисел.
22) Дана упорядоченная четверка чисел а, b, с и d. Составить программу, печатающую номера
отрицательных чисел.
23) Дана четверка чисел а, b, с и d. Составить программу, заменяющую четные числа нулями.
24) Дана четверка чисел а, b, c и d. Составить программу, заменяющую нечетные числа
единицами.
25) Составить программу, находящую из четверки чисел а, b, с и d два таких, произведение
которых максимально.
26) Составить программу, находящую из четверки чисел а, b, с и d два таких, сумма которых
минимальна.
27) Даны три числа а, b и с. Составить программу, заменяющую нулями те из них, произведение
которых больше десяти.
28) Даны три числа а, b, и с. Составить программу, которая находит их произведение, если a>b>c,
их сумму, если a<b и разность (a – b) в остальных случаях.
29) Дана упорядоченная четверка чисел a, b, c и d. Составить программу, печатающую номера тех
чисел, которые больше десяти.
�Оглавлен ие
30) Дана упорядоченная четверка чисел а, b, c и d. Составить программу, печатающую номера тех
чисел, которые делятся на 3.
�Оглавлен ие
Лабораторная работа № 6
ОПЕРАТОР ВЫБОРА
В Turbo Pascal предусмотрен еще один управляющий механизм для выбора одной из нескольких
альтернатив, который иногда оказывается более предпочтительным по сравнению с вложенной конструкцией
If. Оператор выбора (варианта) состоит из ключевого слова Case, после которого идет ключ (параметр)
выбора (селектор), ключевое слово of, список операторов выбора, каждому из которых предшествует метка
(константа) выбора, а после него ключевое слово end. Как и в операторе If, здесь может присутствовать
слово else, имеющее тот же смысл.
Структура этого оператора в Turbo Pascal такова:
Case S of
c1: operator1;
c2: operator2;
...................
cN: operatorN
else
operator
end;
B этой структуре S – выражение типа любого порядкового типа (обычно Integer), значение которого
вычисляется; с1, c2, ..., cN – константы, с которыми сравнивается значение выражения S;
operator1, ..., operatorN – операторы, из которых выполняется тот, с константой которого совпадает
значение выражения S; operator – оператор, который выполняется, если значение выражения S не совпадет
ни с одной из констант c1, ..., cN.
Ветвь оператора else operator является необязательной. Если она отсутствует и значение выражения S не
совпадает ни с одной из перечисленных констант, активизируется оператор, находящийся за словом end, т.е.
первый оператор за границей Case (пример 1). Селектор может иметь любой скалярный тип, кроме
вещественного (пример 3). Селектор может иметь и литерный тип. Его использование рассмотрено в примере 5.
При вводе одного из символов у или Y на экран будет выведено слово «Да», а при вводе n или N – слово
«Нет». Использование строкового типа в качестве селектора запрещено.
Если для нескольких констант нужно выполнить один и тот же оператор, их можно перечислить через запятую
(или даже указать диапазон, если возможно), сопроводив их одним оператором (пример 2, 4). Ниже приведены
типичные форматы записи оператора Case.
Приме р 1. Селектор целочисленного типа:
Case i of
1: y:= i+ 10;
2: y:= i+ 100;
3: y:= i+ 1000
end;
Приме р 2. Селектор интервального типа:
Case i of
�Оглавлен ие
1..10: writeln('число',i:4,'в диапазоне 1-10');
11..20: writeln('число',i:4,'в диапазоне 11-20');
21..30: writeln('число',i:4,'в диапазоне 21-30')
else
writeln ('число',i:4,'вне пределов контроля')
end;
Приме р 3. Селектор перечисляемого типа:
Type
color = (red, blue, black);
Var
х: integer;
clr: color;
Begin
write('Введите х: ', #61#62); readln (х);
Case х of
{ввод значений}
1: clr:= red;
2: clr:= blue;
3: clr:= black
end;
write('color-');
Case clr of
{вывод значений}
red: writeln('red');
blue: writeln('blue');
black: writeln('black')
end
End.
Приме р 4. Селектор для нескольких констант:
Case i of
2, 4, 6, 8: writeln('четная цифра');
1, 3, 5, 7, 9: writeln('нечетная цифра');
10..100: writeln('число от 10 до 100');
else
writeln('отрицательное число или больше 100')
end;
�Оглавлен ие
Приме р 5. Селектор литерного типа (char):
Var
ch: char;
Begin
readln(ch);
Case ch of
'n', 'N': writeln('Нет');
'y', 'Y': writeln('Да')
end
End.
Используя оператор Case, можно организовать ввод и вывод данных перечисляемого типа, минуя ограничения
языка Turbo Pascal (пример 3).
Рассмотрим программу, имитирующую работу микрокалькулятора. Программа вводит две строки: первая
содержит два произвольных числа, разделенных пробелом, вторая – символ арифметического действия,
например:
2
2
18.35 0.12
или
*
/
Программа осуществляет над введенными числами соответствующее действие и выводит на экран
результаты. Признаком конца работы программы служит любой символ, отличный от +, -, *, /.
Приме р 6
Program Calc;
Var
operation: char;
{знак операции}
х, у, z: real;
{операнды и результаты}
stop: boolean;
{признак ошибочной операции останова}
Begin
stop:= false;
repeat
writeln;
{пустая строка – разделитель}
write('х, y:= '); readln(x, y);
writeln('операция: ');
readln(operation);
Case operation of
'+': z:= х + y;
�Оглавлен ие
'–': z:= х – y;
'?': z:= х ? y;
'/': z:= х / y
else
stop:= true
end;
if not stop then writeln('результат z:=', z)
until stop
End.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Составить программу вычисления площадей (площадей полных поверхностей, объемов) различных
геометрических фигур:
ab,
h
a ,
2
h
( a b) ,
s
2
1)
r 2 ,
ab sin ,
,
r 2
360
если n 1,3;
если n 2, 4;
если n 5,7;
если n 6,8;
если n 9,11;
если n 10,12.
2(ab bc ac ),
2rh 2r 2 ,
4r 2 ,
2) s 2
2
R r ( R r)l,
2
rl r ,
r (2h d ),
abc,
1
r 3 h ,
3
4 3
3) s r ,
3 2
r h ,
h ( R 2 Rr r 2 ),
2r 2 h,
если
если
если
если
если
если
k
k
k
k
k
k
1..3;
4..6;
7..9;
10..11;
12..14;
15..17.
если k 1;
если k 2;
если k 3;
если k 4;
если k 5;
если k 6.
2. Используя оператор Case, составить программу вычисления значений функции:
2 3 b ,
2
(b ),
tg(b ) 1 ,
y
1)
b
e b ,
arctg ,
b
1 sin x,
1
(1 cos x),
2
2) y tg x ,
3
2
c tg x,
sin x 2 ,
если b 1;
если b 3;
если b 5;
если b 7;
если b 9.
если 5 x 10;
если 10 x 15;
если 15 x 20;
если 20 x 25;
если 25 x 30.
�Оглавлен ие
ea b ,
lg a ,
b
3) y ( a b)2 c ,
sin 2 ,
2
2
a b ,
a bx cx 2 ,
c
a sin bx ,
a bx 3 c,
4) y
x
a ln b
,
b
2
e a sin x c,
a 4 x ,
sin x cos 2 x,
2
2 x 1,
x e x ,
5) y
cos x,
x 3 c tg 2 x,
2
x 5,
lg( x x 2 ),
2
c bx ax ,
3x ,
6) y
arccos x ,
x 2 b ln x 2 ,
x
2
e bx ,
если k 2;
если k 4;
если k 6;
если k 8;
если k 10;
если 1 x 2;
если 2 x 3;
если 3 x 4;
если 4 x 5;
если 5 x 6;
если 6 x 7.
если 1 x 2;
если 2 x 3;
если 3 x 4;
если 4 x 5;
если 5 x 6;
если 6 x 7.
если 1 x 2;
если 2 x 3;
если 3 x 4;
если 4 x 5;
если 5 x 6;
если 6 x 7.
3.
1) Type Country = (Austria, Bulgaria, Greece, Italy, Norway, France,
Germany);
Capital = (Vena, Sofia, Afiny, Rom, Oslo, Paris, Bonn);
Var St: Country; Stol: Capital;
– по значению переменной St (названию страны) присвоить переменной Stol название столицы этой страны;
– по значению переменной Stol (названию столицы) присвоить переменной St название этой страны;
2) Var Eng: (Ada, Basic, Modula2, Lisp, Pascal, Pl1, Fortran, C);
По Eng – английскому названию языка программирования вывести на экран русское название этого языка
(Ада, Бейсик, Модула2, Лисп, Паскаль, Пл1, Фортран, Си);
3) Type Name = (zero, one, two, three, four, five, six, seven);
�Оглавлен ие
Var d: '0'..'7'; n: Name;
По литере-цифре d присвоить переменной n название этой цифры.
4) Type Country = (Germany, Cuba, Laos, Mexico, Monaco, China, Poland);
Continent = (Asia, America, Europe);
Var St: Country; Con: Continent;
По St – названию страны определить Con – название ее континента.
5) Type Season = (Winter, Spring, Summer, Autumn);
осень}
nov, dec);
{зима, весна, лето,
Month = (jan, feb, mar, apr, may, jun, jul, aug, sep, oct,
Var Mon: Month; Sn: Season;
Определить Sn – сезон, на который приходится месяц Mon.
6) Type Units = (decimeter, kilometer, meter, millimeter, centimeter);
Var х: integer; p: Units;
Значение переменной х, означающее некоторую длину в единицах p, заменить на величину этой же длины в
метрах.
7) Var k: 1..9;
Напечатать значение переменной k римскими цифрами.
dec);
8) Type Month = (jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov,
Var Day: 28..31; Mon: Month;
Переменной Day присвоить количество дней в месяце Mon (год считать не високосным).
9) Для целого числа k от 1 до 99 напечатать фразу «мне k лет», учитывая при этом, что при некоторых
значениях k слово «лет» надо заменить словом «год» или «года».
�Оглавлен ие
Лабораторная работа № 7
ЦИКЛЫ
Циклы (многократно повторяемые действия) могут быть заданы в Turbo Pascal следующим образом:
a) Цикл со счетчиком:
for i:= A to[downto] B do P
где i – переменная типа Integer; А и B – константы или выражения типа Integer; при to значение
i при каждом повторе увеличивается на 1 (при А > В оператор Р не выполняется ни разу); при
downto – уменьшается на 1 (при А < В оператор Р не выполняется ни разу); Р – оператор (тело
цикла), который может быть и составным:
for i:= A to[downto] B do
begin
<операторы>
end;
b) Цикл с завершением по нарушению условия:
while B do P;
где В – условие (при невыполнении условия оператор Р не выполняется ни разу); Р – оператор (тело
цикла), который может быть и составным:
while B do
begin
<операторы>
end;
Выполнение: проверяется условие В, и, если оно удовлетворено, то выполняется Р, а затем вновь
проверяется В и т.д. Как только на очередном шаге окажется, что условие В не удовлетворяется, то
выполнение цикла прекратится.
c) Цикл до выполнения условия (с завершением по достижению условия)
repeat
<операторы>
until <условие>;
Выполнение: выполняются операторы и проверяет условие. Если оно не выполнено, то вновь
выполняются операторы и т.д. При удовлетворении условия выполнение цикла прекратится. В любом
случае операторы выполняются хотя бы раз.
Пример 1. Составить программу вычисления n!.
а)
Program fact1;
�Оглавлен ие
var n, i, p: integer;
Begin
write('n='); readln(n);
p:= 1;
for i:= 1 to n do p:= p?i;
write('n!=', p)
End.
b)
Program fact2;
var n, i, p: integer;
Begin
write('n='); readln(n);
p:= 1;
i:= 0;
while i < n do
begin
p:= p?i; i:= i + 1
end;
write('n!=', p)
End.
c)
Program fact3;
var n, i, p: integer;
Begin
write('n='); readln(n);
p:= 1 ;
i:= 0;
repeat
p:= p?i; i:= i + 1
until i >= n;
write('n!=', p)
End.
Пример 2. Составить программу, печатающую таблицу значений функции у=sqrt(x) на отрезке
[0,3] с шагом 0,3.
�Оглавлен ие
Program t;
var i: integer;
Begin
write('x', ' ': 6);
for i:= 0 to 10 do write(i*0.3: 6: 1);
writeln;
for i:= 1 to 75 do write('-');
writeln;
write('sqrt(x)', ' ');
for i:= 0 to 10 do
write(sqrt(i*0.3): 6: 2)
End.
Таблица будет изображена на экране в виде:
x
0.0
0.3
0.6
0.9
1.2
1.5
1.8
2.1
2.4
2.7
3.0
----------------------------------------------------------------------------------------------sqrt(x) 0.00
0.55
0.77
0.95
1.10
1.22
1.34
1.45
1.55
1.64
1.73
Пример 3. Не используя стандартные функции (за исключением abs), вычислить с точностью до
0.0001 функцию y=f(x). Считать, что требуемая точность достигнута, если очередное слагаемое по
модулю меньше 0.0001, все последующие слагаемые можно уже не учитывать. Привести и
значение функции у, найденное с помощью стандартных функций.
y cos x 1
x2 x4 x6
2! 4! 6!
Program f1;
var x, y, n, u: real;
Begin
write('x='); readln(x);
y:= 1;
{задается начальное значение для суммы}
n:= 1;
{номер слагаемого : y = 1–u1+u2–...}
u:= 1;
repeat
u:= –u*x*x/((2*n – 1)*2*n);
{un = un-1(–x2)/((2n – 1)2n)}
y:= y + u; n:= n + 1
until abs(u) < 0.0001;
write('полученное y=',y:6:2,'стандартное x=', cos(x):6:2)
�Оглавлен ие
End.
Program f2;
var x, y, n, u: real;
Begin
write('x='); readln(x);
y:= 1;
{задается начальное значение для суммы}
n:= 1;
{номер слагаемого : y=1–u1+u2–...}
u:= 1;
while abs(u)>=0.0001 do
begin
y:= y + u;
u:= –u*x*x/((2*n–1)*2*n);
{un =un-1(–x2)/((2n – 1)2n)}
n:= n+1;
end;
write('полученное x=',x:8:4,'стандартное x=',cos(x):8:4)
End.
Пример 4. Дана непустая последовательность положительных вещественных чисел, за которой
следует отрицательное число. Составить программу вычисления среднего арифметического этих
чисел.
Program s1;
var x, s: real; i: integer;
Begin
write('x='); readln(x);
i:= 0; s:= 0;
repeat
s:= s + x;
i:= i + 1;
write('x', i + 1, '='); readln(x);
until x < 0;
write('cp. арифм. =', s/i)
End.
Program s2;
var x, s: real; i: integer;
Begin
�Оглавлен ие
write('x='); readln(x);
i:= 0; s:= 0;
while x >= 0 do
begin
s:= s + x;
i:= i + 1;
write('x', i + 1, '='); readln(x)
end;
write('cp. арифм. =', s/i)
End.
Пример 5. Дано целое n > 0. Составить программу, печатающую все простые числа из диапазона
[2, n].
Program p1;
var n, m, k, p: integer;
Begin
write('n='); readln(n);
for m:= 2 to n do
begin
p:= 0;
for k:= 2 to trunc(sqrt(m)) do
if m mod k = 0 then p:= 1;
if p = 0 then write(m,' ')
end
End.
Program p2;
var n, m, k: integer; t: boolean;
Begin
write ('n='); readln(n);
for m:= 2 to n do
begin
k:= 2;
repeat
t:= m mod k = 0;
k:= k + 1
�Оглавлен ие
until t or (k>= trunc(sqrt(m)));
if not t then write (m, ' ')
end
End.
Недостатком программы р1 является неэкономное использование машинного времени: проверка на
делимость делителем k каждый раз осуществляется во всем диапазоне [2,
m ].
В программе р2 выход из цикла организован с помощью булевой переменной t.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Сформировать таблицу значений функции у = f(x) на отрезке [a, b] с шагом h в виде:
x
0
0.1
1
sin(x)
0.000
0.010
0.841
(y = sin x, a = 0, b = 1, h = 0.1)
1) y = ex
2) y=10x
a=0
a=0
a = 0.2
a=1
b=2
b=2
b = 1.2
b=0
h = 0.2
h = 0.2
h = 0.1
h = 0.1
6) y = ctg x
3) y = sin x
7) y = ln x
8) y = arctg x
4) y = cos x
9) y = arcctg x
a = 0.9
a=1
a=0
a=3
b = 0.1
b=4
b=2
b=1
h = 0.1
h = 0.4
h = 0.2
h = 0.3
2. Вычислить:
100
1
52
1) i 2 ;
i 1
n
i2
2) i 2 2i 3 ;
i 1
2
2n 2);
2
2);
n 1
1 sin kx
;
k
k 1
20
n
6)
n 3
i 1
5) ln(n
k 1
30
1 i2 ;
k
k
4) k 1 cos kx;
8)
n
3) ln
7) ln(i
n2
ln n
;
n
n
k
9) 1 k 3 ;
k 1
3. Не используя стандартные функции (за исключением abs), вычислить с точностью до 0.0001
функцию y=f(x). Считать, что требуемая точность достигнута, если очередное слагаемое по модулю
меньше 0.0001, все последующие слагаемые можно уже не учитывать. Для задач 1) – 6) привести и
значение функции у, найденное с помощью стандартных функций.
x x2
;
1! 2!
1)
y e x 1
2)
y arctg x x
3)
y sin x x
4)
y ln( x 1) x
x3 x5
( x 1);
3 5
x3 x5
;
3! 5!
x2 x3
( x 1);
2
3
�Оглавлен ие
5)
y sh x
e x e x
x3 x5
x ;
2
3! 5!
6)
y ch x
e x e x
x2 x4
1 ;
2
2! 4!
7)
y
8)
y
9)
y e x dx x
sin x
1x3 1x5
dx x
x
3 3! 5 5!
0
( найти
y (1));
sin x
x 1 x3 1 x5
dx
3 7 3! 11 5!
0 2 x
( найти
y (1));
x
x
x
2
0
x3 1 x5 1 x7
3 2! 5 3! 7
( найти
y (1));
4. Приближенно вычислить интегралы, используя метод средних прямоугольников при n =100
b
f ( x )dx h f ( x ) f ( x )
1
2
f ( x ) n,
a
где
h
2
1)
1
2
4)
1
7)
ba
h
, x k a kh .
n
2
dx
2
1 sin x
dx
1 x4
1
;
sin x
0 x dx;
;
2)
5)
8)
2
xdx
1 1 ex ;
1
dx
0 1 x 4 ;
1
2
x
e dx;
0
1
xdx
3)
1 ex
0
1
6)
;
1 x 6 dx;
0
1
sin x
9) 2
0
x
dx ;
7) – 9) – сравнить с результатом предыдущего задания.
5. Вычислить:
1) Сколько членов суммы 1 + 1/2 + 1/3 + ... нужно взять, чтобы результат превысил 4?
2) Сколько членов суммы 1 + 1/4 + 1/9 + ... нужно взять, чтобы результат превысил 1.6?
3) Сколько членов суммы 1+1/2+1/4+1/8+1/16 + ... нужно взять, чтобы результат оказался не менее
1.999?
Числами Фибоначчи называют числа следующей последовательности: 1, 1, 2, 3, 5, 8, ... . Здесь
каждое следующее число равно сумме двух предыдущих.
4) Вычислить двадцатое число Фибоначчи;
5) Вычислить сумму 10 первых чисел Фибоначчи;
6) Найти первое число Фибоначчи, большее m (m > 1);
7) Вычислить сумму всех чисел Фибоначчи, которые не превосходят 1000;
8) Вычислить сумму квадратов всех целых чисел, попадающих в интервал (ln x, ex), x > 1;
�Оглавлен ие
9) Вычислить количество точек с целочисленными координатами, попа-дающих в круг радиуса r (r
> 0) с центром в начале координат.
6. Решить следующие задачи:
1) Дано 15 вещественных чисел. Вычислить разность между максимальным и минимальным из
них.
2) Дана непустая последовательность различных натуральных чисел, за которой следует 0.
Определить порядковый номер наименьшего из них.
3) Даны целое n > 0 и последовательность вещественных чисел, среди которых есть хотя бы одно
отрицательное число. Найти величину наибольшего среди отрицательных чисел этой
последовательности.
4) Дано 12 вещественных чисел. Определить, образуют ли они возрастающую последовательность.
5) Дана последовательность из 14 целых чисел. Определить, со скольких отрицательных чисел она
начинается.
6) Дано 15 вещественных чисел. Найти порядковый номер того из них, которое наиболее близко к
какому-нибудь целому числу.
7) Даны натуральное n и вещественные числа x1, у1, x2, у2, ..., xn, уn. Рассматривая пары xk, уk как
координаты точек на плоскости, определить радиус наименьшего круга (с центром в начале
координат), внутрь которого попадают все эти точки.
8) Дана последовательность различных натуральных чисел, за которой следует 0. Определить два
наибольших числа среди них.
9) Дана последовательность различных натуральных чисел, за которой следует 0. Определить,
сколько из этих чисел больше предыдущего числа.
7) Вычислить:
1)
4)
10
i , j 1
10
k 1
i2
;
j3
2)
20
1
i j
i , j 1
;
2
3)
12
i
i 1 k 1
n!
k
20
n 1
5)
k
sin kn
k!
;
1
k 1;
n 1
n
k 1
;
2
�Оглавлен ие
Лабораторная работа № 8
МАССИВЫ
Массив – это структурированный тип данных, состоящий из фиксированного числа элементов,
имеющих один и тот же тип. Элементами массива могут быть данные любого, но только одного типа,
включая структурированные. Число элементов массива фиксируется при описании и в процессе
выполнения программы не меняется. Доступ к каждому отдельному элементу осуществляется путем
индексирования элементов массива. Индексы представляют собой выражения любого скалярного
типа, кроме вещественного. Тип индекса определяет границы изменения значений индекса.
Для описания массивов используется зарезервированное слово Array of.
Пример описания массивов различной размерности:
Cons t
Min = 10;
Мах = 25;
Type
MassivA = Array [1..100] of Real;
MassivB = Array [1..20, 1..50] of Integer;
MassivС = Array [1..10, 1..20, 1..30] of Char;
Var
a: MassivA;
b: MassivB;
с: MassivC;
Mas: Array [1..Min, 1..Max] of Char;
Как видно из примера, массив может быть описан без представления типа в разделе описания типов
данных. Однако, если использовать описание
Var
a: Array [1..5] of Real;
b: Array [1..5] of Real;
то переменные а и b считаются в Turbo Pascal переменными разных типов. Для обеспечения их
совместимости необходимо объявить их так:
Type
Massiv = Array [1..5] of Real;
Var
a,b: Massiv;
При индексации компонентов (элементов) массива надо соблюдать лишь два требования: во-первых,
диапазон не должен принадлежать типу LongInt, т.е. он обязан «уместиться» максимум в типе Word,
�Оглавлен ие
а, во-вторых, произведение количества компонентов массива, задаваемое диапазоном индексов, на
размер компонента в байтах не может превышать 65520 байт.
В общем случае ничто не обязывает объявлять диапазон индекса числами. В качестве индексов можно
использовать любые перечисляемые типы, как встроенные, так и вводимые. Индексы могут задаваться
по-прежнему диапазоном, а если диапазон соответствует всему типу, то можно вместо него просто
записать имя этого перечисляемого типа:
Type
MonthType = (January, February, March, April, May);
ComplectType = Array [MonthType] of Word;
SpringType = Array [March..May] of Word;
Var
Complect: СompleсtType;
{5 элементов типа Word}
Spring: StringType;
{3 элемента типа Word}
Alpha: Array['A'..'z'] of Char;
{52 символа}
Switch: Array [Boolean] of Byte;
{2 элемента}
Элементы массивов будут индексироваться значениями заданных перечисляемых типов или их
диапазонов: Complect[January] – первый, a Spring[May] – последний элементы в своих
массивах.
При описании многомерных массивов количество измерений формально не ограничено. Каждое
измерение не зависит от остальных, и можно объявлять массивы с разными индексами:
Var
m: Аrrау[–10..0, 'А'..'С', Boolean] of Byte;
Turbo Pascal позволяет записывать индексы не через запятую, а как бы изолированно
m[–3, 'B', True]
эквивалентно m[–3]['В'][True].
Следует помнить, что, если индекс элемента массива задается константой, то скорость обращения к
нему будет максимальной, потому что компилятор в этом случае вычислит расположение элемента
еще на этапе компиляции программы.
Действия над массивами. Для работы с массивом как единым целым используется идентификатор
массива без указания индекса в квадратных скобках. Массив может участвовать только в операциях
отношения «равно», «не равно» и в операторе присваивания. Массивы, участвующие в этих действиях,
должны быть идентичны по структуре, т.е. иметь одинаковые типы индексов и одинаковые типы
компонентов. Например, если массивы а и b описаны как
Var
a, b: Array[1..20] of Real;
то применение к ним допустимых операций даст следующий результат:
�Оглавлен ие
Выражение
Результат
А=В
Равен True, если значение каждого элемента массива А равно соответствующему значению
элемента массива В.
А <> B
Равен True, если хотя бы одно значение элемента массива А не равно значению
соответствующего элемента массива В.
А:= В
Все значения элементов массива В присваиваются соответствующим элементам массива А.
Массив В не меняется.
Действия над элементами массивов. Индексированные элементы массива называются
индексированными переменными и могут быть использованы, как и простые переменные, т.е. они
могут находиться в выражениях в качестве операндов, использоваться в операторах for, while, repeat,
входить в качестве параметров в процедуры read[ln], write[ln].
Инициализация массива заключается в присваивании каждому элементу массива одного и того же
значения соответствующего базового типа. Это можно сделать, записав группу операторов
присваивания. Например,
а[1]:= 0; а[2]:= 0; а[3]:= 0; а[4]:= 0; а[5]:= 0;
Однако гораздо удобнее получить этот же результат, использовав оператор for:
for i:=1 to 5 do a[i]:=0;
Для инициализации двумерного массива используют вложенный оператор for:
for i:= 1 to n do
for j:= 1 to m do
b[i, j]:= 0;
Значения элементам массива можно присваивать с помощью оператора присваивания, как в примере
инициализации, однако чаще всего они вводятся с экрана с помощью процедуры read[ln] c
использованием оператора for:
for i:= 1 to n do
readln(a[i]);
Значения двумерного массива вводятся с помощью вложенного оператора for:
for i:= 1 to n do
for j:= 1 to n do
begin
write('b[', i, ',' , j, ']=');
readln(b[i, j]);
end;
Если значения элементов могут принимать произвольные значения, используют датчик случайных
чисел:
�Оглавлен ие
Randomize;
for i:= 1 to n do
a[i]:= random(100);
{целые числа 1..100}
или для двумерного массива
Randomize;
for i:= 1 to n do
for j:= 1 to m do
b[i, j]:= random(10);
{вещественные числа из диапазона 1..10}
Вывод значений элементов массива выполняется аналогичным образом, но используется процедура
write[ln]:
for i:= 1 to n do
for j:= 1 to m do
writeln('b['i,',', j,']=', b[i, j]:8:4);
Копированием массивов называется присваивание значений всех элементов одного массива всем
соответствующим элементам другого массива. Копирование можно выполнить одним оператором
присваивания:
d:= а;
или с помощью оператора for:
for i:= 1 to n do
d[i]:= a[i];
Поиск в массиве каких-либо элементов, удовлетворяющих некоторым известным условиям,
осуществляют, вводя дополнительную переменную k и используя операторы for и If:
k:= 0;
for i:= 1 to n do
if a[i]:= 0 then k:= k + 1;
Программа определяет число элементов массива а, имеющих нулевое значение. Перестановка
значений элементов массива осуществляется с помощью дополнительной переменной того же типа,
что и базовый тип массива. Например, требуется поменять значения первого и пятого элементов
массива а:
vs:= а[5];
а[5]:= а[1];
а[1]:= vs;
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Составить программу, которая, сформировав с помощью датчика случайных чисел одномерный
массив данных, подсчитывает следующие выражения:
1)
y
x
x1 x2
n ;
n
1 2
2)
y x1x1 x 2 x 2 x nx n ;
3)
y
4)
y x 1 x 2 x 3 x
5)
y x 1x n x 2x n 1 x nx 1 ;
6)
y x1 x 2 n x 2 x 2 n 1 x n x n 1 ;
7)
y x n x n x n 1 x n x n 1 x n 2 x n x 1 ;
8)
y
x 1 x 2 x
n
;
n 1
x n;
x1 x2 x n x2 x n
x n ;
n
n 1
2. В случайной последовательности x1 , x2 , , x3 n каждая тройка чисел описывает координаты центра и
радиус круга. Существует ли изолированный круг, который не пересекается другими?
3. В случайной последовательности x1 , x2 , , x2 n – пары соседних членов х 2k-1 и х 2k, описывают концы
отрезков. Накрывают ли полностью эти отрезки отрезок [х min , х max] ?
4. Даны действительные числа x, y1, y2, ..., y100 (y1 < y2 < ...< y100, y1 < x < y100). Найти натуральное k, при
котором y k 1 x y k .
5. Даны n и
призеров.
a1 , a2 , , a n n 3 ; ai
– результат i–го спортсмена в беге на 100 м. Сформировать тройку
6. Даны n натуральных чисел . Определить и вывести количество членов последовательности:
1) являющихся нечетными числами;
2) кратных 3 и не кратных 5;
3) являющихся квадратами четных чисел;
4) удовлетворяющих условию ak
ak 1 ak 1
;
2
5) удовлетворяющих условию 2k < аk < k!;
6) имеющих четные порядковые номера и являющихся нечетными числами;
7) являющихся удвоенными нечетными числами;
8) при делении на 7 дающих остаток 1, 2 или 5;
9) обладающих тем свойством, что корни уравнения
x 2 3a i 5
действительны и положительны.
�Оглавлен ие
10) Найти количество и сумму тех членов данной последовательности, которые делятся на 5 и не
делятся на 7.
11) Получить произведение членов последовательности, кратных р (р – натуральное).
12) Получить удвоенную сумму всех положительных членов последовательности.
13) Заменить все большие 7 члены последовательности числом 7, подсчитать количество таких
членов.
14) Получить сумму тех чисел данной последовательности, которые кратны 5.
15) Получить сумму тех чисел данной последовательности, которые нечетны и отрицательны.
16) Получить сумму чисел данной последовательности, которые удовлетворяют условию |at| < t2.
7. Даны натуральное n , символы
s1 , s2 , , s n
.
1) подсчитать, сколько раз среди данных символов встречается символ «+» и сколько раз символ
«*»;
2) подсчитать общее число вхождений символов «+», « – », «*» в последовательность.
Преобразовать последовательность, заменив в ней:
3) все восклицательные знаки точками;
4) каждую точку многоточием (т.е. тремя точками);
5) каждую из групп стоящих рядом точек одной точкой;
6) каждую из групп стоящих рядом точек многоточием (т.е. тремя точками).
Среди символов есть двоеточие. Получить все символы, расположенные:
7) до первого двоеточия включительно;
8) после первого двоеточия;
9) между первым и вторым двоеточием.
8. Даны действительные числа
1)
a1 , a n 1 , a 2 , a n 2 , , a n , a 2 n ;
2)
a1 , a2 n , a2 , a2 n 1 , , a n , a n 1 ;
3)
a1 a 2 n ,a 2 a 2 n 1 , ,a n a n 1 ;
4)
a 2 n , a1 , a 2 , , a 2 n 1 ;
5)
an 1 , an 2 , , a 2n , a1 , a 2 , , an ;
6)
a n 1 , a n 2 , , a 2n , a n , a n 1 , , a1 ;
7)
a 2 n , a n 1 , a 2 n 1 , a n , , a n , a1 ;
8)
a1 , a3 , , a2 n 1 , a2 , a4 , , a2 n;
a1 , a2 , , a2 n
. Получить:
�Оглавлен ие
9. C помощью датчика случайных чисел сформировать: в заданиях 1)–3) одномерный массив из N
элементов, в заданиях 4)–10) – двумерный массив N*N и выполнить следующие действия:
1) упорядочить элементы массива по возрастанию (сортировку производить перестановкой
соседних элементов);
2) упорядочить элементы массива по возрастанию (алгоритм сортировки следующий: поиск
наименьшего элемента, помещение его на первое место; поиск наименьшего элемента из
оставшихся и помещение его на второе место и т.д.);
3) упорядочить элементы массива по убыванию (просматривать последовательно элементы и
вставлять их на подходящее место в упорядоченную создаваемую последовательность; это место
определяется последовательным сравнением элемента с уже упорядоченными элементами).
4) упорядочить (переставить) строки матрицы по неубыванию значений первых элементов строк;
5) упорядочить (переставить) строки матрицы по невозрастанию сумм элементов строк;
6) упорядочить (переставить) строки матрицы по неубыванию значений наименьших элементов
строк;
7) упорядочить (переставить) строки матрицы по невозрастанию значений наибольших элементов
строк;
8) упорядочить (переставить) строки матрицы по неубыванию сумм элементов строк;
9) упорядочить (переставить) строки матрицы по неубыванию наименьших элементов строк;
10) упорядочить (переставить) строки матрицы по невозрастанию наибольших элементов строк.
10. Дан упорядоченный одномерный массив целочисленных значений и целое число р. Удалить k–ый
элемент массива и вставить в массив число р так, чтобы не нарушилась упорядоченность.
11. Дана действительная квадратная матрица порядка 2N. Получить новую матрицу, переставляя ее
блоки размера N*N, как показано на рисунке:
12. Дана действительная квадратная матрица порядка 3N. Найти наибольшее из значений элементов,
расположенных в заштрихованной части матрицы:
�Оглавлен ие
�Оглавлен ие
ПРИЛОЖЕНИЕ
{ввод одномерного массива}
write('укажите размер массива n='); readln(n);
for i:= 1 to n do
begin
write('a[', i, ']=');
readln(a[i]);
end;
{формирование одномерного массива с помощью датчика случайных чисел}
writе('укажите размер массива n='); readln(n);
Randomize;
for i:= 1 to n do
begin
a[i]:= random(200);
{диапазон изменения чисел 0..199}
b[i]:= 10?random;
{вещественные числа в диапазоне 0.0..9.9}
end;
{ввод двумерного массива по строкам}
write('укажите число строк n='); readln(n);
writе('укажите число столбцов m='); readln(m);
for i:= 1 to n do
begin
write('введите ', i, '–ю строку');
for j:= 1 to m do
begin
write('b[', i. ', ', j, ']=');
readln(b[i, j]);
end;
end;
{ввод двумерного массива по столбцам}
write ('укажитете число столбцов m='); readln (m);
write('укажите число строк n='); readln(n);
for j:=1 to m do
�Оглавлен ие
begin
write('введите ', j, '–и столбец');
for i:= 1 to n do
begin
write('b[', i, ', ', j, ']= ');
readln(b[i, j]);
end;
end;
{вывод одномерного массива}
writeln('вывод массива');
for i:= 1 to n do
write('a[', i:2, ']=', a[i]:4);
{вывод двумерного массива}
for i:= 1 to n do
begin
for j:=1 to m do
write('b['. i, ', ', j, ']=', b[i, j]);
writeln;
end;
{суммирование элементов одномерного массива}
s:= 0;
for i:= 1 to n do
s:= s + a[i];
{суммирование элементов двумерного массива}
s:= 0;
for i:= 1 to n do
for j:= 1 to m do
s:=s+b[i,j];
{суммирование диагональных элементов двумерного массива}
s:= 0;
for i:= 1 to n do
s:= s + b[i, i];
�Оглавлен ие
{суммирование двух массивов}
for i:= 1 to n do
c[i]:= a[i] + b[i];
{суммирование двумерных массивов}
for i:= 1 to n do
for j:= 1 to m do
c[i, j]:= a[i, j] + b[i,j];
{суммирование элементов i–ой строки матрицы}
s:= 0;
for j:= 1 to m do
s:= s + b[i, j];
{суммирование матрицы по строкам}
for i:= 1 to n do
begin
s:= 0;
for j:= 1 to m do
s:= s + b[i, j];
d[i]:= s;
end;
{транспонирование матрицы}
{заменить строки столбцами, а столбцы строками}
for i:= 1 to n do
for j:= 1 to m do
b[i, j]:= a[j, i];
{транспонирование квадратной матрицы}
for i:= 1 to n–1 do
for j:= i + 1 to n do
begin
p:= a[i, j];
a[i, j]:= a[j, i];
a[j, i]:= p;
�Оглавлен ие
end;
{умножение матрицы на вектор}
for i:= 1 to n do
begin
s:= 0;
for j:= 1 to m do
s:= s + a[i, j] ?b[j];
c[i]:= s;
end;
{умножение матрицы на матрицу}
for i:=1 to n do
for j:=1 to m do
begin
s:= 0;
for l:=1 to k do
s:= s + a[i,l]*b[l,j];
c[i,j]:= s;
end;
{удаление элемента из массива}
n:= n–1 ;
for i:= k to n do
a[i]:= a[i+1];
{включение элемента в заданную позицию массива}
for i:= n downto k do
a[i + 1]:= a[i];
a[k]:= b;
n:= n+1 ;
{включение элемента
упорядоченности}
в
массив,
упорядоченный
по
i:= 1;
m1: if i > n then begin a[i+1]:= b; goto m2 end;
if b > a[i] then begin i:= i+1; goto m1 end;
возрастанию
с
сохранением
�Оглавлен ие
for j:= n downto i do
a[j+1]:= a[j];
a[i]:= b;
m2: n:= n+1 ;
{удаление строки с заданным номером из матрицы}
n:= n – 1 ;
for i:= k to n do
for j:= 1 to m do
b[i, j]:= b[i+1, j];
{включение строки в матрицу}
for i:= n downto k do
for j:= 1 to m do
b[i+1, j]:= b[i, j];
for j:= 1 to m do
a[k,j]:= c[j];
n:= n+1 ;
{перестановка строк матрицы}
for k:= 1 to m do
c[k]:= a[i,k];
for k:= 1 to m do
a[i,k]:= a[j,k];
for k:= 1 to m do
a[j,k]:= c[k];
{перестановка строк матрицы}
for k:= 1 to m do
begin
p:= a[i,k];
a[i,k]:= a[j,k];
a[j,k]:= p;
end;
{умножение строки матрицы на число b}
�Оглавлен ие
for j:= 1 to n do
a[i, j]:= a[i, j]*b;
{поиск минимального (максимального) элемента в массиве}
max:= а[1]; index:= 1;
for i:= 2 to n do
if a[i] > max then
begin
max:= a[ i ];
index:= i;
end;
{поиск минимального (максимального) элемента в матрице}
max:= а[1, 1]; indexi:= 1; indexj:= 1;
for i:= 2 to n do
for j:= 1 to m do
if a[i, j] > max then
begin
max:= a[i, j];
indexi:= i;
indexj:= j;
end;
{упорядочить массив по возрастанию (убыванию)}
for j:= 1 to n–1 do
for i:= 1 to n–j do
if a[i] > a[i+1 ] then
begin
s:= a[i];
a[i]:= a[i+1];
a[i+1]:= s;
end;
{преобразование матрицы в одномерный массив}
for i:= 1 to n do
for j:= 1 to m do
�Оглавлен ие
b[(i–1)*m+j]:= a[i, j];
{определение числа элементов массива, удовлетворяющих заданному условию}
k:= 0;
for i:= 1 to n do
if а[j] >= t then k:= k+1;
{суммирование элементов массива, удовлетворяющих заданному условию}
s:= 0;
for i:= 1 to n do
if a[i] >= t then s:= s + a[i];
{объединение двух массивов одинакового размера}
for i:= 1 to n do
begin
с[2*i – 1]:= a[i];
c[2*i]:= b[i];
end;
{инвертирование массива}
m:= n div 2;
for i:= 1 to m do
begin
p:= a[i];
a[i]:= a[n–i+1];
a[n–i+1 ]:= p;
end;
{поиск в массиве заданного элемента и его номера}
l:= 100;
st:= 'элемента, равного L, нет';
k:= 0;
for i:= 1 to n do
if a[i] = l then k:= i;
if k = 0 then writeln(st)
else writeln('номер элемента i = ', k);
�Оглавлен ие
{циклический сдвиг элементов массива}
{исходные данные: n – размер массива, а – массив размером n, m – число позиций сдвига, р –
массив размером не менее m }
for i:= 1 to m do
p[i]:= a[n – m + 1];
for i:= n – m downto 1 do
a[i + m]:= a[i];
for i:= 1 to n do
a[i]:= p[i];
{циклический сдвиг элементов массива}
{исходные данные: n – размер массива, а – массив размером n, m –число позиций сдвига, р –
переменная, j – управляющая переменная внутреннего цикла}
for i:= 1 to n – 1 do
begin
р:= a[i];
for j:= i + 1 to n do
if a[j] <> р then
begin
p:= a[i];
k:= j;
end;
a[k]:= a[i];
a[i]:= p;
end;
�Оглавлен ие
Лабораторная работа № 9
СТРОКОВЫЙ ТИП ДАННЫХ
Строки – это последовательности символов, при использовании в выражениях строка обязательно
заключается в апострофы, идентификатор строки – string, за которым обязательно следует
заключенное в квадратные скобки значение максимально допустимой длины строки. Формат описания
строки:
Type
<имя типа> = string[i];
{ i – переменная типа byte, i <= 255}
Var
<идентификатор, ...>: <имя типа>;
Переменную типа string можно задать и без описания типа:
Var
<идентификатор, ...>: string[i];
Строковые выражения – это выражения, в которых присутствуют строковые данные. Над строковыми
данными допустимы операции сцепления и операции отношения.
Операция сцепления (+) применяется для сцепления нескольких строк в одну, длина результирующей
строки не должна превы-шать 255.
Пример: выражение – 'А' + 'Б' + 'В', результат – 'АБВ'.
Операции отношения (=, <>, >, <, >=, <=) проводят сравнение двух строк и имеют приоритет
ниже операции сцепления, строки сравниваются слева направо до первого несовпадающего символа,
результат операции отношения – True или False.
Примеры: выражение – 'Принтер' = 'Принтер', результат –True; выражение –
'ХХХХХ' < 'ХХХХ', результат – False.
Для присваивания строковой переменной результата строкового выражения используется оператор
присваивания (:=).
Пример: Str1:= 'Группа студентов'; Str2:= Str1 + ' второго курса';
Допускается смешение в одном выражении операндов строкового и литерного типа. К отдельным
символам строки можно обратиться по номеру (индексу данного символа в строке). Индекс –
целочисленная величина, записывается в квадратных скобках. Например, выражение Str2[8]
обеспечит доступ к восьмому символу 'у' переменной Str2.
Для обработки строковых данных используются следующие стандартные процедуры и функции:
Процедуры:
Delete (St, Poz, N) – удаление N символов строки St, начиная с позиции Poz.
Пример: St:= 'река Обь'; Delete(St, 1, 5) оставит 'Обь'.
Insert (Str1, Str2, Poz) – вставка строки Str1 в строку Str2, начиная с позиции Poz.
�Оглавлен ие
Пример: Str1:= 'ГП'; Str2:= 'БУ'; выражение Insert (Str1, Str2, 2) даст
результат 'БГПУ'.
Str (IBR, St) – преобразование числового значения величины IBR и помещение результата в строку
St.
Примеры: IBR:= 1500, Str(IBR:6, S) даст результат ' 1500'; IBR:= 4.8Е + 3,
Str(IBR:10, St) даст в переменной St выражение ' 4800'.
Val (St, IBR, Cod) – преобразует значение St в величину целочисленного или вещественного типа
и помещает результат в IBR. Cod – целочисленная переменная. Если во время операции
преобразования ошибки не обнаружено, значение Cod = 0, если ошибка обнаружена (например,
литерное значение переводится в числовое) Cod будет содержать номер позиции первого ошибочного
символа, а значение IBR не определено.
Функции:
Copy (St, Poz, N) – выделяет из St подстроку длиной N символов, начиная с позиции Poz. Если
Poz больше длины St, то результатом будет пробел, если Poz > 255, то возникнет ошибка при
выполнении. Poz, N – целочисленные выражения.
Пример: St:= 'ABCDEF'; Copy (St, 2, 3) выделит 'BCD'.
Concat (Str1, Str2, ..., StrN) – выполняет сцепление строк Str1, Str2, ... в том порядке, как
они указаны в списке. Сумма символов сцепленных строк не должна превышать 255.
Пример: Concat ('индекс', ' 656099') даст 'индекс 656099'.
Length (St) – вычисляет длину в символах строки St. Результат имеет целочисленный тип.
Пример: St:= '1234567890', Length (St) даст 10.
Роs (Str1, Str2) – обнаруживает первое появление в строке Str2 подстроки Str1. Результат имеет
целочисленный тип и равен номеру той позиции, где находится первый символ подстроки Str1. Если
подстрока Str1 в строке Str2 не найдена, результат равен нулю.
Пример: Роs ('тройка', 'перестройка') будет равно 6.
UpCase (Ch) – преобразует строчную букву в прописную (только латинский алфавит). Параметр и
результат имеют литерный тип.
Обработка строковых данных – необходимый элемент таких программ, как текстовые редакторы. Ниже
приведен пример программы простейшей лингвистической обработки, в котором к строковым данным
применяются наиболее часто употребляемые функции и процедуры.
Program DemoStr;
{Программа формирует строку из трех исходных строк. Определяется номер позиции первого появления в
результирующей строке буквы 'а' и общая длина строки. }
Var
А, В, С: string [12];
{А, В, С – исходные строки}
Str, Str1: string [40];
{Str – результирующая строка,
Ch1: string [1];
Str1 – инвертированная строка}
Ch: char ;
�Оглавлен ие
i, n: integer ;
Begin
A:= 'electronic';
B:= 'digit'; C:= 'machine';
Ch1:= Copy (A, 1,1);
{Выделение первой буквы в А };
Writeln;
Ch:= UpCase(Ch1[1]);
{Преобразование выделенной буквы из строчной в прописную };
Writeln;
Str:= Сoncat(A, В, C);
{Конкатенация строк А, В, С};
Writeln;
Delete(Str, 1, 1);
позицию прописной буквы};
{Стирание первой буквы для последующей записи в первую
Writeln(Str);
Insert(Ch, Str, 1);
{Вставка прописной буквы}
Insert(' ', Str, 11);
{Вставка первого пробела}
Insert(' ', Str, 17);
{Вставка второго пробела}
Writeln(Str);
{Вывод результирующей строки}
Writeln('Первая буква “а” появилась в позиции ', Pos('a',Str));
n:= Length(Str);
WriteIn('Длина строки = ', n);
Str1:= ";
For i:= 1 to n do
Str1:= Str1 + Copy(Str, n–i + 1, 1);
Writeln(Str1)
End.
{Получение и вывод инвертированной строки}
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Дано несколько слов. Составить программу, которая определяет, одинаковы ли длины слов или нет,
и определяет наибольшее и наименьшее по длине слова.
2. Составить программу, которая меняет местами первые и последние буквы слов данного
предложения.
3. Дано предложение. Составить программу, обращающую отдельные слова в предложении, но
сохраняющую порядок слов.
4. Составить программу, которая подсчитывает количество сдвоенных букв в предложении.
5. В строке длиной 30 содержится имя, отчество и фамилия так, что каждая часть занимает 10 позиций.
Напечатать фамилию и инициалы.
6. Целочисленные переменные i, j, k содержат информацию о длинах сторон треугольника.
Напечатать фразу «Рассмотрим треугольник со сторонами ... см, ... см,... см», где вместо многоточий
указаны соответствующие значения.
7. Составить программу, которая печатает отдельно каждое слово из за-данного предложения.
8. Дана дата в виде «месяц–число–год». Напечатать дату в виде «число–месяц–год».
9. В переменной содержится существительное первого склонения, оканчивающееся на «а». Напечатать
слово во всех падежах.
10. Дано несколько строковых переменных. В каждой из них даны имена и фамилии (например: Илья
Муромец, Александр Невский). Напечатать отдельно первые, а затем вторые слова из пар.
11. Определить, какая гласная встречается в заданной фразе наиболее часто.
12. Определить длину предъявленного слова. Напечатать «В этом слове N букв». Употребить форму
«буква», «буквы» или «букв».
13. Дано предложение. Напечатать длины слов, встречающихся в предложении.
14. Дано предложение. Напечатать все слова из этого предложения, которые содержат букву «а».
15. Составить слово, содержащее первые буквы слов заданного предложения.
�Оглавлен ие
Лабораторная работа № 10
ПРОЦЕДУРЫ И ФУНКЦИИ
При решении задач часто возникает необходимость повторять одни и те же вычисления при
различных значениях параметров. Для уменьшения размера программ целесообразно выделить эти
вычисления в отдельную подпрограмму. В основной программе при необходимости осуществляются
обращения к подпрограмме. В языке Turbo Pascal в качестве подпрограмм используются функции и
процедуры.
Функции представляют собой группу операторов, в результате выполнения которых вычисляется одно
значение, присваиваемое имени функции.
Функция включает в себя заголовок функции, разделы описаний (меток, констант, типов, переменных,
дополнительных функций и процедур, являющихся локальными по отношению к описываемой
функции), тело функции.
В заголовке функции за ключевым словом Function указывается имя функции, а в скобках – список
параметров со своими типами. В заголовке должен быть определен тип значения, возвращаемого
функцией. Окончательный результат присваивается имени функции в конце тела функции. Общая
структура записи функции имеет такой вид:
Function F(q1: T1; q2: T2; ...): T;
{Разделы определений и описаний локальных параметров и подпрограмм}
begin
p1;
p2;
• • •
F:= < вычисленное начение >
end;
где F – имя функции, q1, q2 – имена формальных параметров, Т1, T2 – типы параметров, Т – тип
имени функции, р1, p2 – операторы тела функции.
Функция может иметь свои локальные константы, типы, переменные и вспомогательные процедуры и
функции.
Обращение к функции осуществляется в правой части оператора присваивания указанием имени
функции и фактических параметров в виде F(b1, b2, ...), где F – имя функции, bi – фактические
параметры.
Пример 1. Составить программу для определения числа сочетаний
C nm
n!
,
m !(n m )!
используя функцию при вычислении факториала.
Program Number;
Var
�Оглавлен ие
n, m: byte;
nсm: longint;
Function Fact (k: byte): longint;
Var
p: longint;
i: byte;
begin
p:= 1;
for i:= 1 to k do
p:= p*i;
Faсt:= p;
end;
Begin
writeln('Введите данные для определения числа сочетаний');
readln(n, m);
nсm:= Fact(n) div Fact(m) div Fact(n–m);
writeln('Число сочетаний = ', ncm);
End.
2
Пример 2. Составить программу для вычисления функции y ax bx c ,
20
20
40
i 1
i 1
i 1
где a pi , b ti , c ri .
Решение. Функция для вычисления сумм в общем виде может быть представлена как Sum =
Program Runy;
Const
MaxSize = 50;
Type
md = 1..MaxSize;
mas = array [md] of real;
Var
np, nt, nr, i: integer;
p, t, r: mas;
х, y: real;
Function Sum(z: mas; nd: integer): real;
k
z .
i 1
i
�Оглавлен ие
Var
j: integer;
s: real;
begin
s:= 0;
for j:= 1 to nd do
s:= s + z [ j ];
Sum:= s;
end;
Begin
write('Введите х:'); readln(x);
write('Введите число элементов в массивах p, t, r');
readln(np, nt, nr);
writeln('Вводите элементы массива p');
for i:= 1 to np do read(p[i]);
writeln('Вводите элементы массива t');
for i:= 1 to nt do read(t[i]);
writeln('Вводите элементы массива r');
for i:= 1 to nr do read(r[i]);
y:=Sum(p, np)*x*x + Sum(t, nt) *x + Sum(r, nr);
writeln('y= ', y);
End.
Процедуры используются в тех случаях, когда в подпрограмме необходимо получить несколько
результатов. Процедура определяется в разделе описания процедур.
Описание процедуры включает в себя заголовок, разделы описаний (меток, констант, типов,
переменных, процедур, функций), тело процедуры.
В заголовке процедуры за ключевым словом Procedure указывают имя процедуры и в скобках –
список формальных параметров со своими типами. Эти параметры используются только в теле
процедуры и локальны по отношению к ней. Общая структура записи процедуры имеет такой вид:
Procedure F(var q1: T1; q2 : T2 ; ...);
{Разделы определений и описаний локальных параметров и подпрограмм}
begin
p1;
p2
• • •
�Оглавлен ие
end;
где F – имя процедуры, qi – имена формальных параметров, Тi –типы формальных параметров, рi –
операторы тела процедуры.
Имена формальных параметров, являющихся результатами вычислений в процедуре, записываются
после зарезервированного слова var.
Обращение к процедуре осуществляется оператором процедуры, в котором записывается имя
процедуры и фактические параметры:
F (b1, b2 , …);
где bi – фактические параметры, которые должны соответствовать формальным по количеству, типу
и месту расположения.
Пример 3. Составить программу для вычисления функции
z
используя для вычисления процедуру
th x
th a th 2 a b
2
th a b
2
,
e x e x e 2x 1
.
e x e x e 2x 1
Решение. Формальными параметрами процедуры будет переменная х и результат с именем R. Чтобы
избежать двукратного вычисления e2x, вводится дополнительный оператор присваивания
c:=ехр(2.0*х).
Program Fun1;
Var
a, b, z, t1, t2, t3: real;
Procedure Th(x: real; var r: real);
Var
c: real;
begin
c:= exp(2*x);
r:= (c–1)/(c+1);
end;
Begin
writeln('Введите а и b'); read(a, b);
Th(a, t1);
Th((a – b), t2);
Th(sqr(a) – sqr(b), t3);
z:= (t1 + sqr(t2))/sqrt(t3);
�Оглавлен ие
writeln('z= ', z);
End.
Если в процедуре и главной программе используются одни и те же имена параметров (процедура
связана с главной программой посредством глобальных переменных), то процедура может быть
организована без параметров.
Пример 4. Составить программу с процедурой без параметров для вычисления полярных
координат x 2 y 2 и arctg y x по прямоугольным х и у (х>0) координатам.
Program PolKorl;
Var
х, у, r, f: real;
n, i: integer;
Procedure Polar;
begin
r:= sqrt(sqr(х) + sqr(y));
f:= arctan(y/x);
end;
Begin
write('Введите количество точек'); readln(n);
for i:= 1 to n do
begin
write('Введите координаты точки: ');
readln(х, у);
Polar;
writeln(' Прямоугольным координатам:', x:6:1, y:6:1);
writeln('–
f:10:2);
соответствуют
полярные
координаты:',
r:6:1,
end
End.
Формальные параметры функций и процедур можно указывать в любом порядке, параметры одного
типа не обязательно группировать в одном месте. При обращении к процедуре или функции
фактические параметры следует записывать в той же последовательности, что и формальные.
При выборе имен, содержащих процедуры и функции, целесообразно, чтобы имена локальных и
глобальных параметров не совпадали. Это делает программу нагляднее. Правилами определения
области действия допускается использование одного имени для глобального и формального
параметров. В этом случае глобальный параметр теряет свое имя внутри блока процедуры или
функции, так как с этим именем связан локальный параметр.
�Оглавлен ие
При организации процедур и функций в языке Turbo Pascal различают параметры-значения и
параметры-переменные.
Параметры-значения определяют исходные данные для работы процедур и функций при каждом
обращении к ним. В списке формальных параметров они описываются в виде:
(q1: T1; q2 : T2)
или
(q1, q2 : T);
где qi – имена параметров, T, Ti – тип параметров.
При обращении фактический параметр может быть любым выражением, результат вычисления
которого принадлежит тому же типу, что и формальный параметр. В качестве простейшего выражения
указанного типа может быть константа или переменная. При обращении к процедуре выражение
вычисляется, результат копируется в выделенную область параметров, передается в процедуру, а при
выходе из нее эта область освобождается.
Параметры-переменные определяют выходные данные процедуры (результаты обработки данных),
которые передаются в основную программу. Поэтому фактический параметр, определяющий результат,
должен описываться как переменная. Параметры-переменные в списке формальных параметров
описываются в виде
(var q1, q2, …, qn: T);
где qi – параметры-переменные, Т – их тип.
Параметры-переменные в заголовке функции не используются, т.к. результат присваивается имени
функции.
При обращении фактические параметры должны быть переменными того же типа. В процедуру
передается адрес переменной, и операторы непосредственно используют данную переменную.
Вычисление адресов производится в момент обращения к процедуре, поэтому, если переменная
является элементом массива, то ее индексное выражение вычисляется при обращении к процедуре.
При использовании процедур и функций может встречаться рекурсивное обращение – обращение к
самим себе. Рекурсия в языке Turbo Pascal возможна благодаря тому, что при вызове процедуры
динамически создаются новые локальные переменные. Рекурсивные вызовы процедуры и функции
приводят к увеличению времени решения. Многие математические функции можно выразить
рекурсивно.
Пример. Используя рекурсию, вычислить значение
если n 0,
1,
n!
n n 1!, если n 0.
Function Fact(n: integer): integer;
begin
if
n=0
then Fact:= 1
else Faсt:=Faсt(n–1)*n
end;
При вычислении значения m! в программе нужно записать оператор mfac:= Fact(m); при
обращении к функции Fact фактический параметр m заменяет формальный параметр n. Если m>0, то
�Оглавлен ие
возникает рекурсивное обращение к функции Fact со значением параметра m–1. Создается копия тела
функции и для нового параметра со значением m–1 выделяется новая переменная, локальная по
отношению к копии тела функции. Эта переменная получает вычисленное значение. Затем вновь
производится обращение к функции со значением m–2 и т.д., пока значение параметра не станет
равным 1.
Однако в большинстве случаев рекурсивное решение может быть заменено на итерационное.
Вот как можно реализовать вычисление n! с помощью функции, использующей итерацию:
Function Fact(n: integer): integer;
Var
i, p: integer;
begin
if n = 0 then Fact:= 1
else
begin
p:= 1;
for i:= 1 to n do p:= p*i;
Fact:= p
end
end;
Различные способы объявления процедур рассмотрим на примере задачи о вычислении площади
выпуклого четырехугольника ABCD, заданного длинами четырех сторон и диагонали АС. Диагональ
делит выпуклый четырехугольник на два треугольника, к которым применима формула Герона
S = р(р – а)(p – b)(p – c),
где р=(а+b+с)/2 – полупериметр треугольника, а а, b, с – длины сторон треугольника.
Простейшее решение – дважды выписать в программе операторы, задающие вычисления по формуле
Герона. Мы же организуем процедуру и будем к ней обращаться.
Процедура без параметров
Program F1;
Var АВ, ВС, CD, DA, АC, s1, s, а, b, c, p: real;
Procedure Str1;
{Описание процедуры}
begin
p:= (a + b + c)/2;
s:= sqrt(р*(р – a)*(p – b)*(p – c))
end;
Begin
�Оглавлен ие
read(AB, ВС, CD, DA, AC);
a:= АВ; b:= ВС; c:= АС;
Str1;
{Первый вызов процедуры}
s1:= s;
а:= DA; b:= AC; с:= CD;
Str1;
{Очередной вызов процедуры}
s1:= s1 + s;
writeln(s1)
End.
В программе два обращения к процедуре Str1, после которых переменная s имеет значение площади
соответствующего треугольника. Связь процедуры Str1 с остальными операторами программы
осуществляется через переменные а, b, с, s. В процедуре имеется вспомогательная переменная р,
причем в основной программе она не используется. Удобнее в этом случае сделать переменную р
локальной, исключив ее из описательной части программы F1. Описание же процедуры будет
выглядеть так:
Procedure Str1;
Var
р: real;
begin
р:= (а + b + c)/2;
s:= sqrt(p*(p – a)*(p – b)*(p – c))
end;
После выполнения процедуры значение переменной р забудется.
Параметры - переменные
Продемонстрированный способ использования процедур неудобен из-за большого числа операторов
присваивания, определяющих значения переменных а, b, с. Есть другой способ – описать
процедуру с параметрами (аргументами). Вторая версия той же программы будет такой:
Program P2;
Var
АВ, ВС, CD, DA, AC, s1, s2: real;
Procedure Str2(Var a, b, c, s: real);
Var
p: real;
begin
p:= (a + b + c)/2;
�Оглавлен ие
s:= sqrt(p*(p – a)*(p – b)*(p – c));
end;
Begin
read(AB, ВС, CD, DA, AC);
Str2(AB, ВС, АC, s1);
Str2(CD, DA, AC, s2);
writeln(s1 + s2)
End.
Указанные в скобках при описании процедуры параметры а, b, с, s – это формальные параметры.
При выполнении программы в момент обращения к процедуре они заменяются фактическими
параметрами. Порядок следования параметров существенен и важно соответствие типов переменных.
Формальные параметры не описываются. Первое обращение к процедуре приведет к выполнению
оператора
begin
р:= (АВ + ВС + АС)/2;
s1:= sqrt(p*(p – АВ)*(р – ВС)*(р – АС))
end;
Параметры - значения
Заголовок процедуры может быть устроен так, что некоторые группы формальных параметров не
содержат слова Var. Например, Procedure Str3(a, b, c: real; var s: real). Формальные
параметры, которые входят в группы, не содержащие слова Var, называются формальными
параметрами-значениями. В приведенном выше примере а, b, с – это формальные
параметры-значения, a s – это формальный параметр-переменная. К процедуре Str3 можно
обратиться, например, так: Str3(3.14*2, х, Sqrt(10 – Sqr(х)), у). Это обращение повлечет
за собой вначале присвоения: а:= 3.14*2; b:= х; с:=Sqrt(10 – Sqr(х)); а затем отработку
самой процедуры.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Если координаты вершин треугольника в прямоугольной системе координат равны, соответственно
x1 , y1 , x2 , y2 , x3 , y3 , то площадь этого треугольника равна
0.5 x1 y2 x2 y3 x3 y1 x1 y3 x2 y1 x3 y2
.
Используя этот факт, написать программу вычисления площади выпуклого четырехугольника ABCD,
заданного координатами четырех вершин
x A , y A , xB , yB , xC , yC , xD , yD .
2. Даны вершины треугольника А x1 , y1 , В x2 , y2 и С x3 , y3 . Найти длины медиан.
3. Даны длины сторон треугольника а, b, с. Найти длины медиан треугольника. Замечание: длина
медианы, проведенной к стороне а, равна 0.5 2 b 2 2 c 2 a 2 .
4. Даны координаты вершин двух треугольников. Определить, какой из них имеет большую площадь.
5. Составить программу, вычисляющую 1) скалярное, 2) векторное, 3) смешанное произведения
векторов, заданных своими координатами. Составить программу, вычисляющую 4) сумму векторов и
5) угол между векторами.
6. Составить программу, вычисляющую следующие величины:
1)
4)
7)
s gt 2
p nkT;
2) v 2 gh ; 3)
;
l
E
;
Rr
v
kT
;
m
mv 2
;
2
5)
Ek
8)
E mc 2 ;
6)
9)
En mgh ;
Rобщ
R1 R2
R1 R2
7. Гиперболические функции определяются следующим образом:
1) sh x
e x e x
;
2
2) ch x
ex ex
;
2
3) th x
sh x
;
ch x
4) cth x
ch x
;
sh x
где х – вещественно. Вычислить эти функции, а также:
5)
2
sh x th ( x 1) th (2
sh( x 1));
6)
ch 2 x sh 2 x;
8. Дано: вещественные х, у. Вычислить
1) z = (sign х + sign y) sign(x+y), 2) z = sign(x) sign(y) sign(x+y),
3) z sign x sign 2 y 1 / 1 3 sign x sign y , где
�Оглавлен ие
1, при
sign a 0, при
1, при
a 0,
a 0,
a 0.
9. Даны действительные числа s, t. Получить
1) f(t, –2s, 1.17) + f(2.2, t, s–t), где
f ( a , b, c )
2a b sin c
,
5 c
2) g(1.2, –s) + g(t, s) – g(2s – 1, st), где
g (a , b )
a 2 b2
.
a 3ab 3b 2 4
2
10. Даны действительные числа a, b, c. Получить
1)
min( a, a b) max( a, b c)
,
1 max( a bc,1.15)
2)
min( u v 2,3.14),
где u min a , b , v min ab, a b ,
10
1.7 t 2 t 1 a
3) 6 t bc 2 1 , где t x
x
k 0
2 k 1
10
2k 1!
x 2 k 2k !
.
k 0
11. Даны действительные числа s, t. Получить
1)
2)
h s ,t max h 2 s t , st ,h 4 s t , s t
h 1,1
,
h t , s max h t , s , h s , t , h t, t ,
где h s, t
a
b
a b 3 .
2
1 b 1 a2
12. Даны массивы целых чисел х i, уi, zi, где i = 1..n.
Вычислить
n
x y
i 1
i
z.
n i 1 i
13. Дано: натуральные m, n (m>1), целые a1, ..., an , b1, ..., bn, с1, ..., c30. Получить
min b1 , , bm min c1 , , c30 , при min a1 , an 10,
l
2
1 min c1 , , c30 , в противном случае.
14. Дано: натуральные k, l, m, действительные x 1, ..., xk , y1, ..., yl, z1, ..., zm. Получить
max y1 , , yl max z1 , , zm , при max x1 , xk 0,
l
2
1 max x1 , , xk , в противном случае.
�Оглавлен ие
15. Дано натуральное n, действительные а1, ..., а3n. Получить
где
x a1a 2 a n ,
y a n 1a n 2 a 2n ,
x y2 z3,
z a 2 n 1a 2 n 2 a 3n .
16. Заданы массивы целых чисел. Вычислить:
1)
20 2
xi
i 1
u 20
y2
i
i 1
2)
max ci
min bi
, при min ai max bi ,
t max ai min bi ci
max b c min c , иначе.
i
i
i
3)
x y
10
i 1
i
n i 1
при
15
x y
i 1
i
i
0,
иначе.
.
17. Даны действительные числа a1, ..., an , b1, ..., bn. Образовать новые последовательности, в которых
1) элементы последовательности ai , следующие за членом с наибольшим значением заменены на
0.5;
2) элементы последовательности {bi}, меньшие 1, заменены на 1.
18. Даны три целые матрицы размера N*N. Вывести ту из них,
1) у которой сумма диагональных элементов максимальна;
2) в которой присутствует максимальный элемент;
3) в которой присутствует строка с максимальной суммой элементов;
4) в которой присутствует столбец с минимальной суммой элементов.
19. Даны N слов. Напечатать:
1) те из них, которые начинаются с буквы 'а';
2) слово максимальной длины;
3) слова, заканчивающиеся на 'b';
4) буквы, входящие одновременно во все слова;
5) буквы, содержащиеся в первом слове и не содержащиеся в остальных.
20. Составить процедуру, позволяющую определить позиции
1) самого правого вхождения заданного символа в исходную строку;
2) крайнего левого вхождения символа в строку;
3) вхождения сдвоенных букв в слово. Если таковых нет, результатом работы процедуры должна быть
–1.
21. Составить процедуру, заменяющую в исходной строке символов все единицы нулями и все нули
�Оглавлен ие
единицами.
22. Вычислить
b
f ( x )dx,
a
где f ( x) равно
1) ехр(х),
4) ln(x),
7) 1/(1+x 2),
2) sin(x),
5) arctg(x),
8) ехр(х),
3) cos(x),
6) 1/x,
9) cos(ln(x)).
23. Вычислить Z – сумму значений функции
Z=f(a, b)+f(a2 ,b2)+f(a-b, b)+f(a2+b2, b2-1),
где
u sin t ,
f u ,t
2
u t ,
1) a = 2.5; b = –7.3;
если u 0;
если u 0.
3) a = –0.2; b = –0.42;
2) a = –0.2; b = 4.2; 4) a = 23.5; b = 41.2.
24. Вычислить Z – сумму значений функции
Z = f(sin , a)+f(cos , a)+f(sin2 , a-1)+f(sin - cos , a2 - 1) +f (sin2 - 1, cos +1),
где
u sin t ,
f u ,t
2
u t ,
если u 0;
если u 0.
1) α = π/18; a = –2.1; 3) α = –π/14; a = –0.2;
2) α = 3.3; a = –2.1;
4) α = –π/10; a = 31.2;
�Оглавлен ие
Лабораторная работа № 11
МНОЖЕСТВА
Множества – это структурированный тип данных, представляющий набор взаимосвязанных по
какому–либо признаку или признакам объектов, которые можно рассматривать как единое целое.
Каждый объект множества называется элементом множества. Все элементы множества должны
принадлежать одному из скалярных типов, кроме вещественного. Этот тип называется базовым типом
множества.
Базовый тип задается диапазоном или перечислением. Область значений типа множество – набор
всевозможных подмножеств, составленных из элементов базового типа.
Если базовый тип принимает n значений, то тип множество для него будет иметь 2n вариантов
значений. В выражениях на языке Turbo Pascal значения элементов множества указываются в
квадратных скобках: [1, 2, 3, 4], ['a', 'b', 'c', 'd'], ['a'...'z'].
Если множество не имеет элементов, оно называется пустым и обозначается как [ ]. Для описания
множественного типа используется словосочетание Set of (множество из ...). Для задания типа
множество следует указать элементы этого множества, как правило, в виде перечисления или
диапазона, например:
Пример 1
Type
Alfa = Set of 'A'..'Z';
Count = Set of (Plus, Minus, Mult, Divid);
Ten = Set of 0..9;
Number = Set of '0'..'9';
Введя тип множество, можно задать переменные или типизированные константы этого типа. При
задании значений константе типа множество элементы константы задаются перечислением через
запятую элементов, помещенных в квадратные скобки. Например, для введенных выше типов можно
задать такие переменные и типизированные константы:
Пример 2
Var
CharVal: Set of 'A'..'Z';
Operac: Sет of (Plus, Minus, Mult, Divid);
Num: Ten;
Const
Index: Set of 0..9 = [0, 2, 4, 6, 8];
Digit: Set of '0'..'9' = ['0'..'9'];
Переменная CharVal может принимать значения 'A', 'B', 'C', ... – любое значение от 'A' до 'Z',
переменная Num может принимать значение 0, 1, 2, 3, ..., т.е. любое значение в диапазоне
0..9. Попытка присвоить другие значения вызовет программное прерывание. Переменной или
�Оглавлен ие
типизированной константе типа множество можно в программе присвоить то или иное значение.
Обычно значение задается с помощью конструктора множества. Конструктор задает множество
элементов с помощью перечисления в квадратных скобках выражений, значения которых дают
элементы множества. Допустимо использовать диапазоны элементов. Следующие структуры являются
конструкторами множеств (пример 4).
Пример 3
[Plus, Minus]
[1..K mod 12,15]
[Cur(0)..Cur(32),'A','B']
В каждое множество включается и так называемое пустое множество [ ], не содержащее никаких
элементов. Конструктор множества можно использовать и непосредственно в операциях над
множествами.
Количество элементов (мощность) множества в Turbo Pascal не может быть больше 256, а
порядковые номера элементов (т.е. значение функции Ord) должны находиться в пределах от 0 до
255. Контроль диапазонов осуществляется директивой {$R+}. Объем памяти, занимаемый одним
элементом множества, составляет 1 байт.
При работе co множествами Turbo Pascal допускает использование операций "=", "<>", ">=",
"<=", объединения (+), пересечения (*), разности (–) и операции In. Результатом выражений с
применением этих операций является значение True или False, в зависимости от того, истинно это
выражение или ложно.
Операция «равно» (=). Два множества A и B считаются равными, если они состоят из одних и тех же
элементов. Порядок следования элементов в сравниваемых множествах значения не имеет.
Значение A
Значение B
Выражение
Результат
[1, 2, 3, 4]
[1, 2, 3, 4]
A = B
True
['a'..'2']
['b'..'2']
A = B
False
['a'..'2']
['2'..'a']
A = B
True
Операция «не равно» (<>). Два множества A и B считаются не равными, если они отличаются по
мощности или по значению хотя бы одного элемента.
Значение A
Значение B
Выражение
Результат
[1, 2, 3]
[3, 1, 2, 4]
A <> B
True
['a'..'2']
['6'..'2']
A <> B
True
['c'..'t']
['t'..'c']
A <> B
False
Операция «больше или равно» (>=). Используется для определения принадлежности множества.
Результат операции A >= B равен True, если все элементы множества B содержатся во множестве A.
В противном случае результат равен False.
Значение A
Значение B
Выражение
Результат
[1, 2, 3, 4]
[2, 3, 4]
A >= B
True
['a'..'2']
['b'..'t']
A >= B
True
�Оглавлен ие
['z','x','c']
['c','x']
A >= B
True
Операция «меньше или равно» (<=). Используется аналогично предыдущей операции. Результат
выражения A <= B равен True, если все элементы множества A содержатся во множестве B. В
противном случае результат равен False.
Значение A
Значение B
Выражение
Результат
[1, 2, 3]
[1, 2, 3, 4]
A <= B
True
['a'..'h']
['2'..'a']
A <= B
True
['a','v']
['a','n','v']
A <= B
True
Операция In. Используется для проверки принадлежности какого-либо значения указанному
множеству. Обычно применяется в условных операциях.
Значение A
Выражение
Результат
2
if A in [1, 2, 3] then...
True
'v'
if A in ['a'..'n'] then...
False
x1
if A in [x0, x1, x2, x3] then...
True
При использовании операции In проверяемое на принадлежность значение и множество в
квадратных скобках не обязательно описывать в разделе объявлений.
Операция In позволяет эффективно производить сложные проверки условий, заменяя иногда десятки
операций. Например, выражение
if (a=1) or (a=2) or (a=3) or (a=4) or (a=4) or (a=5) then...
можно заменить более коротким
if a in [1..5] then ... .
Часто операцию in пытаются записать с отрицанием: X not in M. Такая запись является ошибочной,
т. к. две операции следуют подряд: правильная конструкция имеет вид: not (X in M).
Объединение множеств (+). Объединением массивов является третье множество, содержащее
элементы обоих множеств.
Значение A
Значение B
Выражение
Результат
[1, 2, 3]
[1, 4, 5]
A + B
[1, 2, 3, 4, 5]
['A'..'D']
['E'..'Z']
A + B
['A'..'Z']
[ ]
[ ]
A + B
[ ]
Пересечение множеств (*). Пересечением двух множеств является третье множество, которое
содержит элементы, входящие одновременно в оба множества.
Значение A
Значение B
Выражение
Результат
[1, 2, 3]
[1, 4, 2, 5]
A*B
[1, 2]
['A'..'Z']
['B'..'R']
A*B
['B'..'R']
[ ]
[ ]
A*B
[ ]
�Оглавлен ие
Разность множеств (–). Разностью двух множеств является третье множество, которое содержит
элементы первого множества, не входящие во второе множество.
Значение A
Значение B
Выражение
Результат
[1, 2, 3, 4]
[3, 4, 1]
A – B
[2]
['a'..'z']
['d'..'z']
A – B
['a'..'c']
СТАРШИНСТВО МНОЖЕСТВЕННЫХ ОПЕРАТОРОВ.
Приоритетный уровень
Операторы
Операции
*
пересечение
+, –
объединение, разность
=, <>, >=, <=, In
равенство, неравенство, подмножество, принадлежность
1 (высший)
2
3 (низший)
Для изменения порядка выполнения используются круглые скобки.
Средства работы с множествами позволяют в некоторых случаях сократить программы и сделать их
более наглядными и эффективными за счет уменьшения числа различных проверок.
Пример 5
Program Prim 5;
Var Stroka: string;
i: integer;
Prav: boolean;
Begin
i:= 1;
writeln('введите строку');
readln(Stroka);
L:= Length(Stroka);
{число введенных символов}
Prav:= L > 0;
{True, если не нулевая строка}
while Prav and (i <= L) do
begin
{проверка допустимости символа}
Prav:= Stroka[i] In
['0'..'9', 'A'..'Z', 'a'..'z', ' '];
i:= Succ(i);
{следующий номер}
end;
if Prav then writeln('правильная строка')
else writeln('неправильная строка');
End.
�Оглавлен ие
Для вывода элементов некоторого множества, сформированного в процессе выполнения программы,
необходимо воспользоваться оператором цикла, внутри которого была бы проверка на
принадлежность текущего значения параметра цикла выводимому множеству. Например, для
множества ВВ, описанного как ВВ: Set of 'A'..'Z'; можно организовать вывод элементов
следующим образом:
Пример 6
For i:= 'A' to 'Z' do
if i in BB then write(i:2);
Причем параметр цикла i должен быть описан либо как символьная переменная, либо как i:
'A'..'Z'. Печать элементов множества производится в том порядке, в котором они встречаются в
базовом множестве. Приведенная ниже программа Lat формирует множество LB, в которое входят
только заглавные латинские буквы, встретившиеся во входной строке, и множество знаков
препинания PR из входной строки (пример 7).
Пример 7
Program Lat;
Var
c, i, j: char;
LB: Set of 'A'..'Z';
PR: Set of '!'..'?';
Begin
write('=>');
LB:= [ ]; PR:= [ ];
repeat
read(c);
if c in ['A'..'Z'] then LB:= LB + [C]
else
if c In [':', ';', '.', ',', '!', '?'] then PR:= PR + [C]
until Eoln;
writeln('Латинские буквы:');
for i:= 'A' to 'Z' do
if i in LB then write(i:2);
writeln;
writeln('Знаки препинания:');
for j:= '!' to '?' do
if j in PR then write(j:2);
End.
�Оглавлен ие
ВОПРОСЫ И УПРАЖНЕНИЯ
1. Какие типы данных используются в качестве базовых при построении множественных типов?
2. Дано описание переменной множественного типа: Var Pm: Set of (Red, Grey, Blue,
Black). Выписать все допустимые значения этой переменной.
3. Какие операции определены над переменными множественного типа и каков их приоритет?
4. Будут ли равны множества:
a) ['A'..'D'] и ['A','B','C','D'];
b) [White, Black] и [Black, White].
5. Вычислить следующие выражения:
а) [5] <= [1..5];
b) ['A'..'D', 'K'..'M'] + ['D'..'K'];
c) [Jan, Feb, Мar]*[Mar];
d) [2, 1, 3..6] = [1..7];
e) 15 In [1..10];
f) [',', '(', ')', '.'] – [',', '.'].
6. Вычислить выражение:
[1..14]*[5, 12..60] + [4..7] – [2*16]*[6].
7. Упростить данные выражения множественного типа:
а) [11..17]*[2] + [7, 17..40]*[2..17] – [2..8];
b) (A – B)*A + (A – B)*B;
c) (A + B)*(A – B)*(B – A);
d) A – B – (A – B) – (B – A);
e) A – (A – B).
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. Дана непустая последовательность символов. Требуется построить и напечатать множество,
элементами которого являются встречающиеся в последовательности:
1) цифры от '0' до '9';
2) буквы от 'A' до 'F' и от 'X' до 'Z';
3) буквы от 'G' до 'N' и цифры от '0' до '9';
4) знаки препинания;
5) буквы от 'A' до 'Z' и цифры от '0' до '5';
6) буквы от 'T' до 'X' и знаки препинания;
7) знаки арифметических операций и знаки препинания;
8) цифры и знаки арифметических операций;
9) знаки препинания и буквы от 'E' до 'N';
10) цифры от '5' до '9' и знаки препинания;
11) знаки операций отношения;
12) цифры от '3' до '9', буквы от 'A' до 'F' и знаки препинания;
13) знаки арифметических операций и операций отношения;
14) буквы от 'F' до 'M' и знаки арифметических операций;
15) знаки препинания и операций отношения;
16) цифры от '0' до '5' и буквы от 'K' до 'R'.
II. Операции над массивами. При выполнении задания следует учесть приемы программирования,
использованные в приведенной ниже программе:
Program Eratosphen;
Const
n = 255;
Var
Sieve, Primes: Set of 2..n;
Next: byte;
j: word;
Begin
Sieve:= [2..n];
Primes:= [ ];
Next:= 2;
repeat
�Оглавлен ие
while not (Next in Sieve) do
Next:= Next + 1;
Primes:= Primes + [Next];
j:= Next;
while j <= n do
begin
Sieve:= Sieve-[j];
j:= j + Next
end;
until Sieve = [ ];
for j:= 2 to n do
if j In Primes then Write(j:5)
End.
1. Из множества целых чисел [1..1000] методом решета Эратосфена получить множество простых
чисел и вывести их на экран.
2. Из множества целых чисел [1..1000] получить множество чисел, являющихся квадратами четных
чисел и вывести их на экран.
3. Из множества целых чисел [1..1000] получить множество чисел, являющихся квадратами нечетных
чисел и вывести их на экран.
4. Дано целое n от 2 до 1000. Используя метод решета Эратосфена, напечатать в убывающем порядке
все простые числа из диапазона n..2n.
5. Из множества целых чисел [1..500] методом решета Эратосфена получить множество простых чисел
и вывести их на экран.
6. Из множества целых чисел [1..500] получить множество чисел, являющихся квадратами четных
чисел и вывести их на экран.
7. Из множества целых чисел [1..500] получить множество чисел, являющихся квадратами нечетных
чисел и вывести их на экран.
8. Дано целое n от 2 до 500. Используя метод решета Эратосфена, напечатать в убывающем порядке все
простые числа из диапазона n..2n.
�Оглавлен ие
Лабораторная работа № 12
ЗАПИСИ
Комбинированный тип характеризует объекты, называемые записями.
Запись – это сложная переменная с несколькими компонентами, называемыми полями. В отличие от
массивов компоненты записи (поля) могут иметь разные типы и доступ к ним осуществляется не по
индексу, а по имени поля. При определении комбинированного типа задаются имя и тип каждого
поля. Описание комбинированного типа начинается со служебного слова Record и заканчивается
словом End. После зарезервированного слова Record следует перечислить все поля записи с указанием
через двоеточие их типов. Поля отделяются друг от друга точкой с запятой (;). Поля записи могут быть
любого типа.
Пример 1
Пример 2
Type
Type
Complex = Record
Date = Record
Re:real;
Year: integer;
Im:real
Month: 1..12;
End;
Day: 1..31
End;
Var
Var
x,y,z: Complex;
MyBirthday: Date;
Пример 3
Пример 4
Type
Type
Person = Record
Complex = Record
Name: string[20];
Re,Im:Real
Sex: (Male,Female);
Age: integer;
Married: Boolean
End;
Var
x,y,z: Complex;
End;
Var
Man: Person;
Если несколько полей записи имеют один и тот же тип, то имена полей можно перечислить через
запятую и затем указать общий тип. Так, рассмотренный в примере 1 тип комплексных чисел можно
ввести и другим образом (см. пример 4).
После введения типа запись можно задать переменные или типизированные константы этого типа.
При задании значений константе типа запись поля задаются в круглых скобках через точку с запятой.
В отличие от констант типа массив для задания значения каждого поля сначала указывается имя
�Оглавлен ие
поля, а затем через двоеточие – его значение. Так для введенных выше типов можно
например, следующие переменные и константы:
ввести,
Пример 5
Var
x, y, z: Complex;
Dat, Dat1: Data;
Const
Birthday: Data = (Year:1971; Month:12; Day:9);
Ivanov: Person = (Name: 'Иванов';
Sex: Male;
Age: 40;
Married: True);
Примечание. Так же, как и при введении типа массив, тип запись можно вводить непосредственно при
определении переменных или типизированных констант. Фрагмент (пример 6) определяет те же
комплексные переменные, что и в примере 4.
Пример 6
Var
x, y, z: Record
Re,Im: real
End;
Доступ к полям переменной или константы типа запись осуществляется указанием имени переменной
(константы) и имени поля, записываемого через точку, например:
Man.Name; MyBirthday.Year; X.Re; MyBirthday.Month;
Dat.Day; MyBirthday.Day;
и т.д. Такие имена в программах используются так же, как и переменные других типов.
Использование полей записей. Оператор присваивания заносит в соответствующее поле значение
компоненты записи:
Пример 7
X.Re:= 1.5;
X.Im:= 1.7;
Y.Re:= -X.Re;
Y.Im:= -X.Im;
Ivanov.Married:= False;
Значения переменных и констант типа Record можно присваивать другим переменным того же типа,
например Dat:= Dat1; (см. пример 5). Паскаль допускает вложение записей друг в друга, т.е.
�Оглавлен ие
компоненты записи (поля) в свою очередь могут иметь тип запись. Уровень вложения не должен
превышать 9.
Пример 8
Type
Student = Record
Surname: string[25];
Birthday: Record
Day: 1..31;
Month: (Jan, Feb, Mar, Apr, May, Jun,Jul, Aug,
Sep, Ocт, Nov, Dec);
Year: integer
End;
Sex: (Male, Female);
End;
Var
St: Student;
Group: array[1..30] of Student;
К каждому из компонентов записи можно получить доступ, если указать имя переменной типа Record,
затем через точку и имя поля. Для вложенных полей приходится продолжать уточнения:
Пример 9
St.Birthday.Day:= 25;
St.Birthday.Month:= Feb;
St.Birthday.Year:= 1977;
Для того, чтобы не выписывать каждый раз имя переменной при обращении к полям переменной
типа запись, можно использовать оператор присоединения, имеющий вид
With <список переменных–записей, полей> do <оператор>;
Имена переменных-записей и полей, указанные в заголовке оператора присоединения, можно
опускать при обращении к компонентам записей в области действия оператора with. Внутри
оператора к компонентам записи можно обращаться только с помощью имени компоненты.
Пример 10
With x do
begin
Re:= 1.5;
Im:= 1.7;
Y.Re:= -Re;
�Оглавлен ие
Y.Im:= -Im;
end;
With Ivanov do
Married:= False;
Приведенный выше фрагмент эквивалентен фрагменту из примера 7, а фрагмент:
Пример 11
With St.Birthday do
begin
Day:= 25;
Month:= Feb;
Year:= 1977
end;
эквивалентен фрагменту из примера 9.
Записи могут входить в качестве компонентов в другие переменные. Например, переменная Group это вектор, состоящий из 30 записей. Оператор присваивания нового значения полю Month в пятой
записи массива имеет вид:
Group[5].Birthday.Month:= Feb;
Легко видеть, что к каждой записи (элементу массива) доступ осуществляется при помощи индекса.
Приведенный ниже фрагмент программы подсчитывает число студентов мужского пола, родившихся в
1974 году:
Пример 12
k:= 0;
for i:= 1 to 30 do
With Group[i].Birthday do
if (Year = 1974) and (Sex = Male) then k:= k + 1;
writeln('число мужчин = ', k:2);
Следует обратить внимание на то, что оператор присоединения стоит внутри цикла по i. Это
объясняется тем, что в области действия оператора присоединения нельзя изменять элементы списка
переменных–записей и полей, указанные в заголовке. В данном примере в заголовке оператора With
стоит Group[i] - элемент массива, зависящий от параметра i.
Тип запись может иметь вариантную часть. Вариантная часть записи может быть только одна и
должна располагаться в конце записи.
Пример 13
a) Type Sex = (Male,Female);
Man = Record;
�Оглавлен ие
FirstName: String[25];
Born: 1800..2000;
Mn: Sex;
Case sex of
Male: (Military: Boolean; Job: String[20]);
Female: (Married: Boolean; Children: byte)
End;
Var
M1, M2: Man;
b) Type Figure = (Square, Triangle, Circle);
Param = Record
x, y: real;
Fig: Figure
Case Figure of
Square: (side: real);
Triangle: (side1, side2, Angle: real);
Circle: (Radius:real)
End;
Var
Kwadrat, Krug: Param;
Вариантная часть записи начинается оператором Case и следует за общей частью; после ее окончания
в записи не могут появляться никакие другие поля, поэтому оператор Case не закрывается служебным
словом End.
Обычно некоторое из полей общей части указывает вариант. В примере (13.а) это поле Мn, называемое
полем признака или дискриминантом. Все варианты описываются внутри оператора Case. Каждый
вариант характеризуется задаваемым в скобках списком описаний присущих ему компонентов.
Перед списком стоит одна или несколько меток. Тип этих меток указывается в заголовке вариантной
части (в отличие от оператора варианта, где селектором варианта является выражение, а не тип).
Отметим, что тип должен быть скалярным, при этом он задается именем.
В явном виде указывать тип в заголовке не разрешается. Часто для сокращения записи поле признака
(дискриминант) включается в заголовок вариантной части:
Case Mn: Sex of
или
Case Fig: Figure of.
Для переменной М1 типа Man можно написать следующие операторы присваивания:
M1.Firstname:= 'Иванов'; M1.Born:= 1911;M1.Mn:= Male;
M1.Military:= True; M1.Job:= 'Pilot';
�Оглавлен ие
Задав значение поля признака Mn (некоторую константу типа Sex), можно присваивать новые
значения только полям вариантной части, помеченным такой же константной. Хотя никакого контроля
поля селектора при обращении к компоненту из вариантной части не производится, для надежности
работы программы следует придерживаться этого правила.
Примечание. В стандартном Паскале в качестве ключа выбора необходимо указывать некоторую
переменную порядкового типа, причем в исполняемой части программы можно присваивать значения
этой переменной и таким образом влиять на работу полей. В Тurbo Pascal также можно в поле
ключа выбора описывать переменную порядкового типа и даже присваивать ей какое-либо значение,
однако это не повлияет на выбор поля: значения констант выбора могут быть в Тurbo Рascal
произвольными и даже повторяющимися.
�Оглавлен ие
ВОПРОСЫ И УПРАЖНЕНИЯ
1. Какой тип характеризует объекты, называемые записями?
2. Могут ли компоненты записи быть различных типов?
3. К какому типу относится следующее описание? Назвать компоненты записи и их типы.
Book = Record
Nazv: string[15];
Godizdan: 1000..1992;
Cena: real
End;
4. Имеется описание
Type Family = Record
Glava: string[20];
Age: 18..100;
Children: array[1..2] of Record
Name: String[25];
Born: 1900..2000
End
End;
Занести исходную информацию в переменную А без использования оператора присоединения и
продублировать ее в переменной В.
5. Известно, что
Type Time = Record
hour: 0..23;
minute: 0..59;
second: 0..59
End;
Var
T1, T2: Time;
Написать программу, которая вводит значения полей записей T1 и Т2 и печатает True, если Т1
предшествует Т2, и печатает False в противном случае.
6. Как осуществляется доступ к полям записей?
7. Что является селектором в операторе Case при задании вариантной части записи?
8. Могут ли записи входить компонентами в другие переменные?
�Оглавлен ие
9. Даны названия 15 ЭВМ. Для каждой ЭВМ известны объем памяти, стоимость и быстродействие.
Составить программу, которая вводит данные о всех ЭВМ, определяет, какая ЭВМ имеет минимальное
отношение стоимость/быстродействие, и печатает название этой машины и ее характеристики.
Перед выполнением контрольных заданий проанализируйте работу программы, приведенной ниже.
Программа Zap вводит информацию о пяти студентах: фамилию, год рождения, год поступления в вуз
и оценки последней сессии. Результатом работы программы является список отличников. В программе
показаны возможности организации работы с записями с использованием оператора присоединения:
Program Zap;
Uses Crt;
Const n = 3;
Type Student = Record
Surname: String[20];
Born: 1965..1978;
Year: 1988..1991;
Mark: Record
Inf, Phys, Hist: 1..5
End
End;
Var
Group: array[1..5] of Student;
S1: Student;
i, j: integer;
Begin
ClrScr;
Writeln('Вводите данные :'#61#61#62);
With S1, Mark do
begin
for i:=1 to n do
begin
write('фамилия - '); readln(Surname);
write('Год.рожд., Год.пост., Отметки...');
readln(Born, Year, Inf, Phys, Hist);
Group[i]:= S1
end
end;
�Оглавлен ие
writeln ('Список отличников:');
j:=0;
For i:=1 to n do
With Group[i], Mark do
if (Inf = 5) and (Phys = 5) and (Hist = 5) then
begin
writeln(Surname,' Год рождения- ',Born:4,
' Год поступления- ',Year:4);
j:=j+1;
end;
if j=0 then writeln(‘Отличников нет’)
End.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1.
Опишите структуры, показанные на рисунках, пользуясь словесными выражениями, например:
“a подразделяется на b и c” и т.д. Затем то же сделайте на Turbo Pascal: объявите каждую запись,
задавшись подходящими типами всех компонентов.
2. Описать комбинированный тип для представления следующего понятия:
1) сведения о 10 персонах (дата рождения: число, день недели, месяц, год; место жительства: город,
улица, номер дома, номер квартиры);
2) семинар (предмет, преподаватель, номер группы, день недели, часы занятий, аудитория);
3) бланк требования на книгу (сведения о книге: шифр, автор, название, год издания; сведения о
читателе: номер читательского билета, фамилия; дата заказа);
4) экзаменационная ведомость (предмет, номер группы, дата экзамена, 25 строчек с полями: фамилия
студента, номер его зачетной книжки, оценка за экзамен);
5) сведения о 10 студентах группы (фамилия, имя, отчество; дата рождения: число, месяц, год; пол;
семейное положение; отношение к воинской службе);
6) сведения о заводе-изготовителе компьютеров (название завода; название заводов-поставщиков
комплектующих изделий; номера магазинов потребителей; название производимых ЭВМ (5..10
�Оглавлен ие
наименований): цена каждого товара за штуку в рублях и в долларах; количество каждого вида изделий
в штуках);
7) сведения об ЭВМ (название; объем памяти; быстродействие, стоимость в рублях и в долларах;
фирма поставщик; тип монитора и дисководов);
8) сведения о 5 персонах (фамилия, имя, отчество, пол, национальность, семейное положение,
образование (высшее, среднее специальное, среднее, неполное среднее); адрес: улица, номер дома,
номер квартиры, почтовый индекс, номер телефона).
9) сведения о заводе-изготовителе автомобилей (название завода, название заводов-поставщиков
комплектующих изделий, номера фирменных магазинов, марка производимых автомобилей, цена
автомобиля в рублях - долларах, количество каждой выпускаемой марки автомобилей.
Каждому компоненту записи присвоить значение: a) с помощью оператора присваивания; b)
используя оператор присоединения With.
Организуйте вывод значений компонент записи.
3.
1) распечатать анкетные данные студентов-отличников;
2) распечатать анкетные данные студентов, успевающих на 4 и 5;
3) распечатать анкетные данные студентов, получивших одну оценку 3 за все время обучения;
4) распечатать анкетные данные студентов, получивших в последнюю сессию оценки 2;
5) распечатать анкетные данные студентов, получивших в первую сессию все оценки 5;
6) распечатать анкетные данные студентов, получивших за все время обучения одну оценку 4, а все
остальные оценки - 5;
7) распечатать список и даты рождения студентов, фамилии которых начинаются с буквы 'А';
8) распечатать список студентов, фамилии которых начинаются с буквы 'Б' и их оценки за все время
обучения;
9) распечатать оценки в последнюю сессию студентов, фамилии которых начинаются с букв 'В' и 'Г';
10) распечатать фамилии и даты рождения студентов, не получивших ни одной оценки 3 за все
время обучения;
11) упорядочить список студентов по среднему баллу последней сессии и распечатать его;
12) упорядочить список студентов по среднему баллу и распечатать его;
13) вычислить средний балл группы и распечатать список студентов, имеющих средний балл выше
среднего балла группы;
14) вычислить средний балл группы и распечатать список студентов, имеющих средний балл ниже
среднего балла группы;
15) вычислить средний балл группы в последнюю сессию и распечатать список студентов, имеющих
средний балл, равный среднему баллу группы.
16) упорядочить список студентов по году рождения и распечатать его;
�Оглавлен ие
17) распечатать список студентов, упорядоченный по алфавиту;
18) распечатать список студентов, упорядоченный по месяцу рождения;
19) распечатать список отличников, упорядоченный по году рождения;
20) распечатать список студентов, упорядоченных по дате рождения.
�Оглавлен ие
Лабораторная работа № 13
ФАЙЛЫ
Файл – это
информации.
клавиатурой,
языка Turbo
поименованная часть памяти на внешнем носителе, предназначенная для хранения
Файл может быть связан с любым источником или потребителем информации:
принтером, магнитным диском и др. Будем рассматривать лишь стандартные файлы
Pascal и дисковые файлы, созданные пользователем.
Стандартные файлы определены разработчиками системы и их можно только использовать.
Файлы пользователя размещаются на внешних носителях. В файлах могут храниться программы,
данные, тексты документов, закодированные изображения и т.п. Файл может быть входным или
выходным. Из входного файла программа получает данные, в выходной файл выводит их. Каждый
файл имеет имя, зарегистрированное в директории (оглавлении диска).
Определение файлового типа. Файл с точки зрения языка Turbo Pascal – это структурированный
тип данных, состоящий из последовательности компонентов одного типа и одной длины.
Определение типа файла начинается словосочетанием file of, после которого задается тип
компонентов файла, который описывает, что содержит данный файл. Далее следует идентификатор
предварительно определенного типа файла. Число компонентов, называемое длиной файла, не
фиксируется.
Формат:
Type
<имя типа> = File of <тип компонент>;
Var
<идентификатор>:<имя типа>;
Пример:
Type
Karta = File of Record
{здесь элементами}
Dlina: byte;
{файла объявлены}
Ves: real
{данные типа ЗАПИСЬ}
End;
Var
Kartfile: Karta;
Для описания файлов, состоящих из записей, можно использовать и другую форму, которая не
вызывает ошибок даже у новичков.
Формат:
Type
<тип компонент> = Record
<поле>:<тип>;
�Оглавлен ие
...
<поле>:<тип>
End;
Var
FV: File of <тип компонент>;
{переменная для доступа к файлу}
RV: <тип компонент>;
{переменная для доступа к записи}
Пример:
Type
Zapis = Record
Nomer: integer;
FIO: string[20];
Oklad: real
End;
Var
FV: File of Zapis;
RV: Zapis;
Переменные файлового типа нельзя использовать в выражениях. Файл хранится во внешней памяти и
вызывается в оперативную память для обработки. Доступ к компонентам файла осуществляется через
указатель файла (буферную переменную). При чтении или записи этот указатель перемещается к
следующему компоненту и делает его доступным для обработки. Существует два способа доступа к
компонентам файла: последовательный и произвольный (прямой). При последовательном способе
доступа поиск начинается с начала файла и проверяется по очереди каждый элемент, пока не будет
найден нужный. Произвольный способ доступа позволяет обращаться к компоненту по его
порядковому номеру в файле.
Спецификация файла. Имя файла состоит из собственно имени (1–8 символов: букв и цифр) и
необязательного типа файла (3 символа). Тип файла присваивается обычно в мнемонической
зависимости от содержания файла. Например, programm.pas, programm.bas, pascal.doc, instruct.txt.
Стандартные процедуры и функции обработки файлов. При их описании используем следующие
обозначения: FV – файловая переменная; Str – строковое выражение; P – переменные p1, p2,
...,pn того же типа, что и компоненты переменной FV; n – целочисленное выражение.
Процедуры. Осуществляют все необходимые действия по организации файлов и доступу к
компонентам файлов.
Str) – связывает файловую переменную FV с именем файла Str. С момента
выполнения этой процедуры все действия над переменой FV будут эквивалентны действиям над
файлом, определяемым значением Str.
Assign(FV,
�Оглавлен ие
Rewrite(FV) – создать новый файл на диске. Имя файла предварительно определяется в процедуре
Assign. Указатель файла устанавливается на первую позицию (с номером 0), файл подготовлен для
загрузки.
Reset(FV) – установить указатель в начало файла. Эта процедура, примененная к несуществующему
файлу, вызывает ошибку ввода–вывода.
Read(FV, P) – читать из файла FV значения переменных p1,p2,..,pn. После выполнения
процедуры указатель перемещается на следующий компонент.
Write(FV, P) – записать в файл. Переменные p1,...,pn записываются в дисковый файл,
определенный переменной FV, и указатель перемещается к следующему компоненту.
Seek(FV, n) – установить указатель на компонент с порядковым номером n в файле. Счет
начинается с нуля, т. е. первый компонент имеет номер 0, второй – 1 и т.д.
Flush(FV) – очистить буфер сектора. Выполнение процедуры вызывает выталкивание внутреннего
буфера в файл, если ранее выполнялись операции записи. К закрытому файлу процедура не
применяется. Файл – текстовый.
Close(FV) – закрыть файл. Если файл был открыт, никогда не следует выходить из программы,
предварительно не закрыв его.
Erase(FV) – уничтожить файл. Для уничтожения открытого файла, его предварительно закрывают
процедурой Close.
Rename(FV, Str) – переименовать файл. Его новое имя дается переменной Str.
Truncate(FV) – уничтожить все компоненты файла, начиная с места текущего положения указателя,
и подготовить файл для записи.
Функции. Выполняют дополнительные действия,
существующих файлов.
облегчающие программисту обслуживание уже
Eof(FV) – проверить маркер “конец файла”. Значение функции равно True, если указатель файла
находится сразу за последним компонентом файла, и False в любом другом случае.
FileSize(FV) – определить длину файла. Функция возвращает целочисленное значение, равное
количеству компонентов файла. Размер файла берется из директория. Функция используется для того,
чтобы проверить, содержит файл информацию или является пустым.
IOResult(FV) – проверка результата выполнения последней операции на наличие ошибок. Функция
возвращает номер ошибки, если она обнаружена, и 0 – если ошибок нет.
�Оглавлен ие
СТАНДАРТНЫЕ ФАЙЛЫ
В языке Pascal все внешние устройства трактуются как логические устройства, которым
соответствуют заранее определенные (стандартные) файлы. Эти файлы фактически являются
драйверами, обеспечивающими операции ввода–вывода между процессором и конкретными
физическими устройствами. Используются следующие логические устройства:
Con: – (консоль) пульт управления. Для ввода – это клавиатура, для вывода – дисплей. Вводимая
информация отображается и может редактироваться. Непосредственно ввод осуществляется нажатием
клавиши “Ввод”.
Prn: – логическое имя принтера.
Aux: – вспомогательное устройство.
Nul: – логическое имя “пустого устройства”.
Для организации работы с логическими устройствами используются стандартные файлы. Система
сама открывает и закрывает эти файлы, поэтому к ним не применяются процедуры Assign, Flush,
Reset, Rewrite. В системе имена логических устройств и соответствующих им стандартных
файлов, за исключением основных файлов ввода–вывода, совпадают:
Input – основной файл для ввода. Назначается устройству Con.
Output – основной файл для вывода. Назначается устройству Con.
Con – назначается устройству Con, Aux – назначается устройству Aux,
устройству Nul, Prn – назначается устройству Prn.
Nul – назначается
�Оглавлен ие
ФАЙЛЫ ПОСЛЕДОВАТЕЛЬНОГО ДОСТУПА
Используются для решения задач, требующих поочередной обработки компонент файла. Работа с
последовательными файлами предполагает создание файла, его обработку и корректировку. Для
создания последовательного файла необходимо выполнить следующие шаги:
1) связать имя файла с файловой переменной (процедура Assign);
2) открыть новый файл (процедура Rewrite);
3) подготовить информацию для ввода;
4) записать в файл компоненты (процедура Write);
5) закрыть созданный файл (процедура Close).
Пример. Организовать последовательный файл с именем BIBL.DOC на дисководе А. Структура
записи следующая: порядковый номер книги; автор книги; название книги; индекс книги. Блок
организации оформить процедурой с именем Org. Значения полей ввести с клавиатуры. Признак
окончания ввода – число 99 в области номера.
Program Posled_File;
Type Books = Record
Nomer: integer;
Avtor: string[16];
Nazv: string[30];
Index: integer;
End;
Var BooksFile: File of Books;
RecBooks: Books;
I,Rej: integer;
Procedure Org;
{ Выход из процедуры – ответ 99 для поля Nomer }
begin
Assign(BooksFile, 'A:BIBL.DOC');
Rewrite(BooksFile);
with RecBooks do
while True do
begin
writeln('Введите номер книги'); readln(Nomer);
end;
if Nomer = 99 then begin Close(BooksFile); Exit
writeln('Введите имя автора'); readln(Avtor);
�Оглавлен ие
writeln(' Введите название книги'); readln(Nazv);
writeln(' Введите значение индекса'); read(Index);
write(BooksFile, RecBooks)
end;
end;
.......................
Доступ к компонентам последовательного файла. Чтобы обработать хранящиеся в файле данные,
необходимо получить доступ к компонентам файла. Для этого надо: 1) связать имя файла с файловой
переменной (процедура Assign); 2) открыть уже существующий на диске файл (процедура Reset); 3)
последовательно считать компоненты до нужного (процедура Read); 4) выполнить обработку; 5)
закрыть файл (процедура Close).
Пример
Вывести на экран содержание всех записей файла. Блок вывода оформить процедурой с именем Obr.
Procedure Obr;
begin
Assign(BooksFile, 'A:BIBL.DOC');
Reset(BooksFile);
with RecBooks do
while not Eof(BooksFile) do
begin
read(BooksFile, RecBooks);
writeln(Nomer:1, Avtor:16, Nazv:30, Index:6)
end;
Close(BooksFile)
end;
Корректировка последовательного файла. Возможны три вида корректировки: расширение файла
внесением дополнений, полная замена содержимого записи, корректировка значений полей
отдельных записей. Все три вида одинаково применимы и к последовательным, и к произвольным
файлам.
Рассмотрим технологию расширения файлов. Новые компоненты записываются сразу за последним
компонентом корректируемого файла. Расширение файла предполагает следующие шаги: 1) связать
имя файла с файловой переменной (процедура Assign); 2) открыть уже существующий на диске файл
(процедура Reset); 3) установить указатель файла за последним компонентом; 4) подготовить
информацию для нового компонента; 5) записать новый компонент (процедура Write); 6) закрыть
файл (процедура Close).
Для установки указателя за последним компонентом можно использовать следующую инструкцию:
Seek(FV, FileSize(FV)); которая значительно эффективнее и короче, чем поиск конца файла
�Оглавлен ие
путем перебора всех существующих в файле компонентов.
Пример
Расширить файл BIBL.DOC двумя новыми компонентами. Оформить блок корректировки процедурой с
именем Korr.
Procedure Korr;
begin
Assign(BooksFile, 'A:BIBL.DOC');
Reset(BooksFile);
Seek(BooksFile, FileSize(BooksFile));
with RecBooks do
while true do
begin
writeln('Введите номер');
readln(Nomer);
if Nomer = 99 then
begin
Close(BooksFile);
Exit
end;
writeln(' Введите имя автора');
readln(Avtor);
writeln(' Введите название книги');
readln(Nazv);
writeln(' Введите значение индекса');
readln(Index);
write(BooksFile, RecBooks);
end
end;
Объединив все процедуры, получим следующую программу:
Program Posled_File;
Uses Crt;
Type Books = Record
Nomer: integer;
Avtor: string[16];
�Оглавлен ие
Nazv: string[30];
Index: integer;
End;
Var BooksFile: File of Books;
RecBooks: Books;
I,Rej: integer;
Procedure Org;
{описание процедур}
<.........>;
Procedure Obr;
<.........>;
Procedure Korr;
<.........>;
Begin
while True do
begin
writeln('Укажите режимы: ');
writeln(' 1: Создание файла ');
writeln(' 2: Обработка файла ');
writeln(' 3: Расширение файла ');
writeln(' 4: Выход из программы ');
readln(Rej);
case Rej of
1: Org;
2: Obr;
3: Korr;
4: Halt
else writeln ('Повторите ввод')
end
end
End.
�Оглавлен ие
ФАЙЛЫ ПРОИЗВОЛЬНОГО ДОСТУПА
Организация файла произвольного доступа. Создаются для решения задач, требующих оперативного
доступа к хранимой информации или при наличии зависимости значения поля компонента от
порядкового номера компонента в файле. Работа с таким файлом предполагает его организацию,
обработку и корректировку. Организовать файл произвольного доступа можно двумя способами: 1)
создать последовательный файл и обращаться к компонентам по их порядковому номеру, трактуя
последовательный файл как произвольный; 2) создать файл фиктивных записей (например, пробелов
или нулей; это т.н. форматизация файла), затем загрузить его по ключу фактическими данными;
обращение к компонентам по ключу предполагает использование процедуры Seek. Рассмотрим 2–й
способ.
Пример
Форматизовать файл произвольного доступа из 10 записей. Формат компонентов такой же, как и в
предыдущем примере. Оформить блок как процедуру с именем Form.
Program Proizv_File;
Const Razmer = 10;
Type Books = Record
Nomer: integer;
Avtor: string[14];
Nazv: string[30];
Index: integer
End;
Var BooksFile: File of Books;
RecBooks: Books; k,K1: integer;
i,Rej: integer; FileName: string[12];
Procedure Form;
begin
writeln(' Введите имя форматируемого файла');
readln(FileName);
Assign(BooksFile, FileName);
Rewrite(BooksFile);
with RecBooks do
begin
for i:=1 to Razmer do
begin
Nomer:= 0;
{ если нужно, при форматизации сразу в запись заносится значение номера 1 .. i, можно записать Nomer:= i;}
�Оглавлен ие
Avtor:= ' '; Nazv:= ' '; Index:= 0;
write(BooksFile, RecBooks);
end
end;
writeln('Форматизация ', Razmer,' записей выполнено');
Close(BooksFile)
end;
После форматизации файла можно приступить к его загрузке по ключу фактической информацией,
которая заменит фиктивную.
Пример
Внести в файл BIBL2.DOC фактические записи с номерами 3, 7, 8. Оформить блок загрузки процедурой
с именем ZagrKl.
Procedure ZagrKl;
begin
writeln(' Введите имя загружаемого по ключу файла');
readln(FileName);
Assign(BooksFile, FileName);
Reset(BooksFile);
writeln('Сколько записей будете вводить?');
readln(k);
with RecBooks do
for i:= 1 to k do
begin
writeln(' Введите номер '); readln(Nomer);
K1:= Nomer; writeln(' Введите имя автора ');
readln(Avtor);
writeln(' Введите название книги ');
readln(Nazv);
writeln(' Введите индекс '); readln(Index);
Seek(BooksFile,K1–1);
write(BooksFile, RecBooks);
end;
Close(BooksFile);
end;
�Оглавлен ие
Доступ к компонентам файла. Может быть как последовательным, так и произвольным.
Последовательный уже описан. Для организации произвольного доступа используется процедура
Seek. Произвольный доступ организовывается по ключу, значение которого равно порядковому
номеру в файле нужного элемента. Ключ должен быть целочисленным, не превышающим количество
компонентов в файле. Порядок действий при обработке файлов произвольного доступа следующий: 1)
связать имя файла с файловой переменной (процедура Assign); 2) открыть файл (процедура Reset) и
запросить ключ; 3) подвести указатель по ключу к нужному компоненту (процедура Seek); 4) считать
нужный компонент (процедура Read); 5) выполнить обработку считанной информации; 6) закрыть
файл (процедура Close).
Пример. Вывести на экран 6–й и 7–й компоненты файла BIBL2.DOC. Блок вывода оформить
процедурой с именем ObrKl.
Procedure ObrKl;
begin
writeln(' Введите имя файла:'); readln(FileName);
Assign(BooksFile, FileName);
Reset(BooksFile);
while True do
begin
writeln('Дайте ключ выводимой записи:');
readln(K1);
if K1 = 99 then begin Close(BooksFile); Exit
end;
Seek(BooksFile, K1–1);
read(BooksFile, RecBooks);
with RecBooks do
writeln(Nomer:4, Avtor:16, Nazv:15, Index:4);
end
end;
Корректировка файла произвольного доступа. Заключается в изменении значений полей
компонентов в целом (или частично) или расширении файла. Для корректировки полей компонентов
файла необходимо: 1) связать имя файла с файловой переменной (процедура Assign); 2) открыть
корректируемый файл (процедура Reset); 3) подвести указатель файла к корректируемому компоненту
(Seek); 4) считать корректируемый компонент (процедура Read); 5) откорректировать нужные поля; 6)
повторить инструкцию подвода указателя (процедура Seek); 7) записать откорректированный
компонент (процедура Write); 8) закрыть файл (процедура Close).
Пример
Откорректировать «название книги» и «индекс книги» в рассмотренных выше примерах. Блок вывода
оформить процедурой с именем KorrKl.
Procedure KorrKl;
�Оглавлен ие
Var NewAvtor: string[16];
NewNazv: string[30];
NewIndex: integer;
begin
Write(' Введите имя файла:'); readln(FileName);
Assign(BooksFile, FileName);
Reset(BooksFile);
with RecBooks do
begin
Write('Сколько записей будете корректировать? ');
Readln(k);
for i:=1 to k do
begin
Write('Номер корректируемой записи:');
Readln(K1);
Write('Название книги: '); Readln(NewNazv);
Write('Индекс: '); Readln(NewIndex);
Seek(BooksFile, K1–1);
Read(BooksFile, RecBooks);
Avtor:= NewAvtor;
Nazv:= NewNazv;
Index:= NewIndex;
Seek(BooksFile, K1–1);
Write(BooksFile, RecBooks);
end;
end;
Close(BooksFile)
end;
Процедура корректировки полной записи аналогична описанной ранее (см. корректировка
последовательного файла), только новая запись вносится на место уже существующей, а не фиктивной.
Желательно при создании файла спроектировать файл такого размера, чтобы его по возможности не
расширять.
Все приведенные выше процедуры работы с файлом удобно объединить в одной программе. В этом
случае процедуры вызываются из основной программы путем указания номера нужного режима в
меню. После выполнения процедуры происходит возврат в основную программу.
�Оглавлен ие
Program Proizv_File;
Const Razmer = 20;
Type Books = Record
Nomer: integer;
Avtor: string[14];
Nazv: string[30];
Index: integer
End;
Var BooksFile: File of Books;
RecBooks: Books; k,K1: integer;
i,Rej: integer; FileName: string[12];
Procedure Form;
{описание процедур}
<.........>;
Procedure ZapKl;
<.........>;
Procedure ObrKl;
<.........>;
Procedure KorKl;
<.........>;
Begin
while True do
begin
Writeln('Укажите режимы: ');
Writeln(' 1: Форматизация ');
Writeln(' 2: Загрузка по ключу ');
Writeln(' 3: Обработка по ключу ');
Writeln(' 4: Корректировка ');
Writeln(' 5: Выход из программы ');
Readln(Rej);
case Rej of
1: Form;
2: ZagrKl;
3: Obrkl;
�Оглавлен ие
4: KorrKI;
5: Halt
else Writeln ('Повторите ввод')
end
end
End.
�Оглавлен ие
ТЕКСТОВЫЕ ФАЙЛЫ
Определение типа. Текстовый файл – это файл, состоящий из компонентов, являющихся строками.
Длина строки может меняться от 0 до 255. Каждая строка завершается маркером конца строки CR/LF
(код $0D/$0A), файл – маркером конца файла CTRL/Z (код $1A). Для описания файловых переменных
используется стандартный идентификатор Text.
Формат: Var
<идентификатор>: Text;
Приме р:
Var Instr1,Instr2: Text;
Dokument: Text;
�Оглавлен ие
ПРОЦЕДУРЫ И ФУНКЦИИ ОБРАБОТКИ ТЕКСТОВОГО ФАЙЛА
Assign(FV, Str) – связывает текстовый файл с файловой переменной;
Rewrite(FV) – открывает для создания новый текстовый файл;
Reset(FV) – открывает уже существующий текстовый файл;
Close(FV) – закрывает текстовый файл (при выполнении записывается маркер конца файла);
Append(FV) – открывает файл и устанавливает маркер на указатель конца файла;
Read(FV, Ch) – считывает символ Ch из файла FV;
Write(FV, Ch) – записывает символ Ch в файл FV;
Readln(FV, Str) – читает из файла FV строку Str;
Readln(FV) – переход на новую строку;
Writeln(FV, Str) – записывает в файл FV строку Str;
Writeln(FV) – записывает в файл пустую строку;
Eoln(FV) – возвращает True, если указатель файла достиг маркера конца строки. В противном случае
возвращает False;
SeekEoln(FV) – аналогична предыдущей, но указатель файла переходит все пробелы и знаки
табуляции;
SeekEof(FV) – возвращает значение True, если указатель файла находится на маркере конца файла.
Процедуру Readln(FV) используют, как правило, для подсчета количества компонентов в файле
St:= 0;
{обнуление счетчика}
while not Eof(FV) do begin
readln(FV);
{пропуск строки}
St:= St+1
{увеличение счетчика на 1}
end;
write('В файле находится ', St:4,' строк');
а процедуру Writeln(FV) – для создания строк–пробелов
for i:= 1 to 7 do writeln(FV);
Если файловая переменная FV не указана, по умолчанию подразумевается файл вывода на экран
Output.
Оpганизация текстового файла. Осуществляется таким образом: 1) объявляется файловая переменная
в качестве текстовой; 2) имя файла связывается с файловой переменной (процедура Assign); 3)
открывается файл для записи (процедура Rewrite); 4) подготавливается строка для записи (например,
вводится с клавиатуры); 5) записывается строка в файл (процедура Writeln); 6) закрывается файл
(процедура Close).
�Оглавлен ие
Пример:
Создать текстовый файл с произвольным именем и типом на дисководе А. Файл содержит строки
делового письма. Каждая строка состоит из не более чем 60 символов. Если значение строки равно
'kkk', то прекратить запись в файл. Оформить в виде процедуры с именем SozdT.
Program TextFiles;
Type Dlina = string[60];
Var Stro: Text; FileName: string[14];
S: Dlina;
Rej: char;
Procedure SozdT;
begin
write(' Введите имя создаваемого текстового файла ');
readln(FileName);
Assign(Stro, FileName); rewrite(Stro);
while True do
begin
readln(S);
if S='kkk' then
begin
Close(Stro);
Exit
end;
writeln(Stro, S)
{ Запись в файл }
end
end;
Доступ к компонентам текстового файла. Осуществляется таким образом: 1) связать имя файла с
файловой переменной (процедура Assign); 2) открыть файл для чтения (процедура Reset); 3)
прочитать компонент файла (оператор Readln); 4) обработать компонент (например, распечатать на
экране монитора); 5) закрыть файл (процедура Close).
Пример.
Распечатать все компоненты файла, созданного в предыдущем примере. Имя процедуры распечатки
ObrT.
Procedure ObrT;
begin
{$I–}
repeat
{Отмена контроля операций ввода–вывода}
�Оглавлен ие
write(' Введите имя выводного файла: ');
readln(FileName);
Assign(Stro, FileName);
reset(Stro);
until (IOResult = 0) or (FileName = 'kkk');
{$I+}
{Включение контроля операций ввода–вывода}
while not SeekEof(Stro) do
begin
readln(Stro, S); {Чтение из файла}
writeln(S);
end;
end;
Корректировка текстового файла. Заключается в расширении текстового файла новыми
компонентами. Для корректировки необходимо: 1) связать имя файла с файловой переменной
(процедура Assign); 2) открыть файл для внесения новых компонентов (процедура Append); 3)
записать новые компоненты (процедура Write); 4) закрыть файл (процедура Close).
Пример. Расширить ранее созданный файл новыми компонентами. Если значение строки равно
'kkk', прекратить запись. Имя процедуры расширения RasshT.
Procedure RasshT;
begin
{$I–}
{Отмена контроля операций ввода–вывода}
repeat
writeln('Имя корректируемого файла: '); readln(FileName);
Assign(Stro, FileName);
Append(Stro);
until IOResult = 0;
{$I+}
{Включение контроля операций ввода–вывода }
while True do
begin
writeln('Вводите строку'); readln(S);
if S = 'kkk' then begin Close(Stro); Exit; end;
writeln(Stro, S)
end
end;
Все приведенные выше процедуры работы с файлом объединим в одной программе. В этом случае
�Оглавлен ие
процедуры вызываются из основной программы путем указания номера нужного режима в меню.
После выполнения процедуры происходит возврат в основную программу.
Пример.
Объединить функциональные блоки по созданию, обработке и расширению текстовых файлов в одной
программе. Имя файла запрашивать у пользователя. Если при обработке и расширении указанный файл
на диске не найден, запросить имя заново.
Program TextFiles;
Uses Crt;
Type Dlina = string[60];
Var Stro: Text;
S: Dlina;
Rej: char;
Procedure SozdT;
{описание процедур}
<.........>;
Procedure ObrT;
<.........>;
Procedure RasshT;
<.........>;
Begin
while True do
begin
ClrScr; writeln('Укажите режим: ');
writeln(' 1: Создание текстового файла ');
writeln(' 2: Вывод текстового файла: ');
writeln(' 3: Расширение текстового файла: ');
writeln(' 4: Выход из программы: ');
read(Rej);writeln;
case Rej of
'1': SozdT;
'2': ObrT;
'3': RasshT;
'4': Halt;
�Оглавлен ие
else writeln('Повторите ввод режима');
end
end
End.
�Оглавлен ие
ФАЙЛЫ БЕЗ ТИПА
Файлы, не имеющие типа (нетипизированные), описываются с помощью зарезервированного слова
File.
Формат: Var <файловая переменная>: File;
Нетипизированные файлы считываются и записываются только блоками по 128 байт, для чего
используются специальные процедуры BlockRead и BlockWrite соответственно.
Формат: BlockRead(FV, Var, Count);
BlockWrite(FV, Var, Count);
или
BlockRead(FV, Var, Count, Result);
BlockWrite(FV, Var, Count, Result);
где FV – идентификатор файловой переменной, Var – переменная любого типа (обычно это массив),
Count – количество блоков по 128 байт, которое нужно считать или записать, Result – количество
блоков, которое было передано фактически. Размер Var должен быть больше или равен 128 Count.
Пример
Программа быстрого копирования файлов.
Program Untypped_File;
Var OldFile, NewFile: File;
OldName, NewName: string[14];
Oblbuf: array[1..128, 1..200] of byte;
Count: integer;
Begin
writeln('Дайте имя исходного файла '); readln(OldName);
Assign(OldFile, OldName);
Reset(OldFile);
writeln('Дайте имя выходного файла: '); readln(NewName);
Assign(NewFile, NewName); rewrite(NewFile);
repeat
BlockRead(OldFile, Oblbuf, 200, Count);
BlockWrite(NewFile, Oblbuf, Count);
until Count = 0;
Close(OldFile); Close(NewFile);
End.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
Вариант 1
1. Создать файл из 50 целых чисел, используя генератор случайных чисел. Вывести эти числа на
экран. Вывести на экран все числа из этого файла, оканчивающиеся на 7. Найти среднее
арифметическое всех чисел, входящих в созданный файл. Найти наименьшее из них.
2. Создать два упорядоченных файла целых чисел. Объединить их, создав новый упорядоченный
файл.
3. Создать текстовый файл. Подсчитать количество предложений в нем. Найти самое длинное слово.
Вариант 2
1. Создать файл из 55 целых чисел, используя генератор случайных чисел. Переписать все четные
числа из этого файла в другой. Вывести оба файла на экран. Найти в новом файле среднее
арифметическое его элементов. Найти наибольший элемент в новом файле.
2. Создать два упорядоченных по возрастанию файла: 1–й из четных чисел, 2 – из нечетных чисел.
3. Создать текстовый файл. Подсчитать количество знаков препинания в нем. Найти самое короткое
слово.
Вариант 3
1. Используя генератор случайных чисел, создать файл из 20 целых чисел, кратных 5. Вывести его на
экран. Найти среднее арифметическое этих чисел. Найти количество элементов, оканчивающихся
нулем. Найти наименьшее из них.
2. Создать два упорядоченных по убыванию файла. Объединить их в упорядоченный по убыванию
файл.
3. Создать текстовый файл. Убрать лишние пробелы. Вывести на экран слова, начинающиеся с буквы
“А”.
Вариант 4
1. С помощью датчика случайных чисел создать файл из 35 целых чисел. Вывести его на экран.
Найти наибольшее из чисел, оканчивающихся на 3. Посчитать числа, оканчивающиеся на 3. Найти
среднее арифметическое остальных чисел.
2. Создать два упорядоченных по убыванию файла. Объединить их в упорядоченный по
возрастанию файл.
3. Создать текстовый файл. Определить количество вопросительных предложений и количество
слов в первом предложении.
Вариант 5
1. С помощью датчика случайных чисел создать файл из 40 целых чисел. Вывести все четные числа,
встречающиеся в созданном файле. Посчитать их количество. Найти их среднее арифметическое.
Найти число, ближайшее к среднему арифметическому.
2. Создать два упорядоченных файла: один – по убыванию, другой – по возрастанию.
3. Создать текстовый файл. Зашифровать его, используя метод обратного чтения
�Оглавлен ие
Вариант 6
1. Создать файл из 20 вещественных чисел, выбранных случайным образом из отрезка [10..30].
Вывести его на экран. Найти наибольший и наименьший элементы в этом файле. Найти сумму всех
элементов файла.
2. Создать два упорядоченных файла: один – по не убыванию, другой – по не возрастанию.
Объединить эти файлы в новый, упорядоченный по убыванию.
3. Создать текстовый файл. Вывести его на экран. Вывести на экран последнее предложение.
Определить количество слов в нем.
Вариант 7
1. Создать файл из 30 вещественных чисел, выбранных случайным образом из отрезка [5, 8]. Вывести
его на экран. Найти среднее арифметическое его элементов. Найти все элементы, расстояние которых
от среднего арифметического не превышает 1 и записать их в новый файл. Найти наибольший среди
них.
2. Создать два упорядоченных по возрастанию файла. Объединить их в упорядоченный по
убыванию файл.
3. Создать текстовый файл. Вывести его на экран. Определить, есть ли в тексте слово “заряд”.
Вариант 8
1. Создать файл из 25 вещественных чисел, выбранных случайным образом из отрезка [10, 12].
Вывести файл на экран. Найти наибольший и наименьший элементы. Найти среднее арифметическое
первых 10 элементов.
2. Создать два файла. Первый по закону x n = 1/n, второй – yn = 1/(n+1). Объединить их в
упорядоченный по возрастанию файл.
3. Создать текстовый файл. Вывести его на экран. Поменять местами первое и последнее слово.
Вариант 9
1. Создать файл из 50 вещественных чисел, выбранных случайным образом из отрезка [1, 4]. Вывести
файл на экран. Найти наибольший элемент. Найти среднее арифметическое последних 15 чисел.
2. Создать два файла. Первый по закону x n = n2 , где n = 1..10, а второй – y = n2 + 1, где n = 1 .. 15.
Создать новый файл, упорядоченный по убыванию, путем слияния двух ранее созданных.
3. Создать текстовый файл. Вывести его на экран. Сколько в этом файле слов, оканчивающихся на
“м”.
Вариант 10
1. Создать файл из 25 вещественных чисел, выбранных случайным образом из отрезка [1, 8]. Вывести
файл на экран. Найти наименьший элемент. Найти среднее арифметическое всех элементов. Вывести
на экран все элементы, которые отличаются от среднего арифметического не более чем на 0.5.
2. Создать два файла. Первый – по правилу x n = 3n + 1, где n = 5..15, второй – n = 4..18. Создать
новый файл, упорядоченный по возрастанию, путем слияния двух созданных.
3. Создать текстовый файл. Вывести его на экран. Вывести на экран самое длинное предложение.
�Оглавлен ие
Вариант 11
1. Создать файл из 30 вещественных чисел, выбранных случайным образом из [1..5]. Вывести его на
экран. Найти наибольший элемент. Найти среднее арифметическое 18 последних чисел, среднее
арифметическое всех чисел.
2. Создать два файла. Первый – по правилу x n = n + 1, второй yn = 1 – 2n, где n = 1...20. Получить
новый файл, упорядоченный по возрастанию, путем слияния двух созданных.
3. Создать текстовый файл. Вывести его на экран. Вывести на экран предпоследнее предложение.
Вариант 12
1. Создать файл из 28 целых чисел, используя датчик случайных чисел из отрезка [30, 100]. Вывести
его на экран. Найти среднее арифметическое всех нечетных чисел. Найти наименьшее среди четных
чисел.
2. Создать два файла. Первый по правилу x n = (1 –2n)/n, где n = 1 .. 20, второй – y = 1/n, где n = 1 .. 10.
Создать новый файл, упорядоченный по убыванию, путем слияния двух созданных.
3. Создать текстовый файл. Вывести его на экран. Вывести на экран предложения, начинающиеся с
буквы “В”.
Вариант 13
1. Дан файл f, компоненты которого являются действительными числами. Найти: a) сумму компонент
файла f; b) произведение компонент файла f; c) сумму квадратов компонент файла f; d) модуль суммы и
квадрат произведения компонент файла f; e) последнюю компоненту файла.
2. Даны символьные файлы f и g. Определить, совпадают ли компоненты файла f с компонентами
файла g. Если нет, то получить номер первой компоненты, в которой файлы f и g отличаются между
собой.
3. Дан текстовый файл f. Получить все его строки, содержащие более 60 символов.
Вариант 14
1. Дан файл f, компоненты которого являются действительными числами. Найти: a) наибольшее из
значений компонент; b) наименьшее из значений компонент с четными номерами; c) наибольшее из
значений модулей компонент с нечетными номерами; d) сумму наибольшего и наименьшего из
значений компонент; e) разность первой и последней компонент файла.
2. Дан символьный файл f. Получить копию файла в файле g.
3. Дан текстовый файл f. Переписать в файл g все компоненты файла f с заменой в них символа 0 на
символ 1 и наоборот.
Вариант 15
1. Дан файл f, компоненты которого являются целыми числами. Найти: а) количество четных чисел
среди компонент; b) количество удвоенных нечетных чисел среди компонент; c) количество квадратов
нечетных чисел среди компонент.
2. Даны символьные файлы f 1 и f 2. Переписать с сохранением порядка следования компоненты
файла f в файл f 2, а компоненты файла f 2 – в файл f. Использовать вспомогательный файл h.
3. Дан текстовый файл f. Записать в перевернутом виде строки файла f в файл g. Порядок строк в
�Оглавлен ие
файле g должен a) совпадать с порядком исходных строк в файле f; b) быть обратным по отношению к
порядку строк исходного файла.
Вариант 16
1. Дан файл f, компоненты которого являются целыми числами. Получить в файле g все компоненты
файла f: a) являющиеся четными числами; b) делящиеся на 3 и не делящиеся на 7; c) являющиеся
точными квадратами.
2. Дан символьный файл f. Добавить в его конец символы e, n, d (если это необходимо, использовать
дополнительный файл g).
3. Дан текстовый файл f. Переписать компоненты файла f в файл g, вставляя в начало каждой строки
по одному пробелу. Порядок компонент должен быть сохранен.
Вариант 17
1. Дан файл f, компоненты которого являются целыми числами. Записать в файл g все четные числа
файла f, а в файл h – все нечетные. Порядок следования чисел сохраняется.
2. Дан символьный файл f. Подсчитать число вхождений в файл сочетаний ab. Определить, входит
ли в файл сочетание abcdefgh. Подсчитать число вхождений в файл каждой из букв a, b, c, d, e, f и
вывести результат в виде таблицы
a–N b–N c–N
d–N e–N f–N
3. Дан текстовый файл f. Получить самую длинную строку файла. Если в файле имеется несколько
строк с наибольшей длиной, то получить одну из них.
Вариант 18
1. Дан файл f, компоненты которого являются целыми числами. Ни одна из компонент файла не
равна нулю. Файл f содержит столько же отрицательных чисел, сколько и положительных. Используя
вспомогательный файл h, переписать компоненты файла f в файл g так, чтобы в файле g: a) не было
двух соседних чисел с одним знаком; b) сначала шли положительные, потом отрицательные числа; c)
числа шли в следующем порядке: два положительных, два отрицательных, два положительных, два
отрицательных и т.д. (предполагается, что число компонент в файле f делится на 4).
2. Дан символьный файл f. Записать в файл g компоненты файла f в обратном порядке.
3. Дан текстовый файл f. Исключить пробелы, стоящие в концах его строк. Результат поместить в
файл f .
Вариант 19
1. Дан файл f, компоненты которого являются целыми числами. Число компонент файла делится на
100. Записать в файл g наибольшее значение первых ста компонент файла f, затем – следующих ста
компонент и т.д.
2. Даны символьные файлы f и g. Записать в файл h все начальные совпадающие компоненты
файлов f и g.
3. Даны текстовый файл и строка s. Получить все строки файла f, содержащие в качестве фрагмента
строку s.
�Оглавлен ие
Вариант 20
1. Дан файл f, компоненты которого являются целыми числами. Получить файл g, образованный из
файла f исключением повторных вхождений одного и того же числа.
2. Сведения об автомобиле состоят из его марки, номера и фамилии владельца. Дан файл f,
содержащий сведения о нескольких автомобилях. Найти: a) фамилии владельцев и номера
автомобилей данной марки; b) количество автомобилей каждой марки.
3. Даны два текстовых файла f и g. Определить, совпадают ли компоненты файла f с компонентами
файла g. Если нет, то получить номер первой строки и позицию первого символа в этой строке, в
которых файлы f и g отличаются между собой.
Вариант 21
1. Прямая на плоскости задается уравнением ax + by + c = 0, где a и b одновременно не равны нулю.
Будем рассматривать только прямые, для которых коэффициенты a, b, c – целые числа. Пусть f – файл,
содержащий коэффициенты нескольких прямых (не менее трех). Требуется получить в файле g
коэффициенты всех различных прямых файла f.
2. Дан символьный файл f. Записать в файл g с сохранением порядка следования те символы файла f:
a) которым в этом файле предшествует буква 'a'; b) вслед за которым в этом файле идет буква 'a'.
3. Дан файл f, который содержит номера телефонов сотрудников учреждения: указывается фамилия
сотрудника, его инициалы и номер телефона. Найти телефон сотрудника по его фамилии и инициалам.
Вариант 22
1. Дан файл f, компоненты которого являются натуральными числами. Количество чисел в файле
кратно 4. Первые два числа из каждых четырех задают координаты левого верхнего угла
прямоугольника, следующие два числа – координаты его правого нижнего угла. Построить
прямоугольники, заданные в файле f.
2. Дан символьный файл f. В файле f не менее двух компонент. Определить, являются ли два первых
символа файла цифрами. Если да, то установить, является ли число, образованное этими цифрами,
четным.
3. Дан символьный файл f, содержащий произвольный текст длиной более 5000 слов. Слова в тексте
разделены пробелами и знаками препинания. Получить 100 наиболее часто встречающихся слов и
число их появлений. Решить задачу: a) без ограничения на длины слов; b) предполагая, что любое
слово текста состоит не более чем из 16 букв.
Вариант 23
1. Дан файл f, содержащий различные даты. Каждая дата – это число, месяц и год. Найти: a) год с
наименьшим номером; b) все весенние даты; в) самую позднюю дату.
2. Дан символьный файл f. Группы символов, разделенные пробелами (одним или несколькими) и
не содержащие пробелов внутри себя, будем называть словами. Найти самое длинное слово среди
слов, вторая буква которых есть e; если слов с наибольшей длиной несколько, то найти последнее.
Если таких слов нет вообще, то сообщить об этом. Решить эту задачу: а) полагая, что слова состоят не
более чем из 10 символов; b) без ограничения на число символов в слове.
3. Создать текстовый файл. Подсчитать количество знаков препинания в нем. Найти самое короткое
слово.
�Оглавлен ие
Вариант 24
1. Создать файл из 35 целых чисел с помощью датчика случайных чисел. Вывести его на экран.
Найти наибольшее из чисел, оканчивающихся на 5. Посчитать числа оканчивающиеся на 5. Найти
среднее геометрическое остальных чисел.
2. Дан файл f, содержащий сведения о веществах: указывается название вещества, его удельный вес и
проводимость (проводник, полупроводник, изолятор). Найти удельные веса и названия всех
полупроводников. Выбрать данные о проводниках и упорядочить их по убыванию удельных весов.
3. Дан символьный файл f, содержащий сведения о сотрудниках учреждения, записанные по
следующему образцу: фамилия_имя_отчество, фамилия_имя_отчество, ... Записать эти сведения в
файле g, используя образцы: а) имя_отчество_фамилия, имя_отчество_фамилия, ...; b) фамилия_и.о.,
фамилия_и.о., ...
Вариант 25
1. Дан файл f, компоненты которого являются целыми числами. Записать в файл g все четные числа
файла f, а в файл h – все нечетные. Порядок следования чисел сохраняется.
2. Сведения об ученике состоят из его имени, фамилии и названия класса (года обучения и буквы), в
котором он учится. Дан файл f, содержащий сведения об учениках школы. Выяснить, имеются ли в
школе однофамильцы. Выяснить, имеются ли однофамильцы в каких-либо параллельных классах.
Выяснить, имеются ли однофамильцы в каком-нибудь классе.
3. Дан файл f, содержащий сведения об экспортируемых товарах: указывается наименование товара,
страна, импортирующая товар, и объем поставляемой партии в штуках. Найти страны, в которые
экспортируется данный товар, и общий объем его экспорта.
Вариант 26
1. Создать файл из 20 вещественных чисел, выбранных случайным образом из отрезка [10..30].
Вывести его на экран. Найти наибольший и наименьший элементы в этом файле и их произведение.
2. Дан файл f, содержащий сведения о кубиках: размер каждого кубика (длина ребра в сантиметрах),
его цвет (красный, желтый, зеленый или синий) и материал (деревянный, металлический, картонный).
Найти: a) количество кубиков каждого из перечисленных цветов и их суммарный объем; b) количество
деревянных кубиков с ребром 3 см и количество металлических кубиков с ребром, большим 5 см.
3. Дан файл f, содержащий сведения о книгах. Сведения о каждой из книг – это фамилия автора,
название и год издания. Найти названия книг данного автора, изданных с 1960 г. Определить, имеется
ли книга с названием “Информатика”. Если да, то сообщить фамилию автора и год издания. Если таких
книг несколько, то сообщить имеющиеся сведения обо всех этих книгах.
Вариант 27
1. Создать файл из 55 целых чисел, используя генератор случайных чисел. Переписать все четные
числа из этого файла в другой. Вывести оба файла на экран. Найти в новом файле среднее
арифметическое его элементов. Найти наибольший элемент в новом файле.
2. Сведения об ученике состоят из его имени и фамилии и названия класса (года обучения и буквы), в
котором он учится. Дан файл f, содержащий сведения об учениках школы и дополнительно отметки,
полученные учениками в последней четверти. Выяснить, сколько учеников школы не имеют отметок
ниже четырех. Собрать в файле g сведения о лучших учениках школы, т.е. об учениках, не имеющих
�Оглавлен ие
отметок ниже четырех и по сумме баллов не уступающих другим ученикам своего и параллельных
классов.
3. Дан файл f, содержащий сведения об игрушках: указывается название игрушки (например, кукла,
кубики, мяч, конструктор и т.д.), ее стоимость в рублях и возрастные границы детей, для которых
игрушка предназначена (например, для детей от двух до пяти лет). Получить следующие сведения: a)
названия игрушек, цена которых не превышает 400 руб. и которые подходят детям 5 лет; b) цену самого
дорогого конструктора, оформленную по образцу ... руб.; c) названия наиболее дорогих игрушек (цена
которых отличается от цены самой дорогой игрушки не более чем на 100 руб.).
�Оглавлен ие
Лабораторная работа № 14
МОДУЛИ
Модули в Turbo Pascal появились в связи с необходимостью упрощения процесса разработки
сложных программ. Модуль является независимо компилируемой частью программы и представляет
собой мощный инструмент создания различных прикладных программ. Компилятор Turbo Pascal
размещает программный текст каждого модуля в отдельном сегменте памяти. Хотя максимальная
длина сегмента не может превышать 64 Кбайт, число одновременно открытых модулей ограничено
лишь объемом доступной памяти, что позволяет создавать достаточно большие программы.
Структура модуля выглядит следующим образом:
Unit <имя>;
INTERFACE
<интерфейсная часть>
IMPLEMENTATION
<исполняемая часть>
[ Begin
<инициирующая часть> ]
End.
Где
Unit – служебное слово, начинающее заголовок модуля;
<имя> – имя модуля (правильный идентификатор);
INTERFACE – служебное слово, начинающее интерфейсную часть модуля;
IMPLEMENTATION – служебное слово, начинающее исполняемую часть;
Begin – служебное слово, начинающее инициирующую часть (квадратные скобки означают, что эта
часть необязательна);
End – признак конца модуля.
Любая из перечисленных трех частей модуля может быть пустой.
Для правильной компиляции модуля его имя должно совпадать с именем файла на диске, в котором
этот модуль будет храниться. Если, например, модуль определен заголовком
Unit Complex;
то его текст должен быть сохранен в файле с именем Complex.pas. Имя модуля служит для его связи
с другими модулями и основной программой. Эта связь осуществляется специальным предложением
USES <список модулей>;
где Uses – служебное слово, <список модулей> – имена используемых модулей, перечисленные через
запятую. Например:
�Оглавлен ие
USES CRT, Graph, Complex;
Если в программе используются модули, то слово Uses должно открывать раздел описаний основной
программы или следовать сразу за служебным словом Interface в модуле.
Интерфейсная часть. В этой части содержатся объявления всех глобальных объектов модуля (типов,
констант, переменных и блоков), которые должны стать доступными основной программе и другим
модулям. При объявлении процедур и функций в интерфейсной части указывается только их заголовок,
например:
Unit Vect;
INTERFACE
Type vector = Record
x, y, z: real;
end;
Var a, b, c : vector; i: real;
Procedure Summa(var f,d,e: vector);
Procedure ProizvScal(var f,d: vector; var k: real);
Procedure ProizvVect(var f,d,e: vector);
Если теперь в основной программе будет записана строка
USES Vect;
то в ней станут доступными тип Vector и процедуры Summa, ProizvScal и ProizvVect.
Исполняемая часть. Содержит тела процедур и функций, объявленных в интерфейсной части. Здесь
же могут объявляться локальные для модуля объекты – вспомогательные типы, константы,
переменные, процедуры и т. д. Ранее объявленные процедуры и функции должны быть описаны в той
же последовательности, в какой их заголовки записаны в интерфейсной части. Описанию глобального
блока в исполняемой части должен предшествовать заголовок, в котором разрешается опускать список
формальных переменных (и тип результата для функции), поскольку они уже описаны в интерфейсной
части.
Инициирующая часть. Она может отсутствовать вместе с начинающим ее словом Begin или быть
пустой. В эту часть помещают исполняемые операторы, содержащие некоторый фрагмент программы.
Эти операторы исполняются до передачи управления основной программе и обычно используются
для подготовки ее работы. В инициирующей части, например, могут открываться необходимые файлы,
устанавливаться значения переменных и т.д.
КОМПИЛЯЦИЯ МОДУЛЕЙ.
В Turbo Pascal определены три режима компиляции: COMPILE, MAKE и BUILD. Они отличаются
только способом связи компилируемого модуля или основной программы с другими модулями,
объявленными в предложении USES.
При компиляции в режиме COMPILE все упоминающиеся в предложении USES модули должны быть
предварительно откомпилированы и результаты их компиляции помещены в одноименные файлы с
расширением TPU. Например, если в программе (или модуле) есть строка
�Оглавлен ие
USES Vect;
то на диске в каталоге, объявленном опцией UNIT DIRECTORIES, уже должен быть файл VECT.TPU.
Такой файл создается в результате компиляции самого модуля.
В режиме MAKE компилятор проверяет наличие TPU–файлов для каждого объявленного модуля. Если
какой-либо из файлов не обнаружен, система пытается отыскать одноименный файл с расширением
PAS (то есть файл с исходным текстом модуля) и приступает к его компиляции. В этом режиме система
следит за возможными изменениями исходного текста любого используемого модуля. Если внесены
какие-либо изменения в исходный текст модуля, то, независимо от того, есть ли уже соответствующий
TPU-файл или нет, система осуществляет его компиляцию перед компиляцией основной программы.
Если внесены изменения в интерфейсную часть модуля, то будут перекомпилированы также и все
другие модули, обращающиеся к нему.
В режиме BUILD существующие TPU-файлы игнорируются, а система ищет и компилирует
соответствующие PAS-файлы для каждого из объявленных модулей. После компиляции в этом режиме
можно быть уверенным, что учтены все изменения, сделанные в любом из модулей.
Пример
В качестве примера создадим модуль, реализующий операции над векторами в координатной форме
(сложение векторов, их скалярное и векторное произведение).
Unit Vect;
INTERFACE
Type vector=Record
x,y,z: real;
end;
Var a, b, c : vector; i: real;
Procedure Summa(var f,d,e: vector);
Procedure ProizvScal(var f,d: vector; var k: real);
Procedure ProizvVect(var f,d,e: vector);
IMPLEMENTATION
Procedure Summa;
Begin
e.x:=f.x+d.x;
e.y:=f.y+d.y;
e.z:=f.z+d.z;
End;
Procedure ProizvScal;
Begin
k:= f.x*d.x+f.y*d.y+f.z*d.z;
End;
�Оглавлен ие
Procedure ProizvVect;
Begin
e.x:=f.y*d.z-f.z*d.y;
e.y:=f.z*d.x-f.x*d.z;
e.z:=f.x*f.y-f.y*d.x;
End;
END.
Текст этого модуля необходимо сохранить в файле с именем VECT.PAS. После этого можно написать
такую, например, программу:
Program PrimerModul;
Uses Vect;
Var a,b,c: vector;
BEGIN
Writeln('Введите координаты вектора а');
With a do
Readln(x,y,z);
Writeln('Введите координаты вектора b');
With b do
Readln(x,y,z);
Summa(a,b,c);
Writeln('Сумма векторов a и b равна', c.x: 2, c.y: 2, c.z: 2);
ProizvScal(a,b,i);
Writeln('Скалярное произведение векторов a и b равно ', i: 2);
ProizvVect(a,b,c);
Writeln('Векторное произведение векторов a и b равно ', c.x: 2,
c.y: 2, c.z: 2);
readln;
END.
Стандартные модули. В Turbo Pascal имеется восемь стандартных модулей, в которых
содержится большое число разнообразных типов, констант, процедур и функций. Эти модули имеют
имена SYSTEM, DOS, CRT, PRINTER, GRAPH, OVERLAY, TURBO3 и GRAPH3. Модули GRAPH,
TURBO3 и GRAPH3 содержатся в одноименных TPU-файлах, остальные входят в состав библиотеки
TURBO.TPL. Модуль SYSTEM подключается ко всем паскалевским программам автоматические,
остальные доступны лишь после их объявления в списке USES.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ.
Создайте модуль, содержащий процедуры обработки файлов различных типов (см. предыдущую
лабораторную работу). Напишите короткую программу с использованием этого модуля.
�Оглавлен ие
Лабораторная работа № 15
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
До сих пор мы имели дело с такими переменными, которые описывались в разделе Var какого-либо
блока программы. Транслятор после анализа этого раздела отводит каждой переменной
соответствующее число ячеек памяти и закрепляет их за данной переменной на все время работы
блока. Такие переменные называют статическими. Они не могут быть использованы системой под
другие нужды, даже если в процессе работы программы эти переменные больше не понадобятся.
Данные могут быть организованы и другим образом. Их можно хранить в некоторой области памяти,
не обозначая именем переменной, а используя ссылку на эту область, – аналогично тому, как иногда
"обозначают" зрителя: "человек с 5-го ряда, 3-го места".
Такой вид доступа позволяет динамически захватывать и освобождать память в процессе работы блока
программы. Поэтому и сами переменные, которые могут создаваться и ликвидироваться по мере
надобности, называют динамическими.
Рассмотрим подробнее работу с динамическими переменными, которые чаще всего реализуются как
связанные структуры.
Проиллюстрируем особенности такой связанной структуры на примере очереди приема к врачу.
Каждый пациент запоминает человека, за которым занял очередь. Все пациенты связаны в цепочку
согласно очереди, но в пространстве они размещены произвольным образом: т.е. соседние элементы
очереди могут располагаться в пространстве произвольно.
Подобным образом строится структура связанных данных, которые могут занимать память не подряд, а
размещаться там, где есть свободное место. Каждый элемент такой структуры должен "знать", за кем он
"стоит", т.е. содержать ссылку на предыдущий элемент цепочки.
Чтобы проиллюстрировать преимущества динамических переменных, продолжим аналогию с
очередью пациентов.
Пусть один из пациентов покидает очередь. Этот процесс не требует перемещения в пространстве
остальных пациентов: просто стоящий за ушедшим теперь запоминает другого человека. Т.е.
исключение элемента из цепочки данных сводится к изменению одной-единственной ссылки и не
требует перемещения остальных элементов, как это имело бы место для массива.
На рис. 1. показано исключение элемента цепочки.
Исключенный элемент теперь можно освободить от участия в работе блока и использовать
занимаемый им участок памяти для других целей.
С помощью ссылок легко вставить новую компоненту в цепочку данных. Для этого достаточно
изменить две ссылки (рис. 2).
�Оглавлен ие
Новая динамическая компонента может быть размещена в любом свободном месте памяти,
отведенном под такие переменные. Сама динамическая переменная не обозначается
идентификатором. Динамическая переменная – это "невидимка" в программе: идентификатором она не
обозначается, транслятор ей место в памяти не отводит. Память под такую переменную резервируется
и освобождается динамически в процессе счета (с помощью специальных процедур).
Обращение к динамической переменной происходит посредством ссылочной переменной, которая
содержит адрес соответствующей динамической переменной.
Под ссылочную переменную транслятор отводит место в памяти машины; эта переменная имеет имя и
явно упоминается в программе.
Ссылочные переменные образуют новый тип данных – "ссылки" (указатели).
Динамические переменные, как правило, имеют тип "запись" (Record), т.к. должны содержать,
помимо значения (целого, вещественного и т.п.), ссылку на другую динамическую переменную
связанной структуры.
Пусть в памяти машины имеется динамическая переменная, содержащая поле целого значения 2 и
поле ссылки (указатель) на другую компоненту связанной структуры (цепочки):
Адрес данной переменной (ссылки) содержится в ссылочной переменной R:
Обозначим тип ссылочной переменной через Point, а тип динамической переменной – через DT.
Тогда этот факт описывается следующим образом:
Type
Point = ^ DT;
Говорят, что "тип Point указывает (ссылается) на компоненты типа DT" или "тип Point связан с
типом DT".
Ссылочную переменную R можно описать двумя способами:
a)
Type Point = ^ DT;
�Оглавлен ие
Var R: Point;
либо
b)
Var R: ^ DT;
Переменная R указывает на компоненты типа DT.
Чтобы связать динамические переменные в цепочку, надо в каждой компоненте иметь ссылку на
предыдущую компоненту. Например, компоненты, содержащие числа 5, 10, 15, 8, должны иметь еще
информацию о том, где находится предыдущий элемент, т.к. это не массив и компоненты размещаются
не обязательно подряд
Опишем тип таких данных, обозначив его DT. Очевидно, этот тип есть "запись" с двумя полями: полем
целого значения (I) и полем ссылки (P)
Type DT = Record
I: Integer;
P: Point;
End;
Очевидно, ссылочная переменная, указывающая на такого типа данные, должна иметь тот же тип
Point. Опишем этот тип:
Type Point = ^ DT;
Как видим, возник порочный круг: для описания типа Point привлекается понятие DT, а при
описании типа DT необходимо использовать Point.
Условились в этом случае сначала описывать тип ссылочной переменной, а затем уже тип
компоненты:
Type
Point = ^ DT;
DT = Record
I: Integer
End;
Правила языка Pascal только при описании ссылок допускают использование идентификатора (DT)
до его описания; во всех остальных случаях, прежде чем упомянуть идентификатор, необходимо
описать его тип.
Рассмотрим схему образования цепочки динамических данных, содержащих числа 5, 10:
ЭВМ необходимо произвести следующие действия:
1. Найти и зарезервировать место в памяти для компоненты:
�Оглавлен ие
2. Заслать ссылку на эту компоненту (адрес) в ссылочную переменную R:
3. Присвоить полю I значение 5:
4. Присвоить некоторой ссылочной переменной Q значение R (скопировать):
5. Найти и зарезервировать место в памяти для новой компоненты:
6. Заслать в переменную R адрес этой компоненты:
7. Заслать в поле I значение 10:
8. Заслать в поле P значение Q:
Последовательность таких действий создает цепочку динамических переменных. Для резервирования
места в памяти под динамическую переменную и засылки этого адреса в ссылочную переменную R
используют процедуру NEW (R). При этом выделяется столько ячеек памяти, сколько требует
динамическая переменная, с которой связана R. Все эти данные система получает из раздела описания
типов в программе. Динамические переменные, созданные посредством процедуры NEW(R),
называют также указанными переменными (указатель R).
Пусть переменная R имеет тип Point, описанный выше. Тогда после обращения к процедуре NEW(R)
будет создана указанная переменная, в которой предусмотрено поле под значение типа Integer и
поле ссылки. При этом ссылочная переменная R содержит адрес указанной переменной. Через R^
обозначается сама указанная переменная; R^.I – поле целого значения; R^.P – поле ссылки P:
�Оглавлен ие
ОПЕРАЦИИ НАД ССЫЛОЧНЫМИ ПЕРЕМЕННЫМИ
Значение ссылочной переменной R можно присваивать другой ссылочной переменной того же типа.
Пусть Q, R: ^ Point; тогда оператор Q:= R; зашлет в Q тот же адрес, что хранится в R.
Рассмотрим действия со ссылочными переменными на следующей схеме. Пусть Q и R указывают на
различные компоненты динамических переменных типа C:
C = Record
I: Integer;
P: Point
End;
Пусть в памяти ЭВМ размещены две цепочки динамических переменных (Рис. 3).
Выполним один из четырех операторов:
Q:= R;
Q^:= R^;
Q^.I:= R^.I;
Q^.P:= R^.P;
a) После выполнения оператора Q:= R; переменная Q указывает на ту же динамическую переменную,
что и R;
b) После выполнения оператора Q^:= R^; из исходного состояния (Рис. 3.) получим
На место указанной переменной
указывавшей на 30, заслана переменная
�Оглавлен ие
указывающая на 25.
c) После выполнения оператора Q^.I:= R^.I; из исходного состояния (Рис. 3.) получим следующее:
На место целого значения 20 заслано значение 15; поле указателя не изменилось.
d) После выполнения оператора Q^.P:= R^.P; из исходного состояния получим:
На место ссылки на компоненту 30 заслана ссылка на компоненту 25, поле целого значения не
изменилось.
Ссылочные переменные могут указывать на одну и ту же переменную, т.е. быть равными, как R и Q в
случае a).
Ссылочные переменные можно сравнивать посредством операций = и <>. Логическое выражение Q =
R имеет значение True для случая a) и значение False для случаев b) и c), т.к. для b) ссылочные
переменные Q и R указывают на разные динамические переменные, имеющие равные значения.
В качестве аналога нуля для ссылочных переменных принято специальное значение Nil. Если
переменная имеет значение Nil, то это означает, что она не указывает ни на какую переменную.
Значение Nil в поле указателя имеет всегда первая компонента цепочки динамических переменных.
Пример
Значение Nil можно заслать оператором присваивания: L:= Nil; если L = Nil, то цепочка пуста.
Чтобы определить, что данный элемент является первым в цепочке переменных, достаточно
проверить на Nil значение поля указателя этой переменной.
Пример
If L^.P = Nil then . . .
Замечание. Попытка обратиться к указанной переменной с указателем, имеющим значение Nil,
приводит к ошибке. Диагностика при этом не всегда выдается.
Динамическая переменная, созданная процедурой New, может быть "стерта" только процедурой
Dispose. Общий вид:
�Оглавлен ие
Dispose (R);
Здесь R – ссылочная переменная, указывающая на ту динамическую переменную, которую следует
стереть. После стирания динамической переменной R^ нельзя использовать значение R, такая ошибка
может привести к порче памяти и другим серьезным последствиям.
Динамические переменные, не стертые посредством Dispose, продолжают занимать место в памяти
после окончания работы соответствующего блока программы (становятся "мусором"). Поэтому
необходимо все лишние динамические переменные стереть перед окончанием работы блока.
Процедуры и функции управления динамической памятью приведены в таблице 1.
Таблица 1
Процедуры и функции
Назначение
New (Var P: Pointer);
Отводит место для хранения динамической переменной P^ и присваивает
ее адрес ссылке P.
Dispose (Var P: Pointer);
Уничтожает связь, созданную ранее New, между ссылкой P и значением,
на которое она ссылалась.
GetMem (Var P: Pointer; Size: Отводит место в Size байт в динамической памяти (куче), присваивая
Word);
адрес его начала указателю (ссылке) P.
FreeMem (Var P: Pointer; Size: Освобождает Size байт в куче, начиная с адреса, записанного в указателе
Word);
(ссылке) P.
Mark (Var P: Pointer);
Запоминает в указателе P текущее состояние кучи.
Release (Var P: Pointer);
Возвращает кучу в состояние, запомненное ранее в P вызовом процедуры
Mark (P).
MaxAvail: LongInt;
Возвращает длину (в байтах) самого длинного свободного участка памяти
в куче.
MemAvail: LongInt;
Возвращает сумму длин всех свободных участков памяти (в байтах).
Динамические переменные чаще всего реализуются как связанные структуры: списки.
Списком называется упорядоченная структура, каждый элемент которой содержит ссылку,
связывающую его со следующим элементом.
Для организации списков используются записи, состоящие из смысловых частей: основной и
дополнительной. Основная часть содержит подлежащую обработке информацию, в дополнительной
находится указатель на следующую запись списка.
Начало списка указывается в переменной, которая всегда присутствует в программе обработки
списков. Если в списке нет элементов, т.е. список пустой, значение этой переменной равно Nil. Если
список не заполнен, последний элемент содержит в дополнительной части значение Nil.
Наибольшее распространение получили два вида списков – стеки и очереди.
Стек ("магазин") – это список с одной точкой доступа к его элементам, которая называется вершиной
списка. Добавить или убрать элемент можно только через его вершину. Принцип работы стека:
"последний пришел – первый вышел".
�Оглавлен ие
Пример.
Пусть в трубку с запаянным концом закатывают шарики.
Извлекать их можно только в обратном порядке: тот шарик, что закатился последним, будет извлечен
первым.
Рис. 4.
Стек состоит из переменного числа компонент одинакового типа.
Основные операции над стеком: формирование стека, добавление, удаление и просмотр элементов
стека. Для их демонстрации используем описание:
Type
StackP = ^ StackComp;
StackComp = Record
I : Integer;
Next: StackP;
End;
Var
Top, Kon, NewElement: StackP;
Value: Integer;
Организация стека:
Procedure OrgS;
Begin
Top:= Nil;
While True do
begin
read (Value);
if Value = 999 then Exit;
{Ввод элементов прекращается,}
New (Kon);
если введено значение 999}
Kon^.Next:= Top;
Kon^.I:= Value;
Top:= Kon
end
End;
Добавление элементов в стек:
�Оглавлен ие
Procedure DobS;
With NewElement do
Begin
begin
While True do
Next:= Top;
begin
I:= Value;
read (Value);
end;
if Value = 999 then Exit;
New (NewElement);
NewElement^.Next:= Top;
NewElement^.I:= Value;
Top:= NewElement
end
end;
Удаление элементов из стека:
Procedure Out_St(Var K: Integer);
Var
Procedure Out_St;
begin
IOld: StackP;
begin
Top:= Top^.Next
end;
IOld:= Top;
K:= IOld^.I;
Top:= IOld^.Next;
Dispose (IOld)
end;
Просмотр элементов стека:
Procedure ProsS;
begin
Kon:= Top;
While Kon <> Nil do
begin
Writeln (Kon^.I)
Kon:= Kon^.Next
end
end;
{ вывод элементов в обратном порядке }
�Оглавлен ие
Замечание: Пустым стеком называется стек, не содержащий компонент. Такой стек можно получить,
присвоив значение Nil соответствующей ссылочной переменной (в нашем случае Top:= Nil;).
Нельзя применять процедуру Out к пустому стеку.
Стеки позволяют гибко и экономно использовать память, т.к. в каждый момент в стеке могут
находиться только те переменные, которые нужны для дальнейшей работы программы.
Другим видом списка является очередь. Очередь – это структура данных, в один конец которой
добавляются элементы, а с другого – изымаются. Принцип работы очереди: "первый пришел – первый
вышел". В этом случае вводят два указателя: один на начало очереди, другой – на ее конец.
Назовем их соответственно Left и Right.
При добавлении элемента в очередь он располагается в памяти в соответствии со значением Right, а
значение Right изменяется и указывает на следующее свободное место памяти.
Выборка элемента из очереди происходит исходя из значения N, которое изменяется и указывает на
следующий элемент очереди. Очевидно, что, когда очередь пуста, значение Right равно значению
Left.
Операции над очередью те же, что и над стеком. Для их демонстрации используем описание:
Type
StackP = ^StackComp;
StackComp = record
I: Integer;
Next: StackP;
end;
Var
Pp, Top, Kon: StackP;
NewElement, Left, Right: StackP;
Value: Integer;
Организация очереди:
Procedure OrgO;
begin
read (Value);
if Value = 999 then Exit;
New (Kon);
Kon^. Next:= Nil;
Kon^. I:= Value;
Right:= Kon; Left:= Kon;
While True do
�Оглавлен ие
begin
read (Value);
if Value = 999 then Exit;
New (Kon);
Kon^. Next:= Left;
Kon^. I:= Value;
Left:= Kon
end
end;
Добавив в раздел операторов инструкцию Right^. Next = Left;, получим замкнутый,
кольцеобразный список, в котором и Right, и Left можно равнозначно принимать за начало списка.
Добавление элементов в очередь:
Procedure DobO;
begin
read (Value);
if Value = 999 then Exit;
New (NewElement);
Right^. Next:= NewElement;
NewElement^. Next:= Nil;
NewElement^. I:= Value;
Right:= NewElement
end;
Удаление элементов из очереди:
Procedure OutO;
begin
Left:= Left^. Next;
end;
Просмотр элементов очереди:
Procedure ProsO;
begin
Pp:= Left;
While Pp <> Nil do
begin
Write (Pp^. I : 3
�Оглавлен ие
Pp:= Pp^. Next
end
end;
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Описать процедуру, которая по списку L строит два новых списка: L1 – из положительных
элементов и L2 из остальных элементов списка L (тип элементов – Real).
2. Описать процедуру, которая вставляет в начало списка L элемент E.
3. Описать процедуру, которая вставляет в конец списка L элемент E.
4. Описать процедуру, которая вставляет новый элемент E после первого элемента непустого списка L.
5. Описать процедуру, которая вставляет в список L новый элемент E1 за каждым вхождением
элемента E.
6. Описать процедуру, которая вставляет в список L новый элемент E1 перед первым вхождением
элемента E, если E входит в L.
7. Описать процедуру, которая вставляет в непустой список L пару новых элементов E1 и Е2 перед его
последним элементом.
8. Описать процедуру, которая вставляет в непустой список L, элементы которого упорядочены по
неубыванию, новый элемент E так, чтобы сохранилась упорядоченность (тип элементов – Real).
10. Описать процедуру, которая удаляет из непустого списка L первый элемент.
11. Описать процедуру, которая удаляет из списка L второй элемент, если такой есть.
12. Описать процедуру, которая удаляет из списка L за каждым вхождением элемента E один элемент,
если такой есть, и он отличен от E.
13. Описать процедуру, которая удаляет из непустого списка L последний элемент.
14. Описать процедуру, которая удаляет из списка L первый отрицательный элемент, если такой есть
(тип элементов – Real).
15. Описать процедуру, которая удаляет из списка L все отрицательные элементы (тип элементов –
Real).
16. Заданный во входном файле текст (за ним следует точка) распечатать в обратном порядке.
17. Дана непустая последовательность натуральных чисел, за которой следует 0. Напечатать
порядковые номера тех чисел последовательности, которые имеют наибольшую величину.
18. Дано целое число n > 1, за которым следует n вещественных чисел. Напечатать эти числа в порядке
их неубывания.
19. Описать процедуру или функцию, которая проверяет на равенство списки L1 и L2.
20. Описать процедуру или функцию, которая определяет, входит ли список L1 в список L2.
21. Описать процедуру или функцию, которая проверяет, есть ли в списке L хотя бы два одинаковых
элемента.
22. Описать процедуру или функцию, которая переносит в конец непустого списка L его первый
элемент.
23. Описать процедуру или функцию, которая переносит в начало непустого списка L его последний
элемент.
�Оглавлен ие
24. Описать процедуру или функцию, которая добавляет в конец списка L1 все элементы списка L2.
25. Описать процедуру или функцию, которая вставляет в список L за первым вхождением элемента E
все элементы списка L1, если E входит в L.
26. Описать процедуру или функцию, которая переворачивает список L, т.е. изменяет ссылки в этом
списке так, чтобы его элементы оказались расположенными в обратном порядке.
27. Описать процедуру или функцию, которая в списке L из каждой группы подряд идущих равных
элементов оставляет только один.
28. Описать процедуру или функцию, которая оставляет в списке L только первые вхождения
одинаковых элементов.
29. Описать рекурсивную функцию или процедуру, которая определяет, входит ли элемент E в список
L.
30. Описать рекурсивную функцию или процедуру, которая подсчитывает число вхождений элемента
E в список L.
31. Описать рекурсивную функцию или процедуру, которая находит максимальный элемент непустого
списка L (тип элементов – Real).
32. Описать рекурсивную функцию или процедуру, которая печатает в обратном порядке элементы
списка L (тип элементов – Char).
33. Описать рекурсивную функцию или процедуру, которая заменяет в списке L все вхождения Е1 на
Е2.
34. Описать рекурсивную функцию или процедуру, которая удаляет из списка L первое вхождение
элемента E, если такое есть.
35. Описать рекурсивную функцию или процедуру, которая удаляет из списка L все вхождения
элемента E.
36. Описать рекурсивную функцию или процедуру, которая создает L1 – копию списка L.
37. Описать рекурсивную функцию или процедуру, которая удваивает каждое вхождение элемента E в
список L.
38. Описать рекурсивную функцию или процедуру, которая находит среднее арифметическое всех
элементов непустого списка L (тип элементов – Real).
39. Описать процедуру, которая формирует список L, включив в него по одному разу элементы,
которые входят хотя бы в один из списков L1 и L2.
40. Описать процедуру, которая формирует список L, включив в него по одному разу элементы,
которые входят одновременно в оба списка L1 и L2.
41. Описать процедуру, которая формирует список L, включив в него по одному разу элементы,
которые входят в список L1, но не входят в список L2.
42. Описать процедуру, которая формирует список L, включив в него по одному разу элементы,
которые входят в один из списков L1 и L2, но в тоже время не входят в другой из них.
43. Описать процедуру, которая объединяет два упорядоченных по неубыванию списка L1 и L2 (тип
�Оглавлен ие
элементов – Real) в один новый упорядоченный по неубыванию список L.
44. Описать процедуру, которая объединяет два упорядоченных по неубыванию списка L1 и L2 (тип
элементов – Real) в один упорядоченный по неубыванию список, меняя соответствующим образом
ссылки в L1 и L2 и присвоив полученный список параметру L1.
�Оглавлен ие
Лабораторная работа № 16
ПРОЦЕДУРЫ ПОДГОТОВКИ К РАБОТЕ В ГРАФИЧЕСКОМ РЕЖИМЕ
При работе с библиотекой графического модуля Graph необходимо в программе после служебного
слова Uses указать имя этого модуля:
Uses Graph;
Модуль Graph представляет собой библиотеку программ, обеспечивающую полное управление
графическими режимами различных адаптеров дисплеев.
Все процедуры и функции модуля Graph можно разбить на функциональные группы:
1. Управление графическими режимами и их анализ.
2. Рисование графических примитивов и фигур:
a) управление «текущим указателем»;
b) собственно рисование;
c) стиль линий и коэффициент сжатия изображения.
3. Управление цветами и шаблонами заполнения.
4. Битовые операции.
5. Управление страницами.
6. Графические окна.
7. Управление выводом текста.
Любая программа, использующая графику, обязательно должна содержать блок вызовов процедур
инициализации (установления в исходное состояние) графического режима и обращение к процедуре
его закрытия.
Процедура инициализации имеет вид:
InitGraph (Var GraphDriver: Integer;
Var GraphMode:
DriverPath:
Integer;
String);
{тип адаптера}
{режим графики}
{путь к драйверу}
В модуле Graph определены константы для задания вида графического адаптера параметром
GraphDriver перед вызовом InitGraph
Const
Detect = 0;
{для автоматического выбора адаптера}
CGA = 1;
{адаптер CGA}
MCGA = 2;
{адаптер MCGA}
EGA = 3;
{адаптер EGA 256 k}
EGA64 = 4;
{адаптер EGA 64 k}
�Оглавлен ие
EGAMono = 5;
{адаптер EGA c монодисплеем}
IBM8514 = 6;
{адаптер 8514}
HercMono = 7;
{адаптер Hercules}
ATT400 = 8;
{адаптер для ПЭВМ AT&T}
VGA = 9;
{адаптер VGA}
PC3270 = 10;
{адаптер 3270}
Current Driver = - 128;{для GetMode Range}
Если параметру GraphDriver присвоить значение константы Detect, то система включится в
режим автоопределения. Если возможно переключение системы в графический режим, то
инициализируется соответствующий BGI-драйвер и включается режим с максимальным разрешением.
В параметрах GraphDriver и GraphMode при этом будут возвращены автоматически выбранные
значения или код ошибки. Если же параметр GraphDriver содержит номер конкретного адаптера, то
и второй параметр, GraphMode, должен иметь значение (номер) режима, допустимого при этом
адаптере.
Все остальные графические установки (положение текущего указателя, палитра, цвет, параметры
графического окна) при инициализации принимаются по умолчанию.
Параметр PathDriver указывает путь в каталог, содержащий файлы с необходимыми драйверами.
Если в него передается значение '' (пустая строка), то драйверы должны находиться в текущем
каталоге.
Простейший блок инициализации графического режима в программе может выглядеть так:
Uses Graph;
{подключен модуль Graph}
Procedure GrInit;
{инициализация режима графики}
Var
GraphDriver: Integer;
{для графического адаптера}
GraphMode: Integer;
{для графического режима}
ErrorCode: Integer;
{для кода ошибки}
Begin
GraphDriver:= Detect;
{режим автоопределения}
InitGraph (GraphDriver, GraphMode, '');
{инициализация}
ErrorCode:= GraphResult;
{результат инициализации}
if ErrorCode <> grOk then
{если не успешно, то ...}
begin
Writeln ('Ошибка графики:');
GraphErrorMsg (ErrorCode);
Writeln ('Программа остановлена');
Halt (1)
�Оглавлен ие
end
{if}
end;
{= пример инициализации =}
Begin
GrInit;
{вызов процедуры инициализации}
Line (0, 0, GetMaxX, GetMaxY);
{работа с графикой ...}
Readln;
{пауза до нажатия клавиши ввода}
CloseGraph
{закрытие графического режима}
End.
Для окончательного завершения работы в графическом режиме необходимо всегда производить вызов
процедуры CloseGraph. Эта процедура не имеет параметров. Она очищает экран, переводит экран в
текстовый режим. Последующий возврат в графический режим возможен только через повторную
инициализацию.
Процедура InitGraph возвращает также и результат своей работы в параметре GraphDriver. В
случае ошибки он может принимать значения, приведенные в таблице 1.
Таблица 1.
Значение
Объяснение
–2
нет графического адаптера
–3
не найден файл драйвера
–4
ошибка в драйвере (его коде)
–10
не возможен режим для выбранного драйвера
– 15
нет такого драйвера
В модуле Graph реализован еще один способ проверки результата проведения графической операции.
Он осуществляется с помощью функции
GraphResult: Integer;
которая возвращает код результата последнего вызова одной из процедур или функций: Bar, Bar3D,
ClearViewPort,
CloseGraph,
DetectGraph,
DrawPoly,
FillPoly,
FloodFill,
GetGraphMode,
ImageSize,
InitGraph,
InstallUserDriver,
InstallUserFont,
PieSlice, RegisterBGIdriver, RegisterBGIfont, SetAllPalette, SetFillPattern,
SetFillStyle,
Set-GraphBufSize,
SetGraphMode,
SetLineStyle,
SetPalette,
SetTextJustify, SetTextStyle.
Для быстрой выдачи простого сообщения о типе ошибки графической системы используется функция,
преобразующая результат вызова функции GraphResult в сообщение, которое можно вывести на
экран процедурой Write.
Эта функция имеет вид:
GraphErrorMsg (ErrorCode: Integer): String;
Возможные графические режимы для различных адаптеров приведены в библиотеке модуля Grаph.
�Оглавлен ие
Для тестирования графического адаптера в модуле Graph объявлена процедура:
DetectGraph (Var GraphDriver, GraphMode: Integer);
Эта процедура может быть вызвана до инициализации графики. Через формальные параметры
GraphDriver и GraphMode процедура DetectGraph возвращает значения, которые рекомендуется
подставлять в качестве фактических в процедуру InitGraph.
Номер текущего графического режима для установленного драйвера определяется функцией
GetGraphMode: Integer,
а функция
GetMaxMode: word
возвращает номер максимального режима графического адаптера.
Таким образом, каждый драйвер поддерживает диапазон режимов 0 .. GetMaxMode.
Этот же результат может быть получен из процедуры
GetModeRange (GraphDriver: Integer; Var LoMode, HiMode: Integer),
через параметры LoMode, HiMode возвращающей соответственно нижнюю и верхнюю границы
режимов для драйвера GraphDriver.
Функция
GetModeName (GraphMode: Word): String;
возвращает строку, в которой содержится последовательно через пробелы разрешение, имя константы
и название палитры для графического режима GraphMode.
Представленный ниже пример поможет определить, в каких графических режимах может работать
используемая ЭВМ.
Uses Graph;
{подключен модуль Graph}
Var
mode: Integer;
Procedure GrInit;
{процедура инициализации}
<...........>;
Begin
GrInit;
{инициализация}
for mode:= 0 to GetMaxMode do
{показ всех режимов}
OutTextXY (10, 10 + mode * 10,GetModeName (mode));
Readln;
CloseGraph;
End.
Функция
�Оглавлен ие
GetDriveName: string
позволяет получить имя используемого драйвера. Ее применение обосновано только в том случае,
если в процедуре InitGraph переменная GraphDriver определена, как Detect.
Для очистки графического экрана используют процедуры
ClearDevice,
которая очищает графический экран и устанавливает указатель позиции в положение (0, 0), и
GraphDefaults,
которая, кроме очистки экрана, устанавливает ряд параметров графической системы:
1) графическое окно становится равным размеру экрана;
2) восстанавливается системная цветовая палитра;
3) переназначаются цвета основных линий и фона экрана;
4) толщина и стиль линий принимаются как по умолчанию;
5) цвет и шаблон заливки геометрических фигур и замкнутых ломаных принимаются как по
умолчанию;
6) переустанавливается активный шрифт и его стиль.
Переключение системы в другой графический режим осуществляется процедурой
SetGraphMode (GraphMode: integer),
которая переключает систему в указанный параметром GraphMode графический режим и очищает
экран монитора. При этом все дополнительные характеристики устанавливаются по умолчанию.
Переключения возможны только в рамках текущего драйвера.
При написании некоторых программ, использующих и графические, и текстовые режимы работы
ЭВМ, используют процедуру
RestoreCRTMode,
которая возвращает систему в текстовый режим, работавший до инициализации графики. В этом
случае возвращение в графический возможно без его инициализации. Обратное переключение
осуществляется при помощи процедуры
GetGraphMode,
которая возвращает номер текущего графического режима. При работе RestoreCRTMode выгрузки
графического драйвера не происходит, т.е. он остается в памяти ЭВМ активным. Рассмотрим пример:
Uses Graph;
Const
graph_str = 'Это графический режим';
text_str = 'А это текстовый режим';
graph_back = 'А это снова графический режим';
Procedure GrInit;
�Оглавлен ие
<.......>;
Begin
GrInit;
{инициализация графики}
Line (0, 0, GetMaxX, GetMaxY);
{диагональ экрана}
OutTextXY (0, 100, graph_str);
{вывод первого сообщения}
Readln;
{пауза до нажатия ввода}
RestoreCRTMode;
{восстановление текстового режима}
Write (text_str);
{вывод второго сообщения}
Readln;
{пауза до нажатия ввода}
SetGraphMode(GetGraphMode);
{восстановление графического режима}
Line (0, 0, GetMaxX, GetMaxY);
{диагональ экрана}
OutTextXY (0, 100, graph_back);
{вывод третьего сообщения}
Readln;
{пауза до нажатия ввода}
CloseGraph;
End.
Используя процедуру SetGraphMode, следует помнить, что обратное включение графики
устанавливает в исходное состояние все графические параметры модуля Graph и, кроме того,
сбрасывает изображение с экрана.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. Составить программу инициализации графического режима, предварительно выполнив
тестирование графического адаптера. Выполнить построение линии, окружности, эллипса,
прямоугольника, многоугольника.
II. Составить программу инициализации графического режима, используя режим автоопределения
графического адаптера. Определить: a) тип адаптера, b) номер текущего графического режима, c) номер
максимального режима для данного графического адаптера. Вывести на экран информацию: a) о
графическом режиме, b) используемом драйвере, c) о разрешающей способности графического режима.
Переключиться в текстовый режим, а затем обратно включить графический, сопровождая эти действия
выводом информации с использованием процедуры write/writeln.
�Оглавлен ие
Лабораторная работа № 17
РИСОВАНИЕ ГРАФИЧЕСКИХ ПРИМИТИВОВ И ФИГУР
Система координат. Текущий указатель.
Линии и их стили.
Прямоугольники и ломаные.
Коэффициент сжатия изображения.
Окружности, эллипсы, дуги.
Контрольные задания
�Оглавлен ие
Система координат. Текущий указатель. Любое изображение на экране образуется как
композиция светящихся или погашенных пикселов. Эти точки адресуются двумя координатами X и Y,
отсчет которых ведется от верхнего левого угла (для X – слева направо, для Y – сверху вниз).
Координаты верхней левой точки – (0,0). Максимальные адресуемые координаты различных
режимов и типов адаптеров дисплеев различны. В модуле Graph предусмотрена возможность
программного опроса максимальных координат экрана. Она реализована функциями
GetMaxX: Integer;
GetMaxY: Integer.
Координаты X и Y могут принимать только целые значения, а значения GetMaxX и GetMaxY должны
быть инициализированы сразу после включения соответствующего режима.
При рисовании графических фигур пользуются понятием “текущий указатель”, который выполняет те
же функции, что и курсор в текстовом режиме, однако является при этом невидимым.
Положение графического курсора указывает на начальные координаты изображения графического
примитива, выводимого от “текущей позиции”.
Текущий указатель перемещается специальными процедурами. Процедура MoveTo (X,Y: Integer)
перемещает его в точку с координатами X и Y, а процедура MoveRel (dX,dY: Integer) перемещает
текущий указатель на dX пикселов по горизонтали и соответственно на dY – по вертикали
относительно последнего положения текущего указателя. Положительные значения dX и dY
увеличивают его координаты, а отрицательные – уменьшают.
Для определения текущего положения графического курсора используют функции
GetX: Integer;
GetY: Integer,
возвращающие положение указателя соответственно по оси X и по оси Y.
Не все графические процедуры перемещают текущий указатель. Кроме вышеназванных, изменяют его
положение лишь процедуры LineTo, LineRel, OutText.
Все процедуры инициализации и очистки экрана устанавливают его в положение (0,0).
�Оглавлен ие
Линии и их стили. Процедура вывода линии (отрезка) на экран (в текущем цвете и стиле)
определена в следующем виде
Line (X1,Y1,X2,Y2 : Integer),
где X1,Y1 – координаты начала, а X2,Y2 – конца отрезка.
Возможны еще два метода рисования отрезков:
a) из текущей точки в точку с заданными координатами (X,Y) процедурой
LineTo (X,Y : Integer);
b) относительно текущей позиции процедурой
LineRel (dX,dY : Integer),
где dX и dY – приращения координат X и Y относительно точки с текущими координатами. После
выполнения текущий указатель переместится в конец отрезка.
В Turbo Pascal можно управлять стилем линий: задавать толщину, тип (сплошные линии,
пунктирные и т.п.). Для этого определены следующие типы и константы стилей изображаемых линий:
Type
LineSettingsType = Record
LineStyle: Word;
{стиль (тип)}
Pattern: Word;
{шаблон типа}
Thickness: Word;
{толщина}
End;
Const
{для значений поля LineStyle:}
SolidLn = 0;
{сплошная линия}
DottedLn = 1;
{точечная линия}
CenterLn = 2;
{штрихпунктирная линия}
DashedLn = 3;
{пунктирная линия}
UserBitLn = 4;
{тип линии задан явно шаблоном для значений поля Thickness:}
NormWidth = 1;
{толщина линии в 1 пиксель}
ThickWidth = 3;
{толщина линии в 3 пикселя}
Для получения информации о текущем стиле линий используют процедуру
GetLineSettings (Var LineType: LineSettingsType),
а чтобы установить новый стиль линий, необходимо использовать процедуру
SetLineStyle (LineStyle, Pattern, Thickness : Word),
подставив в нее соответствующие значения.
Если LineStyle равен UserBitLn, то при определении типа линии следует руководствоваться
следующими правилами:
�Оглавлен ие
a) линия представляет собой совокупность отрезков, длина каждого из которых 16 пикселов (если
длина отрезка не делится на 16 нацело, последний отрезок обрезается);
b) шаблон-комбинацию задают в виде 16 светящихся или погашенных точек (светящейся точке
ставится в соответствие 1, погашенной – 0).
Поскольку Turbo Pascal не позволяет работать с числами, представленными в двоичной системе
счисления, необходимо перевести полученное число в десятичную или шестнадцатеричную системы
счисления и поставить его фактическим параметром на место Pattern. Например, 1100110011001100
соответствует 52428 десятичное или $CCCC шестнадцатеричное.
Назначение стиля влияет на действие всех процедур, выводящих на экран отрезки или фигуры, из них
состоящие.
Процедуры, выводящие на экран дуги, учитывают только толщину, заданную в стиле.
�Оглавлен ие
Коэффициент сжатия изображения. Т.к. отношение высоты экрана к ширине не равно
отношению его разрешающей способности по вертикали к разрешающей способности по горизонтали,
то для учета этого неравенства вводится специальный показатель – коэффициент сжатия изображения
(aspect ratio). Его значения могут иметь широкий диапазон. Разрешающая способность адаптеров
колеблется от 640×200 для CGA до 1024×768 для IBM8514, и отношение GetMaxX к GetMaxY
меняется от 0.3125 (640×200) до 0.75 (1024×768). Таким образом, на единицу длины экрана
приходится разное количество пикселов по горизонтали и вертикали. Поскольку все операции
производятся с пикселaми, то в результате вместо окружности может получиться эллипс,
горизонтальная полуось которого равна радиусу, а вертикальная – радиусу, деленному на коэффициент
сжатия.
В модуле Graph есть две процедуры:
GetAspectRatio (Var A,B: Word),
возвращающая в переменных A и B значения, отношение которых (A/B) и есть коэффициент сжатия
изображения, и
SetAspectRatio (A,B: Word),
позволяющая изменить текущий коэффициент сжатия на равный (A/B) и позволяющая писать
программы, одинаково работающие на различных ЭВМ.
�Оглавлен ие
Окружности, эллипсы, дуги. Для изображения окружностей используется процедура
Circle (X,Y: Integer; Radius: Word),
где (X,Y) – координаты центра окружности, Radius – ее радиус.
В модуле Graph представлены процедура рисования эллипсов, дуг, секторов и процедура,
позволяющая рисовать сектор, залитый по данному шаблону. Все они используют параметры
StartAngle и EndAngle – начальный и конечный угол дуги. За 0 принято направление оси X (слева
направо), и углы отмеряются от оси X против часовой стрелки. Все значения этих параметров даются в
градусах.
Arc (X,Y: Integer; StartAngle, EndAngle, Radius: Word) –
рисование дуги радиуса Radius из центра (X,Y) от угла StartAngle до EndAngle.
Ellipse (X,Y: Integer;
StartAngle,
EndAngle,
XRadius, YRadius: Word)
рисование эллиптической дуги с аналогичными параметрами, где XRadius, YRadius – размеры
горизонтальной и вертикальной полуосей соответственно.
Некоторые другие процедуры, изображающие секторы (Sector, PieSlice), а также FillEllipse,
выполняют попутно их заливку.
Для определения координат начала и конца дуг окружности или эллипса используют процедуру
GetArcCoords (Var ArcCoords: ArcCoordsType).
Тип ArcCoordsType объявлен в модуле Graph следующим образом:
Type
ArcCoordsType = Record
X,Y: Integer;
{центр}
XStart,YStart: Integer;
{начало}
XEnd,YEnd: Integer;
{конец}
End;
�Оглавлен ие
Прямоугольники и ломаные. Для построения прямоугольника необходимо вызвать процедуру
Rectangle (X1,Y1,X2,Y2: Integer),
которая изобразит на экране прямоугольник с диагональю (X1,Y1) – (X2,Y2).
Чтобы построить фигуры с большим количеством вершин (в том числе и незамкнутых), можно
использовать процедуру
DrawPoly (NumPoints: Word; Var PolyPoints).
Параметр NumPoints – количество точек ломаной, PolyPoints – бестиповый параметр, состоящий
из набора двухкомпонентных записей. Обычно набор точек организуется как массив из записей типа
PointsType:
Type
PointsType = Record
X,Y: Integer;
End;
Ниже рассмотрен пример построения графика с помощью данной процедуры.
Для построения графиков в декартовой системе координат выберем систему координат таким образом,
чтобы ее начало находилось в точке с координатами (GetMaxX div 2, GetMaxY div 2).
Для рисования осей координат OX и OY используем процедуру Line:
Line (0, GetMaxY div 2, GetMaxX, GetMaxY div 2)
рисует ось X, a
Line (GetMaxX div 2, 0, GetMaxX div 2, GetMaxY)
рисует ось Y.
Рис. 1
После этого необходимо произвести разметку осей OX и OY. Выберем цену деления в пикселах. Теперь
введем коэффициент масштабирования MasKoefX, равный числу пикселов, приходящихся на одно
деление.
Отрезок OX будет содержать k подотрезков, по величине равных MasKoefX,
k = (GetMaxX div 2) div MasKoefX.
�Оглавлен ие
Для разметки оси ОX нужно вычислить величину остатка, получающегося при разбиении, т.к. именно с
этой позиции следует вести разметку, чтобы она прошла через начало координат.
X = (GetMaxX div 2) mod MasKoefX
Для выполнения разметки воспользуемся циклом While.
While x < GetMaxX do
begin
Line (x, GetMaxY div 2 – dy, x, GetMaxY div 2 + dy);
x:= x + MasKoefX;
end;
Здесь 2dy – длина вертикальных штрихов разметки.
Аналогичным образом выполняется разметка оси Y. Следует, однако, помнить, что разрешающая
способность по оси X и оси Y неодинакова, поэтому и коэффициент масштабирования по оси Y будет
другим:
MasKoefY = Round (Xasp /Yasp
* MasKoefX).
Значения Xasp и Yasp получим, используя функцию
GetAspectRatio (Xasp , Yasp ).
После разметки осей координат экран будет иметь вид (рис. 2.).
Рис. 2
Для рисования графика функции y = f(x) в системе координат XOY необходимо выполнить
следующий фрагмент программы:
Koord x:= –k; h:= 0.1;
While Koord x < k do
begin
x:= round (Koord x);
y = f(x);
PutPixel (x,round (y));
�Оглавлен ие
Koord x:= Koord x + h;
end;
Так как компьютер выполняет все графические процедуры относительно собственной системы
координат, то нужно выполнить переход из одной системы координат в другую. Из рис. 2. видно, что
координаты точки A в различных системах координат связаны простым соотношением:
xs
= GetMaxX div 2 – (–x) = GetMaxX div 2 + x;
ys
= GetMaxY div 2 – y;
Учитывая все эти соображения, составим программу рисования графиков в среде Turbo Pascal.
Program Grafik;
Uses Crt, Graph;
Const
n=1000;
a=1;
b=0;
MasKoefX=40;
Var
Xasp,Yasp: Word;
y_func: array[1..n] of PointType;
MasKoefY: Word;
Ratio: Extended;
{--------------------------------------------------}
Function f(x: Extended):Extended;
begin
f:= sin(x*x)/cos(x);
end;
{--------------------------------------------------}
Procedure GrInit;
var
grDriver : Integer;
grMode
: Integer;
ErrCode : Integer;
begin
grDriver:= Detect;
InitGraph(grDriver, grMode, 'g:\progr\tp');
�Оглавлен ие
GetAspectRatio(Xasp, Yasp);
Ratio:= Xasp/Yasp;
MasKoefY:=round(Ratio*MasKoefX);
end;
{--------------------------------------------------}
Procedure SysCoord;
Const
dx=2;
dy=2;
var
Delen: Word;
x,y: Word;
Rat: Extended;
begin
Line(0, GetMaxY div 2, GetMaxX, GetMaxY div 2);
x:= (GetMaxX div 2) mod MasKoefX;
While x < GetMaxX do
begin
Line(x, GetMaxY div 2 – dy, x, GetMaxY div 2 + dy);
x:= x + MasKoefX;
end;
Line(GetMaxX div 2, 0, GetMaxX div 2, GetMaxY);
y:= (GetMaxY div 2) mod MasKoefY;
While y < GetMaxY do
begin
Line(GetMaxX div 2 – dx, y, GetMaxX div 2 + dx, y);
y:= y + MasKoefY;
end;
end;
{--------------------------------------------------}
Procedure DrawGraph;
var
i: Word;
xi,yi: Extended;
�Оглавлен ие
Delen: Word;
h: Extended;
CountPoint: Word;
begin
Delen:= (GetMaxX div 2) div MasKoefX;
h:=1/MasKoefX;
i:=0;
xi:= –Delen;
While xi<Delen do
begin
yi:= f(xi);
y_func[i].x:= GetMaxX div 2 + round(xi*MasKoefX);
y_func[i].y:= GetMaxY div 2 – round(yi*MasKoefY);
xi:= xi + h;
inc(i)
end;
CountPoint:=i–1;
DrawPoly(CountPoint, y_func);
end;
{--------------------------------------------------------------}
Begin
GrInit;
SysCoord;
DrawGraph;
ReadLn;
CloseGraph;
End.
С помощью DrawPoly можно вывести график части функции. Для этого достаточно указать при
передаваемом массиве номер n первого рассматриваемого элемента (т.е. точки), а в первом параметре
– количество рассматриваемых точек, начиная с n–ой, например,
DrawPoly (20, y_func [100]);
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. Исследовав область определения и выбрав расположение координатных осей на экране и масштаб,
построить графики функций:
1. y = ex ;
2. y = ln x;
3. y = 10x ;
4. y = ctg x;
5. y = arcctg x;
6. y = arcsin (sin x);
7. y = arctg (tg x);
8. y = x ;
9. y = 1/(x + 1);
10. y = (x + 3)/(x + 1);
11. y = 1 + 2/x + 3/x;
13. y = sin x – cos x;
12. y = 3 – 2/x – 1/x ;
14. y = 2x – cos 0.5x;
15. y = x+x
16. y = x+3cos x
17. y = x – 2x2 + x3 ;
18. y = x + ln (x + 1) + 2;
19. y = x + ex ;
20. y = x1/x ;
21. y = (x – 3) e –x/2 ;
22. y = cos (0.5x) – x ;
23. y = lg x;
24. y = 1/x;
25. y = tg x;
26. y = sin x;
27. y = arccos (cos x);
28. y = arcctg (ctg x);
29. y = 1/x2 ;
30. y = 1/x3 ;
31. y = x/ln x;
32. y = 3x2 – 2x + 5;
33. y = 1/(3x2 + 2x + 1);
34. y = 1/(x2 + 2x + 1);
35. y = (x + 1)2 – sin x;
36. y = (1 + x2 )/x;
37. y = x2ex ;
38. y = x3 – 3x;
39. y = e–x – (x – 4)2;
40. y = 1/(x3 + 1);
41. y = x2/3;
42. y = (x – 4) e–x/10 ;
43. y = (sin x – cos x)e–x/5 ;
44. y = e–x/3 sin x.
II. Построить кривые по заданному параметрическому представлению:
1. Окружность радиуса r с центром в начале координат:
x = r cost, y = r sin t, t [0, 2π ).
2. Эллипс с большой и малой полуосями, равными соответственно r1 и r2 и расположенными
параллельно осям координат:
x = r1 cos t, y = r2 sin t, t [0, 2π ).
3. Улитку Паскаля:
�Оглавлен ие
x = a cos2 t + b cos t, y = a cos t sin t + b sin t, a > 0, b > 0, t [0, 2π ). Рассмотреть случаи,
когда b >= 2a, a < b < 2a, a > b.
4. Кардиоиду:
x = a cos t (1 + cos t), y = a sin t (1+cos t), a > 0, t [0, 2π ).
5. Эпициклоиду:
x = (a + b) cos t – a cos ((a + b) t/a), y = (a +b) sin t – a sin ((a + b) t/a), a > 0, b > 0.
Рассмотреть следующие случаи:
a) если b/а есть целое положительное число, t [0, 2π );
b) если b/a = p/q, где p и q – положительные целые взаимно простые числа, t [0, 2qπ ).
6. Астроиду: x = b cos3 t, y = b sin3 t, t [0, 2π ).
7. Циссоиду: x = at2 /(1 + t 2), y = at3/(1 + t 2 ), t (– , ), a > 0.
8. Строфоиду: x = a(t 2 – 1)/(t 2 + 1), y = at(t 2 –1)/(t 2 +1), t (– , ), a > 0.
9. Конхоиду Никомеда: x = a +lcost, y = atgt +lsint, t (– π /2, π /2) – правая ветвь, t (π /2, 3π /2) –
левая ветвь, a >0, l > 0. Рассмотреть случаи, когда l < a, l > a, l = a.
10. Астроиду: x = R cos3 (t/4), y = R sin3 (t/4).
11. Гипоциклоиду: x = (R – mR) cos mt + mR cos(t – mt),
y = (R –mR)sinmt – mR sin (t – mt), mR = r, (m = r/R), m = 1/4; m = 1/2; m = 2/3; m = 2/5.
12. Декартов лист: x = 3at / (t 3 + 1); y = 3at2 / (t 3 + 1).
13. Кардиоиду: x = 2r cos t –r cos 2t, y = 2r sin t – r sin 2t.
14. Строфоиду: x = 2at2 / (1 + t 2 ), y = at (t 2 – 1) / (1 + t 2 ).
15. Трактрису: x = a (ln tg t/2 + cos t), y = a sin t.
16. Циклоиду: x = a (t – sin t), y = a (1 – cos t).
17. Удлиненную (укороченную) циклоиду: : x = at – d sin t, y = a – d cos t.
18. Циссоиду Диоклеса:x = a / (t 2+ 1), y = a / t(t 2+ 1).
19. Эвольвенту окружности: x = a (cos t + t sin t), y = a (sin t – t cos t).
III. Построить кривые по их уравнениям, заданным в полярных координатах:
1. r = а sin 3α ;
2. r = а sin 2α ;
3. r = а α ;
4. r = а α 2 – l; l >= 0;
5. r = а sin (4α /3);
6. r = а sin (5α /3);
7. r = а/α 2 ;
8. r = а/cos α ± a tg α ;
19. r a 2 cos 2
11. r = а ebα ;
10. r a cos 2 / cos
12. r = а(4cos a – 1/cos a);
�Оглавлен ие
13. r a ;
14. r a 1;
15. r = а sin 3α ;
16. r = а/sinα ± l;
17. r = аα , a>0;
18. r = 1 + sin(2α );
19. r = sin 2α ;
20. r = 3a sinα cosα /(sin3 α +cos3 α );
21. r = а sin (α /2);
22. r = а sin (α /3);
23. r = а/α ;
24.
25. r = 1 + cos a;
26. r = 2а cos a – l;
ra
27. r = 2а(1 – cos α );
28. r = 2а sin 2α /cos α ;
29. r = b + а sinα ;
30. r = а(1 + cosα );
31. r = а sin α ;
32. r = 2а sin2 α /cos α ;
33. r = 2а(1 – cos α );
34. r = α /4;
35. r = b + а sin α ;
36. r = 1 + 2cos α ;
37. r = а sin α ;
38. r = 1 + 2cos 2α ;
39. r = sin 5α ;
40. r = sin 7α .
IV.
1. Построить ход лучей в собирающей линзе. Свет распространяется параллельно оптической оси.
2. Построить ход лучей в собирающей линзе. Свет распространяется под углом a к оптической оси.
3. Построить ход лучей в собирающей линзе. Источник света находится в главном фокусе.
4. Построить ход лучей в собирающей линзе. Источник света находится в фокальной плоскости.
5. Построить ход лучей в рассеивающей линзе. Свет распространяется параллельно оптической
оси.
6. Построить ход лучей в рассеивающей линзе. Источник света находится в главном фокусе.
7. Выполнить построение изображения в собирающей линзе. Предмет расположен на расстоянии
l>f от линзы.
8. Выполнить построение изображения в собирающей линзе. Предмет расположен на расстоянии
l<f от линзы.
9. Выполнить построение изображения в рассеивающей линзе. Предмет расположен на
расстоянии l>f от линзы.
10. Выполнить построение изображения в рассеивающей линзе. Предмет расположен на
расстоянии l<f от линзы.
11. Выполнить построение изображения в сферическом вогнутом зеркале. Предмет расположен на
расстоянии l>f от зеркала.
�Оглавлен ие
12. Выполнить построение изображения в сферическом выпуклом зеркале. Предмет расположен на
расстоянии l<f от зеркала.
13. Построить ход лучей в треугольной призме.
V. Составить программу, иллюстрирующую:
a) часы–ходики;
b) секундомер;
c) вращающийся квадрат;
d) вращающийся треугольник;
e) вращающийся вокруг центра отрезок;
f) вращающийся пятиугольник;
g) вращающийся прямоугольник;
h) вращающаяся пятиконечная звезда;
i) вращающаяся шестиконечная звезда.
�Оглавлен ие
Лабораторная работа № 18
УПРАВЛЕНИЕ ЦВЕТАМИ И ШАБЛОНАМИ ЗАЛИВКИ (ЗАПОЛНЕНИЯ)
В модуле Graph предусмотрены процедуры, с помощью которых можно заполнить (залить)
определенным “узором” любую замкнутую область изображения. Вид “узора” задается так называемым
шаблоном заливки. В Turbo Pascal предопределены ряд стандартных шаблонов, но, кроме того,
имеется возможность конструировать собственные.
Назначение шаблона заполнения (заливки) производится процедурой
SetFillStyle (Pattern: Word; Color: Word),
где параметр Pattern определяет вид шаблона заливки, а Color – его цвет. Все разрешенные
значения параметра Pattern предопределены в модуле Graph в виде констант:
Const
EmptyFill = 0;
{ сплошная штриховка цветом фона (узор отсутствует) }
SolidFill = 1;
{ сплошная штриховка текущим цветом }
LineFill = 2;
{ штриховка линиями ======= }
LtSlashFill = 3;
{ штриховка линиями / / / / / / / }
SlashFill = 4;
{ штриховка утолщенными линиями / / / / / / / }
BkSlashFill = 5;
{ штриховка линиями \ \ \ \ \ \ \ }
LtBkSlashFill = 6;
{ штриховка утолщенными линиями \ \ \ \ \ \ \ }
HatchFill = 7;
{ штриховка +++++++ }
XHatchFill = 8;
{штриховка }
InterLeaveFill = 9;
{ штриховка в прямоугольную клеточку }
WideDotFill = 10;
{ штриховка редкими точками }
CloseDotFill = 11;
{ штриховка частыми точками }
UserFill = 12;
{ штриховка определяется пользователем }
Константа UserFill используется для определения типа заливки, который предварительно был задан
в программе.
Для задания нового шаблона необходимо воспользоваться процедурой
SetFillPattern (PattMatrix: FillPatternType; Color: Word),
передав ей в параметре PattMatrix матрицу шаблона заливки и указав цвет параметром Color. Эта
процедура по действию аналогична SetFillStyle, но устанавливает только «самодельные»
шаблоны. Получение информации о текущих установках шаблона заливки производится процедурой
GetFillSettings (Var FillType: FillSettingsType),
которая возвращает в переменной FillType предопределенного типа
�Оглавлен ие
Type
FillSettingsType = Record
Pattern: Word;
Color: Word;
{шаблон}
{цвет}
End;
номер шаблона из списка, представленного при описании процедуры SetFillStyle (поле Pattern),
и цвет, которым наносится этот шаблон (поле Color).
Если значение поля Pattern оказалось равным UserFill, то для получения подробной информации
следует вызвать процедуру
GetFillPattern (Var PatternMatrix: FillPatternType),
возвращающую в переменной типа FillPatternType
пользователем шаблона.
матрицу последнего определенного
Заливка областей изображения. В модуле Graph имеется ряд процедур, рисующих графические
фигуры и сразу же заполняющих их по заданному шаблону.
Процедура
Bar (X1,Y1,X2,Y2: Integer)
рисует прямоугольник, внутренняя область которого залита по текущему шаблону. Параметры
(X1,Y1) и (X2,Y2) – координаты верхнего левого и нижнего правого углов прямоугольника.
Процедура
Bar3D (X1,Y1,X2,Y2: Integer; D3: Word; Top: Boolean)
рисует параллелепипед, лицевая сторона которого заливается по текущему шаблону, а глубина задается
в пикселах параметром 3D. Параметр Top задает режим отображения верхней плоскости: True –
отображать, False – не отображать. Этот параметр необходим при рисовании столбцов, стоящих друг
на друге.
В модуле Graph определены две константы для нее:
Const
TopOn = True;
{ верхняя плоскость нужна }
TopOff = False;
{ верхняя плоскость не нужна }
Рисование сектора эллипса, который будет залит цветом по текущему шаблону, осуществляется
процедурой
Sector (X,Y: Integer; StartAngle, EndAngle, XRadius, YRadius: Word).
Параметры процедуры имеют тот же смысл, что и в процедурах Arc, Ellipse. Для задания кругового
сектора надо задавать YRadius с учетом коэффициента сжатия:
Var
R,A,B: Word;
Begin
{R – радиус кругового сектора}
�Оглавлен ие
. . . . . .
GetAspectRatio (A,B);
Sector (100, 100, 0, 90, R, R * LongInt (A) div B );
. . . . . .
End.
Этого же эффекта можно достичь, используя процедуру
PiveSlice (X,Y: Integer; StartAngle, EndAngle, Radius: Word),
которая рисует сектор окружности, площадь которого заливается по текущему шаблону заполнения.
Процедура
FillEllipse (X,Y: Integer; XRadius, YRadius: Word);
рисует эллипс текущим цветом и заполняет его по установленному шаблону.
Заполнение более сложных геометрических фигур, в том числе и неправильной формы, производится
процедурой
FillPoly (NumPoints: Word; Var PolyPoints).
Ее параметры имеют такое же назначение, как и в процедуре DrawPoly. Отличие только в том, что
координаты первой и последней вершин многоугольника могут не совпадать. Все равно они будут
соединены линией, и внутренность фигуры будет залита.
Пример.
Uses Graph;
{$I initgraph.pas }
Const
our_figure: Array [1..4] of PointType =
(( x : 319 ; y : 40 ),
{задание координат}
( x : 398 ; y : 146 ),
{концов отрезков }
( x : 240 ; y : 146 ),
( x : 400 ; y : 40 ));
Begin
GrInit;
SetFillStyle (InterLeaveFill, Red);
FillPoly
фигуры}
Readln;
CloseGraph
End.
(SizeOf
(our_figure)
div
{задание шаблона}
SizeOf
(PointType),Our_figure);{рисование
�Оглавлен ие
Универсальная процедура
FloodFill (X,Y: Integer; Border: Word)
заливает всю область вокруг точки (X,Y), ограниченную линиями цвета Border. Например, если
точка (X,Y) находится внутри области, ограниченной окружностью, то вся область будет залита по
шаблону и цветом, установленными процедурами SetFillPattern или SetFillStyle. Если же
точка будет находится вне этой области, то залитым будет весь экран, за исключением этой области.
Опрос и установка цветов пера и фона. Различные адаптеры поддерживают разное количество
цветов, выводимых одновременно на экран в графическом режиме. Но для всех BGI–драйверов оно
ограничено диапазоном 0..15. Нумерация и названия цветов таковы:
Черный
Синий
Зеленый
Голубой
Красный
Фиолетовый
Коричневый
Светло–серый
Темно–серый
Светло–синий
Светло–зеленый
Светло–голубой
Розовый
Светло–фиолетовый
Желтый
Белый
Black = 0
Blue = 1
Green = 2
Cyan = 3
Red = 4
Magenta = 5
Brown = 6
Gray = 7
DarkGray = 8
LightBlue = 9
LightGreen = 10
LightCyan = 11
LightRed = 12
LightMagenta = 13
Yellow = 14
White = 15
Максимальный номер цвета, воспринимаемый данным адаптером в текущем графическом режиме,
может быть получен при помощи функции
GetMaxColor: Word.
На экране всегда различаются цвет фона и цвет пера. Все процедуры изображения фигур, если не
содержат в себе явной установки цвета, рисуют эти фигуры цветом пера. Этот цвет устанавливается
процедурой
SetColor (Color: Word).
Цвет фона всегда един в поле экрана. Он может быть изменен процедурой
SetBkColor (Color: Word).
После использования этой процедуры цвет экрана сразу же меняется на заданный. Цветом фона может
быть любой из разрешенных цветов. По умолчанию и при реинициализации графики цвет фона равен
0 (Black), а цвет пера равен значению GetMaxColor.
Всегда можно опросить текущие установки цвета. Функция
GetColor: Word
возвращает текущие установки пера, а функция
GetBkColor: Word
�Оглавлен ие
возвращает текущий цвет фона.
Управление палитрой. Максимальный набор
цветов,
поддерживаемых
одновременно
BGI–драйвером, называется палитрой и может состоять из 16 цветов, пронумерованных от 0 до 15
(для графических адаптеров EGA и VGA).
Стандартная палитра режима 320×200 адаптера CGA (палитра C0) состоит всего лишь из четырех
цветов:
0 – черный;
2 – малиновый;
1 – синий;
3 – белый.
А для того же адаптера CGA в режиме CGAHi (640×200) палитра состоит из двух цветов: черного (0) и
белого (1).
Числа от 0 до 15, которые используются для обозначения цветов, определяют цветовые атрибуты или
“программные” цвета. Каждому “программному” цвету присваивается “аппаратный” цвет из так
называемой палитры. Например, для адаптера EGA, выводящего одновременно до 16 цветов,
программные цвета выбираются из полной палитры в 64 цвета, имеющейся в этом адаптере. А в
адаптере VGA аппаратная палитра содержит 256 цветов. Для адаптера CGA полная палитра составляет
16 аппаратных цветов, но на экране может одновременно появиться лишь 4 цвета одной из четырех
программных палитр (C0 ... C3).
Для управления соответствием между программными и аппаратными цветами в модуле Graph
предусмотрен ряд процедур, охватывающих практически все возможные операции с палитрой.
В модуле Graph определен тип для описания палитры:
Const
MaxColors = 15;
{максимальный программный номер цвета}
Type
PaletteType = Record
Size: Byte;
Colors: Array [0..MaxColors] of ShortInt;
End;
Поле Size содержит количество цветов в палитре, а поле Colors содержит действующие цвета в
первых Size элементах массива.
Процедуры GetPalette и GetDefaultPalette возвращают в фактических параметрах значение
PaletteType:
GetDefaultPalette (Var Palette: PaletteType);
GetPalette (Var Palette: PaletteType).
Первая возвращает набор цветов, который устанавливается при инициализации графического режима,
т.е. по умолчанию, а вторая процедура возвращает текущий набор цветов.
Функция
GetPaletteSize: Word
�Оглавлен ие
возвращает результат типа Word, который показывает, какое количество цветов входит в текущую
программную палитру. Для установки палитры в модуле Graph представлены три процедуры.
Процедура
SetPalette (ColorNum: Word; Color: ShortInt)
управляет только одним цветом в палитре. ColorNum – это номер программного цвета, Color – номер
аппаратного цвета, который будет под ним пониматься. Например, вызов SetPalette (0,Red)
делает красный цвет первым цветом палитры. При некорректном вызове процедуры функция
GraphResult вернет значение grError.
Процедура
SetAllPalette (Var Palette)
позволяет самостоятельно производить “перетасовку” всей палитры сразу и назначать соответствие
между программными и аппаратными цветами. Параметр Palette является бестиповым, переменной
длины. Первый его байт должен содержать количество цветов в устанавливаемой палитре,
следующие N байтов должны содержать цвета из аппаратной палитры, которые будут использоваться в
дальнейшем. Каждый из этих байтов может принимать значение от – 1 до максимального
аппаратного, причем диапазон чисел от 0 и выше представляет устанавливаемые цвета, а число – 1
задается в том случае, если соответствующий цвет остается без изменения.
Более сложная процедура
SetRGBPalette (ColorNum, RedValue, GreenValue, BlueValue: Integer),
позволяет манипулировать цветовыми сочетаниями развитых графических адаптеров VGA и IBM8514.
Параметр программного цвета ColorNum должен быть в диапазоне 0..15 для VGA и 0..255 для
IBM8514. Последние три параметра показывают смешение красного, зеленого и синего цветов. На
практике применение этой процедуры проблематично из–за сложности представления “аппаратных”
цветов.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. Дано n целых чисел x 1, x2 ,.... , xn и y1, y2, .... , yn. Рассматривая их как количество изделий,
выпущенных двумя предприятиями за n-й день, построить диаграмму,
отдельные
элементы
которой имеют вид, показанный на рис 1. Прямоугольник соответствует количеству изделий,
выпущенных за день одним предприятием.
Решить данную задачу используя процедуру Bar3D с
наложением столбцов один на другой.
1. n = 5; заполнение типа /// и === ;
2. n = 5; заполнение типа /// (тонкими линиями) и крупный горошек;
3. n = 6; заполнение типа === и косой клеткой;
4. n = 6; заполнение типа /// (тонкими линиями) и мелкий горошек;
5. n = 7; заполнение типа /// (тонкими линиями) и клеткой;
6. n = 5; заполнение типа === и косой клеткой;
7. n = 5; заполнение типа \\\\\ (тонкими линиями) и клеткой;
8. n = 6; заполнение типа //// (тонкими линиями) и частой клеткой.
II. Написать программу построения диаграммы с элементами, имеющими вид, показанный на рис. 2.
Высота столбцов и шаблон заполнения задаются случайным образом. Представить эти же данные
секторной диаграммой (секторы пропорциональны заданным числам).
�Оглавлен ие
Лабораторная работа № 19
БИТОВЫЕ ГРАФИЧЕСКИЕ ОПЕРАЦИИ
Turbo Pascal позволяет организовать прямой доступ к каждому пикселу экрана. Делается это
функцией
GetPixel (X, Y: Integer),
которая возвращает значение типа Word – номер цвета пиксела с координатами (X,Y). Поскольку
обычно номер цвета лежит в диапазоне 0..15 или меньше, значащим является только младший байт.
Управление пикселами заключается в возможности назначить цвет любому пикселу экрана. Процедура
PutPixel (X, Y: Integer; Color: Word)
«зажигает» на экране в точке с координатами (X,Y) пиксел цвета Color. На применении этой
процедуры построен следующий пример.
Uses Graph, Crt;
{ $I initgraph.pas }
Const
minx = 290; miny = 70;
{левый верхний угол области}
maxx = 350; maxy = 130;
{правый нижний угол области}
Nx = Succ(maxx – minx);
{ширина области в пикселах}
Ny = Succ(maxy – miny);
{высота области в пикселах}
Npixels = Nx * Ny;
{число пикселов в области }
Var
countpixels, Color: Word;
{счетчик точек и их цвет}
X, Y: Integer;
{координаты текущей точки}
Begin
GrInit;
{инициализация графики}
Color:= GetMaxColor;
{цвет выводимых точек}
countpixels:= 0;
{обнуление счетчика точек}
Repeat
x:= minx + Random(Nx);
{случайные координаты}
y:= miny + Random(Ny);
{точки в прямоугольнике }
if GetPixel(X,Y) = Black then
{если в точке (X,Y) }
begin
{ничего нет, то }
PutPixel(X,Y,Color);
{подсветить ее и }
Inc(countpixels)
{увеличить счетчик }
�Оглавлен ие
end;
until countpixels = Npixels;
Repeat Until KeyPressed;
{пауза до нажатия клавиши }
Repeat
x:= minx + Random(Nx);
{случайные координаты}
y:= miny + Random(Ny);
{точки в прямоугольнике}
if GetPixel(X,Y) = Color then
begin
{если точка (X,Y) }
PutPixel(X,Y,Black);
{светится, то “потушить” }
Dec(countpixels)
{ее и уменьшить счетчик }
end;
Until countpixels = 0;
CloseGraph
End.
Работа с фрагментами изображения. Для запоминания в буфере и восстановления из него
прямоугольных фрагментов графического изображения используют процедуры
GetImage(X1,Y1,X2,Y2: Integer; Var BitMap)
и
PutImage(X1,Y1: Integer; Var BitMap; Mode: Word),
где (X1,Y1), (X2,Y2) – координаты левого верхнего и правого нижнего углов области, а вместо
бестипового параметра BitMap должна подставляться переменная – буфер, занимающая область
памяти размера, необходимого для полного сохранения изображения. Для определения этого размера
используется функция
ImageSize(X1,Y1,X2,Y2: Integer): Word;
которая возвращает размер памяти в байтах, необходимый для сохранения прямоугольной области
экрана. Максимальный размер сохраняемого изображения не должен превышать 64 К.
Обратите внимание, что у процедуры PutImage, которая восстанавливает изображение из буфера
BitMap в прямоугольник, указывается всего одна точка (X1,Y1). Объясняется это тем, что в
структуре BitMap первые два слова (четыре байта) содержат ширину и высоту в пикселах
запомненного изображения.
В этой процедуре имеется возможность определять режим вывода изображения: можно суммировать
изображение на экране и изображение в буфере, можно уничтожать изображение, находящееся в
определяемой области, можно инвертировать изображение, содержащееся в буфере. Эти операции
задаются параметром Mode, для которого в модуле Graph определены константы:
Const
CopyPut = 0;
{операция MOV (замещения)}
�Оглавлен ие
XORPut = 1;
{операция XOR}
ORPut
{операция OR }
= 2;
ANDPut = 3;
{операция AND}
NOTPut = 4;
{операция NOT}
Из этих пяти режимов самым интересным является XOR, поскольку произведенные последовательно
две операции XOR с одинаковым вторым аргументом оставляют первый из них без изменения. Это
свойство используется в тех случаях, когда необходимо изобразить некий подвижный объект на
сложном фоне; два раза выведя один и тот же фрагмент в одно и то же место в режиме XOR, мы
оставим фон неизменным.
Uses Graph,Crt;
{$I initgraph.pas }
Const
r = 10;
{ радиус подвижного шарика}
X1,Y1,X2,Y2,Sx,Sy: Integer;
{переменные для оживления фрагмента }
Var
maxx,maxy,Sxmove,Symove: Integer;
Size: Word;
{ размер фрагмента }
P: Pointer;
{ указатель на буфер }
GrInit;
{ инициализация графики }
maxx:= GetMaxX;
{ максимальное поле экрана }
Begin
maxy:= GetMaxY;
X1:= maxx div 2 – r;
{ координаты области экрана,}
Y1:= maxy div 2 – r;
{ в которой будет нарисован }
X2:= X1 + 2 * r;
{ шарик и которая будет }
Y2:= Y1 + 2 * r;
{ сохраненным фрагментом }
Sx:= X1; Sxmove:= 3;
{ начальная точка движения }
Sy:= Y1; Symove:= –1;
{ и шаг перемещения шарика}
SetFillStyle(SolidFill, Red);
{ выбор типа заливки}
PieSlice(X1 + r, Y1 + r, 0, 360, r); { рисование шарика }
Size:= ImageSize(X1, Y1, X2, Y2);
{ фрагмент в байтах }
GetMem(P, Size);
{ размещение буфера }
GetImage(X1, Y1, X2, Y2, P^);
{ фрагмент и в буфер }
SetFillStyle(CloseDotFill, Blue);
{ тип заливки фона}
Bar(50, 50, maxx – 50, maxy – 50);
{ фоновая картинка}
�Оглавлен ие
repeat
{ начало движения шарика}
PutImage(Sx, Sy, P^, XORPut);
{ вывод шарика }
Delay(120);
{ пауза}
PutImage(Sx, Sy, P^, XORPut);
{ стирание шарика }
{ограничения на движения шарика в пределах поля
фона }
if (Sx < 50) or (Sx > maxx – 50 – 2 * r)
then Sxmove:= – Sxmove;
if (Sy < 50) or (Sy > maxy – 50 – 2 * r) then Symove:= – Symove;
Inc(Sx, Sxmove);
{следующая точка появления }
Inc(Sy, Symove);
{шарика на экране }
until KeyPressed;
{... пока не нажата клавиша}
FreeMem(P, Size);
{освобождение памяти буфера}
CloseGraph
{закрытие режима графики}
End.
В примере продемонстрирован алгоритм мультипликации. Скорость движения картинки сильно
зависит от разрешения экрана и количества цветов.
Обращаем внимание на стандартную связку:
Size:= ImageSize(X1, Y1, X2, Y2); {фрагмент в байтах }
GetMem(P, Size);
{размещение буфера}
GetImage(X1, Y1, X2, Y2, P^);
{фрагмент и в буфер}
. . . . . . . . . .
PutImage (X, Y, P^, ***Put);
{вывод фрагмента(ов)}
FreeMem(P,Size);
{освобождение буфера}
организующую хранение динамического фрагмента через переменную P типа Pointer.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. Составить программу, моделирующую абсолютно упругий центральный удар двух шаров с массами
m1 и m2 движущихся со скоростями v1 и v2.
a) m1 = m2 , v1 = 2v2 , шары движутся навстречу друг другу;
b) m1 = m2 , v1 = v2 , шары движутся навстречу друг другу;
c) m1 = 2m2 , v1 = 2v2 , шары движутся навстречу друг другу;
d) m1 = 0.5m2 , v1 = v2 , шары движутся навстречу друг другу;
e) m1 = 2m2 , v1 = 2v2 , один шар догоняет другой;
f) m1 = m2 , v1 = 0.5v2 , один шар догоняет другой;
g) m1 = 0.5m2 , v1 = 2v2 , один шар догоняет другой;
h) m1 = 2m2 , v1 = 4v2 , один шар догоняет другой.
II. Составить программу, моделирующую:
a) процесс колебания математического маятника;
b) пружинного маятника (колебания происходят в направлении оси Y);
c) движение искусственного спутника Земли;
d) движение двух молекул идеального газа в замкнутом сосуде (соударение молекул друг с другом не
учитывать);
e) движение тела, брошенного под углом к горизонту;
f) модель атома Бора;
g) взаимодействие зарядов (одноименных, разноименных);
h) эксперимент по определению скорости пули с помощью баллистического маятника.
III. Изображение прямоугольной области с координатами (X1,Y1), (X2,Y2) в левом верхнем углу
экрана скопировать в свободные углы экрана. При копировании одно изображение инвертировать.
a) в прямоугольной области изображены 5 окружностей разных радиусов с общим центром;
b) многоугольник, закрашенный в мелкую точку;
c) прямоугольник, закрашенный в крупную точку;
d) эллипс, заполненный по шаблону \\\\\\\;
e) пятиугольник, заполненный по шаблону ====== ;
f) шестиугольник, заполненный по шаблону ////;
g) равносторонний треугольник, заполненный по шаблону – – –;
h) олимпийские кольца.
�Оглавлен ие
Лабораторная работа № 20
УПРАВЛЕНИЕ ВИДЕОСТРАНИЦАМИ. ГРАФИЧЕСКИЕ ОКНА. ВЫВОД ТЕКСТА
Управление видеостраницами. Память видеоадаптеров разделена на так называемые страницы, или
видеостраницы. По умолчанию в графическом режиме действия производятся с нулевой страницей.
Однако, если направить вывод изображений на ненулевую страницу (при условии, что такая доступна
в текущем режиме видеоадаптера), то на экране ничего не отобразится, поскольку по умолчанию
видимой является нулевая страница. Если же после этого дать команду считать видимой “скрытую”
страницу, то она появится на экране буквально мгновенно. Проделать все это позволяют две
процедуры:
SetVisualPage(Page: Word),
которая устанавливает “видимой” на экране видеостраницу номер Page, и процедура
SetActivePage(Page: Word),
устанавливающая перенаправление всех графических операций на страницу номер Page (т.е.
делающая активной). Обратите внимание, что активность не тождественна видимости страницы на
экране.
Рассмотрим типичный пример использования этих процедур.
Uses Graph, Crt;
{используются Graph и Crt}
{ $I initgraph.pas }
{инициализация графики}
Procedure Forms (kadr: Byte);
{рисование кадров 0..1}
Const
Radius: Array [0..3] of integer = (20, 40, 60,
80); {радиусы эллипсов в кадрах}
Var
r, rr: Integer;
Begin
r:= Radius [kadr];
{максимальный радиус}
rr:= 0;
{радиус вложенного эллипса}
Repeat
Ellipse (GetMaxX div 2, GetMaxY div 2, 0, 360, r, rr);
Inc (rr, 5);
Until rr >= r;
End;
Procedure Anim;
{процедура смены кадров}
Const
ms = 60;
Var
{задержка между кадрами, мc}
�Оглавлен ие
i: Byte;
{параметр циклов смены}
Begin
repeat
for i:= 0 to 1 do
begin
SetVisualPage (i);
{смены видеостраниц прямо}
Delay (ms)
end;
for i:= 1 downto 0 do
begin
SetVisualPage (i);
{... и обратно}
Delay (ms)
end;
until KeyPressed
{условие окончания показа}
End;
Var
i: Byte;
{параметр (номер кадра)}
Begin
GrInit;
{инициализация графики}
SetGraphMode(GetGraphMode);
{ режим . . . . . }
for i:= 1 downto 0 do
begin
{цикл заполнения страниц}
SetVisualPage (Succ (i) mod 4);
{ видим пустоту }
SetActivePage (i);
{ и готовим кадр }
Forms (i);
{ рисунок кадра }
end;
Anim;
{начало “оживления” кадров}
Close Graph
{закрытие режима графики}
End.
Особенность программы в том, что сначала кадры записываются на соответствующие страницы, а
затем производится последовательное переключение отображения страниц на дисплей процедурой
SetVisualPage.
Графические окна. Графическое окно (viewport) – это область просмотра, окно экрана, в
компьютерной графике – часть пространства отображения, в которой изображается и просматривается
часть моделируемого объекта. При образовании графического окна получается как бы “экран в экране”
�Оглавлен ие
заданного размера.
В модуле Graph для описания графического окна объявлен следующий тип и две константы:
Type
ViewPortType = Record
X1, Y1, X2, Y2: Integer;
{границы окна}
Clip: Boolean;
{режим отсечения}
End;
Const
ClipOn= True;
{отсечение по границе окна включено}
ClipOff= False;
{отсечение по границе окна выключено}
Значение ClipOn указывает на то, что все элементы изображения, попавшего за границы области
окна, обрезаются по границам графического окна, а ClipOff указывает на то, что все рисуется без
изменений, как бы “не глядя” на границы окна.
Объявление графического окна производится процедурой
SetViewPort (X1, Y1, X2, Y2: Integer; ClipMode: Boolean),
где входные параметры соответствуют полям записи типа ViewPortType. После выполнения этой
процедуры все текущие установки станут относиться к окну. Текущий указатель установится в его
левый верхний угол, и туда же переносится начало системы координат дисплея, т.е. мы получаем
локальную систему координат.
Если параметры процедуры заданы неправильно, то функция GraphResult возвращает ошибку
grError (– 11).
Назначение графического окна можно использовать для перемещения начала системы координат. Так,
если задать окно вызовом
SetViewPort (GetMaxX div 2, GetMaxY div 2, GetMaxX, GetMaxY, ClippOff),
то получим систему координат с началом в центре экрана. При этом станет “видимой” адресация
отрицательных координат. Графическое окно не меняет масштаба системы координат, а лишь
выбирает систему отсчета адресуемых пикселов.
Для определения текущих параметров графического окна используют процедуру
GetViewSettings (Var ViewSettings: ViewPortType).
Если воспользоваться ею сразу после инициализации графического режима, то обнаружится, что
графическим окном является весь экран.
Для очистки графического окна служит специальная процедура
ClearViewPort.
Процедура PutImage работает одинаково как для значения параметра ClipOn, так и для ClipOff. Об
этом следует помнить при использовании данной процедуры.
Вывод текста. Вывод текста в графическом режиме имеет ряд особенностей. Основное отличие в
�Оглавлен ие
том, что все действия производятся только со строковыми константами и переменными, т.е. вся
числовая информация должна предварительно преобразовываться в строковую (процедурой Str).
Другое отличие в том, что можно использовать различные шрифты.
В комплекте поставки есть файлы с расширением .CHR. Это набор штриховых шрифтов, которые могут
быть использованы для вывода информации. Поскольку они построены не матричным способом (как
сделаны стандартные шрифты для текстового режима), а векторным, можно изменять размеры
шрифтов без потери качества их изображения.
С пакетом Turbo Pascal поставляется 4 шрифта. Кроме того, доступен системный матричный шрифт
88 для графических режимов (всегда доступны символы с кодами от 0 до 127 и символы с кодами от
128 до 255 при условии, что их матрицы загружены в память ЭВМ.
Для обозначения шрифтов введены пять констант:
Const
DefaultFont = 0;
{матричный шрифт 8x8 (по умолчанию)}
TriplexFont = 1;
{полужирный}
SmallFont
{светлый шрифт (тонкое начертание)}
= 2;
SansSerifFont = 3;
{рубленый шрифт}
GothicFont = 4;
{готический шрифт}
Активизация любого из названных шрифтов осуществляется процедурой
SetTextStyle (Font, Direction: Word; CharSize: Word).
Здесь параметр Font – номер шрифта, Direction – расположение. Возможны лишь две ориентации
текста, обозначенные константами
Const
HorizDir = 0;
{горизонтальное, слева направо}
VertDir = 1;
{вертикальное, снизу вверх}
На самом деле есть еще один вариант регулирования направления шрифтов. Если задать Direction =
2, то буквы будут повернуты так же, как и при Direction = VertDir, но вывод строки будет
производиться горизонтально, слева направо.
Размер символа устанавливается параметром CharSize, диапазон изменения которого составляет от 0
до 10. Стандартное значение для матричного шрифта 88 равно 1, а для штриховых шрифтов – 4.
При каждом вызове процедурой SetTextStyle какого–либо шрифта он загружается в память ЭВМ.
Поэтому, если программа использует штриховые шрифты, необходимо, чтобы файлы этих шрифтов
находились в известном каталоге совместно с BGI–файлами.
Для вывода текста есть две процедуры:
OutText (TexString: String),
которая выводит на графический экран строку TexString, ориентированную относительно позиции
текущего указателя, и
OutTextXY (TexString: String),
�Оглавлен ие
которая выводит строку, ориентированную относительно координат (X,Y). Шрифт предварительно
может быть установлен вызовом SetTextStyle. Существует несколько вариантов ориентировки
строки относительно стартовой точки. Они задаются процедурой
SetTextJustify (Horisontal, Vertical: Word),
параметры которой могут принимать одно из трех объявленных в модуле Graph значений:
Const
{ для горизонтального ориентирования }
LeftText
= 0;
{ координата X задает левый край строки }
CenterText = 1;
{ координата X задает середину строки }
RightText = 2;
{ координата X задает правый край строки}
BottomText = 0;
{ координата Y задает нижний край строки }
CenterText = 1;
{ координата Y задает середину строки }
{ для вертикального ориентирования }
TopText
= 2;
{ координата Y задает верхний край строки}
Эта процедура позволяет ориентировать выводимую строку относительно стартовой координаты
(X,Y). По умолчанию параметры соответствуют LeftText, TopText.
Текстовые процедуры GoToXY, Write/Writeln и установки цвета текста в графическом режиме
работают только, если переменная модуля CRT – DirectVideo равна False (или модуль CRT не
подключен). Ввод текста через Read/Readln действует всегда. При этом текст стирает фоновое
изображение.
При выводе текста всегда важно знать вертикальный и горизонтальный размер выводимой строки в
пикселах. Это позволяет располагать строки пропорционально разрешающей способности
графического режима.
Функции
TextHeight (TextString: String): Word
TextWidth (TextString: String): Word
возвращают высоту и ширину строк TextString в пикселах, при условии, что они будут выведены
текущим шрифтом и размером.
Пример анализа расположения строк текста приведен ниже:
Uses Graph;
{ $I initgraph.pas }
Const
my_str = 'Turbo Pascal';
{выводимая строка }
maxx, maxy: Integer;
{текущее разрешение экрана}
tx, ty, i, j: Word;
{временные переменные}
Var
�Оглавлен ие
Begin
GrInit;
maxx:= GetMaxX; maxy:= GetMaxY;
{разрешение}
SetTextJustify (CenterText, CenterText);
{ориентация }
SetTextStyle (SmallFont, HorizDir, 6);
{стиль шрифта }
tx:= TextWidth (my_str);
{ширина строки }
ty:= TextHeight (my_str);
{высота строки }
for j:= 1 to (maxy div ty) do
{цикл по оси Y }
for j:= 1 to (maxx div tx) do
{цикл по оси X }
OutTextXY (i * tx, j* ty, my_str);
{тело циклов }
SetTextStyle (DefaultFont, HorizDir, 6);
{смена шрифта }
tx:= TextWidth ('W') div 6;
{1/6 ширины }
ty:= TextHeight ('E') div 6;
{1/6 высоты }
SetColor (LightRed);
OutTextXY (maxx div 2 + tx, maxy div 2 + ty, my_str);
Readln;
{пауза до нажатия ввода }
CloseGraph
{закрытие режима графики}
End.
У процедуры OutTextXY есть одна особенность: выводимая текстовая строка всегда обрезается по
границе графического окна. Более того, если активным является матричный шрифт (DefaultFont), то
“вылезающая” строка вообще не выводится на экран. Решать подобные проблемы можно, точно
рассчитывая место выводимых в графике строк.
Размер букв (высота и ширина) штриховых шрифтов (и только их) может задаваться процедурой
SetUserCharSize (multX, divX, multY, divY: Word).
Она позволяет оперативно менять размер шрифта, установленный SetTextStyle. Отношение
multX/divX задает масштабирование ширины начертания шрифта, а отношение multY/divY
выражает масштаб изменения высоты шрифта. Например, задание multX = 3 и divX = 1 говорит о
том, что буквы выводимого шрифта будут в три раза шире нормы.
Полную информацию о текущем режиме вывода текста можно получить, используя процедуру
GetTextSettings (Var Settings: TextSettingsType).
В параметре Settings она возвращает информацию обо всем, что относится к выводу строк. Тип
этого параметра определен в модуле Graph:
Type
TextSettingsType = Record
Font: Word;
{номер шрифта}
�Оглавлен ие
Direction: Word;
{направление }
CharSize: Word;
{размер шрифта }
Horiz: Word;
{ориентация по X }
Vert: Word;
{ориентация по Y }
End;
Текущим всегда является один тип. При необходимости быстро переключаться с одного шрифта на
другой удобно сохранять и восстанавливать их параметры через переменные описанного типа.
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
1. Создайте на экране четыре окна. В двух окнах поместите простые графические рисунки (например,
ряд концентрических окружностей разного цвета) с использованием различных режимов отсечения. В
два других окна поместите тексты, иллюстрирующие возможность использования шрифтов разного
типа, размера и расположения.
2. Подобным образом заполните пассивную страницу. Организуйте переключение между страницами
по нажатию клавиши “пробел”.
�Оглавлен ие
Лабораторная работа № 21
УПРАВЛЕНИЕ КЛАВИАТУРОЙ
Технические особенности клавиатуры. Клавиатура ПЭВМ – достаточно сложное устройство,
содержащее разнообразные электронные компоненты, в том числе встроенный микропроцессор. Он
устраняет многочисленные ложные импульсы, возникающие в момент нажатия клавиши и ее
отпускания, и тем самым разгружает центральный процессор. Кроме того, микропроцессор
запоминает коды нажатых клавиш в буферной памяти, если по каким-либо причинам центральный
процессор не успевает их обработать достаточно быстро, а затем по запросу центрального процессора
передает их из памяти в том порядке, в каком они туда поступали. Наконец, микропроцессор следит за
временем, в течении которого клавиша удерживается в нажатом состоянии и осуществляет автоповтор
кода клавиши, если это время превышает одну-две секунды.
С точки зрения программирования, наиболее существенным обстоятельством является то, что коды,
вырабатываемые клавиатурой и коды, передаваемые в программу – это разные коды. Выработанный
клавиатурой код называется кодом сканирования. Кодов сканирования ровно столько, сколько клавиш
на клавиатуре. Именно эти коды поступают от микропроцессора клавиатуры. Чтобы сообщить
центральному процессору о готовности клавиатуры к передаче кода, микро-процессор вырабатывает
прерывание с номером 9. Программа обработки этого прерывания (драйвер клавиатуры) входит в
состав DOS и размещается в ПЗУ. Драйвер клавиатуры осуществляет преобразование кода
сканирования с учетом того, что могут быть одновременно нажаты две или более клавиш (например,
клавиша Shift и какая - нибудь литерная клавиша). В результате этого преобразования на выходе
драйвера клавиатуры формируется тот код, который и воспринимается программой.
Микропроцессор клавиатуры дважды вырабатывает прерывание 9 – в момент нажатия клавиши и в
момент ее отпускания. При отпускании клавиши передается двухбайтовая последовательность: сначала
код $F0 (240), а затем код сканирования клавиши. Именно поэтому программа обработки
прерываний может следить за одновременным нажатием нескольких клавиш.
На клавиатуре ПЭВМ имеются три особые клавиши, называемые клавишами смещения – они
предназначены для расширения возможностей клавиатуры. К ним относятся клавиши Shift
(временная смена регистра), Alt (дополнительный регистр) и Ctrl (управляющий регистр).Драйвер
клавиатуры никогда не сообщает программе о нажатии на эти клавиши, однако он соответствующим
образом преобразует код сканирования, так что, например, а и А имеют разные коды, хотя вызываются
нажатием на одну и ту же клавишу.
Стандартная клавиатура IBM AT имеет 101 (или 102) клавишу. С учетом возможностей
использования литерных клавиш совместно с тремя клавишами смещения, число возможных
комбинаций составляет около 400, что много больше емкости одного байта. Поэтому информация на
выходе драйвера клавиатуры должна кодироваться двумя байтами, причем далеко не каждая
комбинация может быть отражена условным знаком (символом) на экране.
Все обычные алфавитно-цифровые клавиши, как в нижнем, так и в верхнем регистрах, вырабатывают
на выходе драйвера однобайтный код символа. Этот код совпадает с указанным в таблице ASCII
кодом соответствующего символа. Некоторые специальные клавиши, такие как F1...F10, курсорные
клавиши и др., а также комбинации всех клавишей с Alt и Ctrl – вырабатывают коды из так
называемого
расширенного
набора
символов.
Эти
коды
передаются
двухбайтной
последовательностью, причем первый байт в этой последовательности нулевой. В таблице 1
приведены коды из расширенного набора.
�Оглавлен ие
Таблица 1
Код
Клавиша или комбинация клавиш
3
Ctrl-2
15
Shift-Tab
16...25
Alt-Q...Alt-P (верхний ряд букв)
30...38
Alt-A...Alt-L (средний ряд букв)
44...50
Alt-Z...Alt-M (нижний ряд букв)
59...68
F1...F10
71
Home
72
Курсор вверх
73
PageUp
75
Курсор влево
77
Курсор вправо
79
End
80
Курсор вниз
81
PageDown
82
Insert
83
Delete
84...93
Shift-F1...Shift-F10
94...103
Ctrl-F1...Ctrl-F10
104...113
Alt-F1...Alt-F10
114
Ctrl-PrintScreen
115
Ctrl-курсор влево
116
Ctrl-курсор вправо
117
Ctrl-End
118
Ctrl-PageDown
119
Ctrl-Home
120...131
132
Alt-1...Alt-= (верхний ряд клавишей)
Ctrl-PageUp
Как видно из этой таблицы используются далеко не все коды и возможны не все комбинации
клавишей. При вводе не предусмотренных комбинаций драйвер их просто игнорирует. Некоторые
комбинации имеют специальное назначение – они не могут восприниматься программой, но
обрабатываются операционной системой. Так, например, Ctrl-S (Ctrl-C) приводит к приостановке
работы программы, Ctrl-Break вообще прекращает ее выполнение, Ctrl-Alt-Del вызывает
перезагрузку компьютера, PrintScreen приводит к копированию содержимого экрана с помощью
�Оглавлен ие
принтера.
Кроме клавишей смещения на клавиатуре имеются четыре клавиши переключателя: Insert
(включение/отключение режима вставки символов), CapsLock (фиксация режима заглавных букв),
NumLock (фиксация дополнительных цифровых и служебных клавишей) и ScrollLock (фиксация
режима прокрутки экрана). В DOS выделены два байта с адресами 1047 и 1048, в которых хранится
информация о состоянии этих переключателей.
Комбинация Ctrl-NumLock приводит к так называемому состоянию захвата: в этом состоянии
драйвер непрерывно сканирует клавиатуру, ожидая нажатие на любую клавишу. В состоянии захвата
не может исполняться ни одна программа, кроме процедур обработки прерываний.
Управление клавиатурой. Для управления клавиатурой в Turbo Pascal имеется несколько
возможностей разного уровня. Прежде всего это стандартные процедуры Read и Readln. Это
процедуры самого верхнего логического уровня – они не только осуществляют взаимодействие с
драйвером клавиатуры, но и преобразуют символьные данные во внутренний формат представления
соответствующих переменных. Однако они обладают тремя существенными недостатками. Во-первых,
с их помощью невозможно опознать нажатие на любые не литерные клавиши (например, на клавиши
управления курсором). Во-вторых, ввод символов с помощью этих процедур сопровождается их
воспроизведением (эхо - повтором) на экране, что не всегда удобно. В-третьих, обращение к этим
процедурам приостанавливает выполнение программы до нажатия клавиши ввода.
Почти все перечисленные недостатки можно преодолеть, если обратиться к двум функциям
стандартного модуля CRT.
Функция KeyPressed. Возвращает значение типа Boolean, указывающая была ли нажата какая нибудь клавиша после последнего чтения из буфера клавиатуры или нет. Обращение
KeyPressed;
Обращение к этой функции никак не влияет ни на подготовленный клавиатурой код нажатой клавиши,
ни на саму функцию KeyPressed: сколько бы раз мы не обращались к ней, она будет возвращать True,
если была нажата какая - либо клавиша, – до тех пор, пока буфер клавиатуры будет прочитан
процедурами Read/Readln или функцией ReadKey. Функция не задерживает работу программы и
возвращает False, если ни одна клавиша не была нажата.
Функция ReadKey. Возвращает значение типа Char – код очередной нажатой клавиши. Обращение
ReadKey;
В отличие от KeyPressed эта функция приостанавливает работу программы до тех пор, пока не будет
нажата любая клавиша. Замечательной особенностью этой функции является то, что с ее помощью
можно опознать нажатие почти на любую клавишу – исключение составляют только клавиши
смещения и клавиши - переключатели. Кроме того, функция вводит символ “вслепую”, т.е. без эхо повтора на экране.
Приводимый ниже пример иллюстрирует возможность опознавания нажатия на клавиши,
генерирующие расширенные коды:
Uses CRT;
Var
ExtChar: Boolean;
{флаг – признак расширенного кода}
�Оглавлен ие
c: Char;
{вводимый символ}
................
Begin
................
c:=ReadKey;
if c=#0 then ExtChar:=True
else ExtChar:=False;
if ExtChar then c:=ReadKey;
................
Следующая программа читает клавиатуру и выводит на экран коды клавишей, до тех пор, пока не будет
нажата комбинация клавиш Ctrl+2:
Program TestOfKeyboard;
Uses CRT;
Var
c1,c2: char;
BEGIN
repeat
c1:=ReadKey;
if c1 = #0 then c2:=ReadKey;
if c1 = #0 then writeln(ord(c1):5, ord(c2):5)
else writeln(ord(c1):5)
until (c1 = #0) and (c2 = #3)
END.
Функции KeyPressed и ReadKey относятся к среднему логическому уровню работы с клавиатурой.
Как уже отмечалось, с их помощью невозможно опознать нажатие на клавиши смещения и клавиши
переключатели. Это становится возможным при переходе на самый нижний логический уровень,
связанный с непосредственным обращением к драйверу клавиатуры или самой клавиатуре. Такие
обращения реализуются с помощью двух прерываний – прерывания с номером 9 – от микропроцессора
клавиатуры и с номером 22 – обращение к драйверу.
Прерывание с номером 22 содержит следующие функции:
AH=0 – читать символ с ожиданием нажатия на клавишу;
AH=1 – проверить готовность клавиатуры;
AH=2 – прочитать статус (байт с адресом 1047).
При обращении к функции АН=0 в AL возвращается код нажатой клавиши или 0; если эта клавиша
генерирует код из расширенного набора, в АН возвращается код сканирования клавиши. При
�Оглавлен ие
обращении к функции АН=2 в регистре АН возвращается содержимое байта с адресом 1047.
Следующая программа читает и выводит коды сканирования клавишей до тех пор, пока не будет
нажата клавиша Esc:
Program ScanCodesDemo;
Uses DOS;
Var
r: registers;
BEGIN
with r do
begin
repeat
repeat
Flags:=0; AH:=1; Intr(22,r);
until Flags<>2022;
AH:= 0;
Intr(22,r);
writeln(AL:5, AH:5);
until (AL=27) and (AH=1)
end
END.
Довольно часто возникает необходимость очистить буфер ввода клавиатуры. Это позволяет сделать
следующий прием:
Var
c: Char;
.................
while KeyPressed do c:=ReadKey;
�Оглавлен ие
КОНТРОЛЬНЫЕ ЗАДАНИЯ
I. При запуске файла Turbo.exe на экране монитора появляется исходное изображение:
Составить программу рисующую эту заставку и позволяющую выполнять операции по активизации
опций основного меню (верхняя строка). Выбор опций производится клавишами “стрелка вправо”,
“стрелка влево”, “стрелка вниз”, “стрелка вверх”. При нажатии клавиши “ввод” активизируется
соответствующее подменю: File, Edit, Run, Compile, Options, Debug, Break/watch и
исчезает центральная часть изображения.
Варианты:
1. активизируется подменю File;
2. активизаруется подменю Edit;
3. активизаруется подменю Run;
4. активизаруется подменю Compile;
5. активизаруется подменю Options;
6. активизаруется подменю Debug;
7. активизаруется подменю Break/watch;
8. при нажатии клавиши F10 активизируется главное меню.
II. Составить программу управления объектом при помощи клавиш управления курсором. При это
нажатие клавиши “стрелка вправо”, “стрелка влево”, “стрелка вверх”, “стрелка вниз” изменяет
координаты объекта на dX и dY соответственно, а попарное нажатие этих клавиш (например,
“стрелка влево” + “стрелка вверх”) проводит к одновременному изменению координат X и Y. Значение
текущих координат объекта индицируется в левом верхнем углу экрана. Для вывода значений
координат использовать процедуры write/writeln и OutTextXY. В качестве объекта использовать
точку, оставляющую след на экране при перемещении. Предусмотреть возможность отключения
“следа”.
�Оглавлен ие
Лабораторная работа № 22
ОСНОВНЫЕ ПОНЯТИЯ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ
В Турбо Паскале, начиная с версии 5.0, наряду со стандартными типами данных, введен
процедурный тип. Он позволяет рассматривать обычные процедуры и функции как новую
разновидность переменных.
Описание этого типа производится по принятым в Турбо Паскале правилам, например:
Type
NewProc=Procedure(St: string, i,j: byte);
NewFunc=Function(X,Y: real): string;
Из этого примера видно, что при объявлении процедурного типа используются зарезервированные
слова Procedure и Function, после которых производится описание всех параметров, а для функции
дополнительно указывается тип результата.
После того, как описан процедурный тип данных, становится возможным использование в программе
и переменных данного типа. Их объявление производится обычным способом:
var
a, b: NewProc;
c, d: NewFunc;
Если в программе встречается переменная процедурного типа, то происходит выполнение
соответствующей процедуры или функции с заданными после идентификатора переменной
параметрами. Процедурный тип совместим со стандартным типом Pointer, и процедурная
переменная после установки ее значения содержит указатель на выполнимый код процедуры или
функции.
Для корректного выполнения присваивания значений переменных процедурного типа программа,
содержащая такие переменные, должна компилироваться с использованием дальней модели памяти,
то есть с установленной опцией OPTION/COMPILLER/FORCE FAR (директива компилятора {$F+}).
Кроме того, в объявлении процедурного типа не могут быть использованы процедуры и функции,
зарезервированные в любом из стандартных модулей Турбо Паскаля и процедуры типа Inline.
После выполнения операции присваивания имя переменной становится синонимом имени
соответствующей процедуры или функции.
Следующий простой пример иллюстрирует использование данных процедурного типа:
Program DataProc;
Type
Sum= Function(X,Y: integer): integer;
var
S: Sum;
I,J: integer;
{$F+}
�Оглавлен ие
Function Summa(X,Y: integer): integer;
Begin
Summa:=X+Y;
End;
{$F-}
BEGIN
Write('Введите первое слагаемое '); Readln(I);
Write('Введите второе слагаемое '); Readln(J);
S:=Summa;
Writeln('Сумма чисел ',I,' и ',J,' равна ', S(I,J));
END.
Следует отметить, что в Турбо Паскале в передаваемой процедурной переменной могут быть
использованы как параметры-значения, так и параметры-переменные.
Следующим шагом в развитии типов данных является появление в Турбо Паскале (начиная с версии
5.5) объектного типа данных, в котором происходит объединение данных и операций над ними.
Объектный тип составляет основу объектно-ориентированного программирования (ООП).
Описание этого типа происходит в разделе Type с использованием зарезервированных слов Object
и End. Данные объектного типа определяются значениями своих полей (как и записи – данные типа
Record) и процедурами и функциями, определяющими правила обработки полей.
Например:
Type
Str= string;
Data=byte;
StudentType=object
Famaly: Str;
Name: Str;
Grup: Str;
Procedure Init(Fm,Nm,Gr: Str);
Procedure Show;
end;
DataType=object(StudentType)
DataMath: Data;
DataPhis: Data;
DataInf: Data;
Procedure Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
�Оглавлен ие
Procedure Show;
end;
В этом примере тип данных StudentType определен как объект. Он содержит три поля Famaly,
Name и Grup, принадлежащие к типу string. Процедуры Init и Show устанавливают правила или
методы работы с полями объекта. Естественно, что они должны быть описаны в вашей программе.
Тип данных DataType описан как объект, порожденный объектом StudentType или, как говорят,
объект DataType является потомком объекта StudentType. В описании типов этому соответствует
слово object и идентификатор объекта-родителя. В Турбо Паскале принято соглашение, согласно
которому объект-потомок наследует все поля и методы объекта-родителя. Поэтому объект типа
DataType, кроме своих собственных полей DataMath, DataPhis и DataInf будет содержать и
наследуемые поля Famaly, Name и Grup.
Непосредственное определение объекта (экземпляра объекта) происходит в разделе описания
переменных, например:
var
Std1, Std2: StudentType;
Dt1, Dt2: DataType;
В результате такого объявления в памяти будет выделено соответствующее место для размещения
объектов Std1 и Std2 типа StudentType и объектов Dt1 и Dt2 типа DataType, после чего
становится возможным обращение к полям и методам этих объектов. Как и в случае записей, для этих
целей можно использовать оператор With или непосредственное обращение к нужному полю:
With Std1 do begin
Famaly:=‘Иванов’;
Name:=‘Сергей’;
Grup:=‘542’;
Еnd;
Dt1.DataPhis:=4;
Dt1.DataMath:=4;
Вместе с тем, как будет видно из дальнейшего знакомства с методами ООП, прямое обращение является
не лучшим способом инициализации полей объекта. Более корректно для этих целей использовать
специальные правила – каковыми и являются методы Init, включенные в описания типов
StudentType и DataType.
Описанием типа, разумеется, не заканчивается формирование объекта – необходимо написать еще
коды процедур и функций (то есть методов), включенных в описание типа объекта. Лишь после этого
объект сможет выступать как единое целое, в неразрывной связи своих свойств и поведения. Такое
объединение кода и данных при создании типа объекта носит название инкапсуляции.
Заголовки методов при их описании должны соответствовать тем, которые указаны в разделе Type.
Так как сразу несколько типов объектов могут иметь правила с одинаковыми именами, то перед
заголовком метода указывается через точку наименование типа объекта. Так, например, описание
методов Init и Show для объектов типа StudentType может выглядеть следующим образом:
�Оглавлен ие
Procedure StudentType.Init(Fm,Nm,Gr: Str);
Begin
Famaly:=Fm;
Name:=Nm;
Grup:=Gr;
End;
Procedure StudentType.Show;
Begin
Writeln;
Writeln('ФАМИЛИЯ: ',Famaly);
Writeln('ИМЯ: ',Name);
Writeln('ГРУППА: ',Grup);
End;
Первая процедура предназначена для инициализации полей объекта, вторая – для вывода их значений
на экран. Объединение через точку имен Init и StudentType служит для указания компилятору, что
процедура Init является методом, принадлежащим объекту типа StudentType. Обращение к полям
объекта внутри процедуры происходит как к обычным переменным, без непосредственного указания
на то, какому объекту эти поля принадлежат.
Как указывалось выше, объект DataType является потомком объекта StudentType, соответственно
последний выступает в роли родителя или предка. Если теперь построить объект-потомок от объекта
DataType, то он будет потомком и объекта StudentType, но уже более далеким. В устанавливаемых
отношениях наследования важным является то, что каждый объект может иметь сколько угодно
потомков, но лишь одного близкого предка. Используя один родительский тип, можно построить
иерархию или дерево порожденных объектов.
В механизме наследования можно условно выделить два основных момента: наследование полей и
наследование методов. Объект типа DataType автоматически унаследовал поля Famaly, Name и
Grup. Поэтому в его описании нет упоминания об этих полях.
Наследование правил имеет свои особенности. Тип DataType наследует от своего предка два метода
Init и Show, служащие для инициализации полей и вывода их значений на экран. Однако, у объекта
DataType число полей на три больше, поэтому для него придется ввести новые правила:
Procedure DataType.Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
Begin
StudentType.Init(Fm,Nm,Gr);
DataMath:=Mt;
DataPhis:=Ph;
DataInf:=Inf;
�Оглавлен ие
End;
Procedure DataType.Show;
Begin
StudentType.Show;
Writeln('МАТАНАЛИЗ: ',DataMath);
Writeln('ОБЩАЯ ФИЗИКА: ',DataPhis);
Writeln('ИНФОРМАТИКА: ',DataInf);
End;
В описании происходит обращение к родительским методам Init и Show, при этом для методов
объекта потомка сохранены старые наименования, хотя текст процедур стал иным. Использование
одинаковых имен методов для порожденных объектов называется полиморфизмом и отражает важное
свойство ООП. Оно заключается в том, что под наследованием правила для всей иерархии
порожденных объектов подразумевается конкретное логическое действие над объектами, а не способ
его реализации. Так метод Init описывает инициализацию полей объекта, независимо от его типа.
Созданные объекты удобно хранить в отдельном модуле, подключая его к программе с помощью
стандартной директивы Uses. Напомним, что модуль в Турбо Паскале имеет стандартную структуру
программы, но начинается не служебным словом Program, а словом Unit, после которого идет имя
модуля. Описание объектов располагается в секции модуля INTERFACE, а описание методов – в
секции IMPLEMENTATION. Для наших объектов модуль выглядит следующим образом:
Unit Student;
INTERFACE
Type
Str= string;
Data=byte;
StudentType=object
Famaly: Str;
Name: Str;
Grup: Str;
Procedure Init(Fm,Nm,Gr: Str);
Procedure Show;
end;
DataType=object(StudentType)
DataMath: Data;
DataPhis: Data;
DataInf: Data;
Procedure Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
�Оглавлен ие
Procedure Show;
end;
IMPLEMENTATION
Procedure StudentType.Init(Fm,Nm,Gr: Str);
Begin
Famaly:=Fm;
Name:=Nm;
Grup:=Gr;
End;
Procedure StudentType.Show;
Begin
Writeln;
Writeln('ФАМИЛИЯ: ',Famaly);
Writeln('ИМЯ: ',Name);
Writeln('ГРУППА: ',Grup);
End;
Procedure DataType.Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
Begin
StudentType.Init(Fm,Nm,Gr);
DataMath:=Mt;
DataPhis:=Ph;
DataInf:=Inf;
End;
Procedure DataType.Show;
Begin
StudentType.Show;
Writeln('МАТАНАЛИЗ: ',DataMath);
Writeln('ОБЩАЯ ФИЗИКА: ',DataPhis);
Writeln('ИНФОРМАТИКА: ',DataInf);
End;
BEGIN
END.
Теперь модуль следует сохранить в файле с таким же именем (в нашем случае – в файле
�Оглавлен ие
Student.pas). Соответственно, исполняемая программа примет вид:
Program Stud;
USES Student;
var
NameStd: StudentType;
DataStd: DataType;
Begin
NameStd.Init('Иванов','Петр','544');
NameStd.Show;
DataStd.Init('Иванов','Петр','544',3,5,4);
DataStd.Show;
End.
Напомним, что компиляцию данной программы необходимо производить в режиме Make или Build
опции COMPILER.
Правила и объекты, которые мы использовали в этом примере, являются статическими. Компилятор
резервирует для них место в памяти точно так же, как он это делает для обычных переменных. Если
названного по имени правила не оказывается у объекта данного уровня, то поиск его продолжается у
родителя на более высоком уровне в дереве иерархии. Если и у корневого объекта дерева не находится
правила с заданным именем, то компилятор выдает сообщение об ошибке. Для обращения к
статическому правилу родителя необходимо указать тип родителя и, через точку, имя правила.
Статические правила сильно привязаны к типу объекта, для которого они были введены. Этого
недостатка лишены виртуальные правила. Подобно динамическим переменным виртуальные правила
не имеют полного определения в памяти до непосредственного выполнения программы. При их
объявлении добавляется зарезервированное слово Virtual:
Procedure Show; virtual;
Следует помнить, что, однажды определив правило как виртуальное, необходимо определять его
таковым и для всех объектов-потомков.
Следующий шаг – придание свойства динамичности самим объектам. Это можно сделать, вводя
указатели на экземпляры объектов, например:
Type
PStudentType=^StudentType;
PDataType=^DataType;
var
PNamStd: PStudentType;
PDataStd: PDataType;
Обращение к динамическим объектам становится возможным только после выделения памяти в куче
(Heap). Это можно сделать, используя стандартную процедуру New:
�Оглавлен ие
New(PDataStd);
После этого обращение к экземпляру объекта производится с помощью соответствующей
переменной-указателя PDataStd^. Так, чтобы проинициализировать поля экземпляра объекта
PDataStd^, достаточно выполнить следующее обращение:
PDataStd^.Init(‘Иванов’,’Петр’,’543’,2,4,3);
Необходимость инициализации любого объекта и некоторая шаблонность необходимых для этого
действий привели к появлению в Турбо Паскале двух новых зарезервированных слов Constructor
и Destructor. В синтаксис стандартных процедур New и Dispose добавлен второй необязательный
параметр-указатель на специальное правило объекта. Это правило носит название конструктор и
предназначено для размещения динамического объекта в памяти и инициализации его полей. Для его
описания и используется ключевое слово Constructor, заменяющее слово Procedure. Выделение
памяти для динамического объекта PDataStd с одновременной инициализацией его полей
осуществляется с помощью процедуры
New(PDataStd, Init(‘Иванов’,’Петр’,’543’,2,4,3));
Обратиться к New можно и как к функции:
PDataStd:= New(PDataType, Init(‘Иванов’,’Петр’,’543’,2,4,3));
Результатом функционального вызова New будет значение указателя на распределенный динамический
объект в куче. Соответственно, вместо первого параметра используется тип указателя на объект.
Деструктор предназначен для очистки и освобождения из памяти динамических объектов с помощью
расширенного вызова стандартной процедуры Dispose . При этом объем освобождаемой памяти
точно соответствует размеру объекта. Для нашего примера текст деструктора имеет вид:
Destructor StudentType.Done;
Begin
End;
Destructor DataType.Done;
Begin
End;
Для освобождения из кучи ранее распределенного динамического объекта PDataStd следует
использовать вызов
Dispose(PDataStd, Done);
С учетом всех сделанных выше замечаний наш модуль Student принимает вид
Unit Student;
INTERFACE
Uses Crt;
Type
Str= string;
Data=byte;
�Оглавлен ие
PStudentType=^StudentType;
StudentType=object
Famaly: Str;
Name: Str;
Grup: Str;
Constructor Init(Fm,Nm,Gr: Str);
Destructor Done; virtual;
Procedure Show; virtual;
Procedure ShowClrScr;
end;
PDataType=^DataType;
DataType=object(StudentType)
DataMath: Data;
DataPhis: Data;
DataInf: Data;
Constructor Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
Destructor Done; virtual;
Procedure Show; virtual;
end;
IMPLEMENTATION
Constructor StudentType.Init(Fm,Nm,Gr: Str);
Begin
Famaly:=Fm;
Name:=Nm;
Grup:=Gr;
End;
Procedure StudentType.Show;
Begin
Writeln;
Writeln('ФАМИЛИЯ: ',Famaly);
Writeln('ИМЯ: ',Name);
Writeln('ГРУППА: ',Grup);
End;
Constructor DataType.Init(Fm,Nm,Gr: Str; Mt,Ph,Inf: Data);
�Оглавлен ие
Begin
StudentType.Init(Fm,Nm,Gr);
DataMath:=Mt;
DataPhis:=Ph;
DataInf:=Inf;
End;
Procedure DataType.Show;
Begin
StudentType.Show;
Writeln('МАТАНАЛИЗ: ',DataMath);
Writeln('ОБЩАЯ ФИЗИКА: ',DataPhis);
Writeln('ИНФОРМАТИКА: ',DataInf);
End;
Procedure StudentType.ShowClrScr;
Begin
ClrScr;
Show;
End;
Destructor StudentType.Done;
Begin
End;
Destructor DataType.Done;
Begin
End;
BEGIN
END.
Исполняемая же часть программы может быть записана в виде:
Program Stud;
USES Student;
var
NameStd: StudentType;
DataStd: DataType;
PStudent: PStudentType;
PData: PDataType;
�Оглавлен ие
Begin
DataStd.Init('Иванов','Петр','544',3,5,4);
DataStd.ShowClrScr;
New(PData,Init('Иванов','Петр','544',3,5,4));
NameStd.Init('Петров','Иван','545');
PStudent:=@NameStd;
PStudent^.Show;
PStudent:=PData;
PStudent^.Show;
Dispose(PStudent,Done);
End.
�Оглавлен ие
Задания для самостоятельной работы
Просмотрите выполнение программы Stud в пошаговом режиме (опции RUN/GO TO CURSOR и
RUN/STEP OVER), следя за изменением полей объектов (опция DEBUG/WATCHES/ADD WATCH).
Создайте объект-потомок объекта DataType, содержащий дополнительное поле Stipend со
значениями ‘Yes’ и ‘No’.
�Оглавлен ие
Лабораторная работа № 23
ЭЛЕМЕНТЫ TURBO VISION
Рассмотренный в предыдущей работе пример создания программы с использованием основных
методов ООП (объектно-ориентированного программирования), несмотря на его простоту и
невыразительность, демонстрирует, тем не менее, многие преимущества такого подхода:
1. Становится совершенно прозрачной структура исполняемой части программы. Программа,
написанная с использованием принципов ООП, должна выполнить три основных действия:
инициализировать объект (процедура Init), показать объект (процедура Show), закрыть объект
(процедура Done).
2. Создание объекта отделено от написания кода программы. Для того, чтобы использовать созданный
объект, совсем не нужно знать, как выглядят включенные в него методы, то есть как устроен блок
IMPLEMENTATION соответствующего модуля – вполне достаточно сведений о том какие поля имеются
у объекта и какими методами он располагает. В этом смысле "объект" в ООП действительно объект –
он имеет определенную "форму" и "знает, как себя вести".
3. Если имеющийся объект чем-то Вас не устраивает, нет нужды менять код модуля, который этот
объект описывает. Принцип наследования позволяет изменять объекты, расширяя их. Вы создаете
объект-потомок, добавляя новые поля и перекрывая унаследованные методы.
Ясно, что указанные преимущества могут проявиться в полной мере лишь при написании сложных
программ, требующих многократного повторения сходных действий. Примером таких программ могут
служить программы, требующие разветвленного пользовательского интерфейса – системы меню,
строк-подсказок, окон помощи, окон ввода данных и так далее. Понятно, насколько бы упростилось
создание подобных программ, если бы в нашем распоряжении имелась библиотека соответствующих
объектов. Turbo Vision и есть такая библиотека! Если Вы работаете в текстовом режиме (хотя
Turbo Vision не исключает, естественно, графических возможностей Паскаля), то в этой
библиотеке Вы найдете все, что нужно для создания Вашей программы. Разветвленное иерархическое
дерево Turbo Vision позволяет найти "плод" на любой вкус. Поэтому нельзя не присоединиться к
призыву разработчиков Turbo Vision – не изобретайте колесо, наследуйте наше!
На самом высоком уровне Turbo Vision – это объединение видимых элементов, событий и
невидимых объектов.
Видимый элемент – это любой элемент программы, который виден на экране. Все видимые
элементы являются объектами. Подробнее эти объекты мы рассмотрим ниже. Отметим только, что все
видимые объекты имеют прямоугольную форму, так как Turbo Vision работает в текстовом режиме.
События – это все то, на что должна отреагировать Ваша программа. События могут приходить от
мышки, от клавиатуры или от других частей Turbo Vision. Они поступают в очередь внутри Turbo
Vision по мере их поступления и затем обрабатываются обработчиком событий. Объект
TАpplication, который является ядром любой программы, содержит обработчик событий. Если
событие не может быть обработано TАpplication, то оно передается в другие видимые элементы до
тех пор, пока не найдется объект, который обработает событие или пока не возникнет ошибка "отказ от
события".
Невидимые объекты – это любые другие объекты программы, отличные от видимых элементов. Они
"невидимы", поскольку сами ничего на экран не выводят. Они производят вычисления, осуществляют
�Оглавлен ие
связь с периферией и выполняют другую работу программы. Если невидимому объекту нужно что-то
вывести на экран, он должен связаться с видимым элементом.
Что собой представляют видимые объекты, Вы можете увидеть на экране монитора после загрузки
Турбо Паскаля 6.0, поскольку его IDE (интегрированная среда разработки программ) создана на
основе Turbo Vision.
Вы видите, прежде всего, DeskTop (панель экрана или рабочий стол) – большой прямоугольник
заштрихованный светлым фоном. Сверху располагается полоса меню, доступ к которой осуществляется
нажатием клавиши F10, клавиши Alt с любой литерной клавишей, выделенной красным цветом
(«горячие» клавиши), или с помощью мыши. Активизация любой команды меню приводит к
появлению дополнительных выпадающих меню. Здесь Вы можете перемещаться с помощью
курсорных клавиш или литерных «горячих» клавиш (без Alt).
Внизу расположена строка статуса, которая содержит наиболее часто употребляемые команды и
может использоваться для вывода различного рода сообщений и подсказок о текущем состоянии
системы (ее статусе).
При выборе команды New в меню File панель экрана перекрывается окном. Окно имеет рамку с
именем и управляющие кнопки вверху. Левая закрывает окно (при ее нажатии мышкой), правая –
изменяет размеры, раскрывая окно на полный экран или сворачивая до прежних размеров. Нажав
клавишу мыши на верхней стороне рамки, Вы можете мышью перемещать окно по экрану. Потянув
мышкой за правый нижний угол окна, можно изменять его размеры.
При отсутствии мышки те же действия можно выполнить и с клавиатуры. Для этого можно войти в
меню Window (Окно) или сразу воспользоваться "горячей" клавишей Ctr+F5, после чего курсорными
клавишами можно перемещать окно или изменять его размеры (при нажатой клавише Shift).
Обратите внимание на то, как при этом изменяется статусная строка. Клавиша F5 распахивает окно на
полный экран или восстанавливает его прежние размеры (разумеется, если они были меньше полных).
Закрыть окно можно командой Close из меню Window или комбинацией клавиш Alt+F3.
С помощью команды New из меню File Вы можете раскрыть какое угодно число новых окон.
Расположить на экране их можно либо каскадом (Cascade из меню Windows) либо мозаикой (Tile).
Переход от окна к окну осуществляется командой Next, клавишей F6 или нажатием клавиши Alt и
цифры, соответствующей номеру окна (последнее возможно лишь для первых 9 окон, остальные не
нумерованы). Естественно, что нужное окно можно выбрать и мышкой (IDE – «мышиная» система, все
действия с помощью мыши осуществляются проще и быстрее).
Окно имеет полосу прокрутки (скроллинга), позволяющую просматривать большие тексты. Скроллинг
– сам по себе видимый элемент. Вместе с вертикальной и горизонтальной полосами прокрутки
скроллинг составляет с окном единое целое, объединяясь в группу видимых элементов.
Войдя, например, в меню Options и выбрав в нем команду Linker, Вы получите еще один пример
видимого элемента – диалоговое окно. Оно окрашено в другой цвет и содержит некоторый текст,
управляющие кнопки и другие элементы. Существуют различные типы диалоговых окон, с которыми
мы познакомимся позже.
Управляющие кнопки могут быть нажаты мышкой. Одна из кнопок выделена цветом надписи (в
нашем случае – кнопка Ok) и является кнопкой по умолчанию – она нажимается клавишей Enter.
Сменить кнопку по умолчанию можно клавишей Tab.
После знакомства с основными элементами Turbo Vision можно перейти к написанию Вашей
�Оглавлен ие
первой программы, воспользовавшись рекомендациями разработчиков Turbo Vision.
Как уже отмечалось, основным объектом при составлении программ в Turbo Vision является
TАpplication (он описан в модуле АPP.TPU). Это абстрактный объект, который сам ничего не
делает. Если выполнить программу:
program MyFirst;
uses App;
var
MyApp: TApplication;
BEGIN
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
то можно увидеть этот объект в «чистом виде» – он создает панель экрана и активизирует клавишу
выхода Alt+X. Кроме того, из приведенного примера видно, что в Turbo Vision принято
соглашение называть процедуру инициализации объекта Init, процедуру вывода на экран – Run и
процедуру закрытия объекта – Done. Эти три процедуры и составляют исполняемую часть
практически любой программы в Turbo Vision. На самом деле метод Run сложнее – он включает в
себя не только вывод объектов на экран, но и обработку событий.
Поскольку объект TApplication слишком прост, Вам придется модифицировать его, то есть
создавать объекты-потомки, расширяя его поля и перекрывая его методы. Посмотрим, прежде всего,
как изменить статусную строку (напомним, что TApplication в этой строке имеет единственную
клавишу AltX). Наша первая в Turbo Vision программа будет иметь вид:
program MyFirst1;
uses App,Objects,Menus,Drivers,Views; {нам понадобятся константы и
const
cmNewWin=199;
переменные, определенные в этих модулях}
{эта константа определяет реакцию на новую команду}
type
TMyApp=Object(TApplication)
{создаем объект-потомок TApplication
procedure InitStatusLine; virtual; и перекрываем его метод InitStatusLine}
end;
var
MyApp: TMyApp;
procedure TMyApp.InitStatusLine;
{описываем новый метод}
var R:TRect;
{эта переменная хранит границы статусной строки}
begin
�Оглавлен ие
GetExtent(R);
{устанавливает R в границы всего экрана}
R.A.Y:=R.B.Y-1;
{передвигаем вершину выше нижней границы на одну строку}
StatusLine:=New(PStatusLine,Init(R, {создаем строку статуса}
NewStatusDef(0,$FFFF,
{устанавливаем диапазон контекстной помощи}
NewStatusKey('~Alt-X~ Exit',kbAltX,cmQuit,
NewStatusKey('~F4~ New',kbF4,cmNewWin,
{определяем элемент строки}
{еще один}
NewStatusKey('~Alt-F3~ Close',kbAltF3,cmClose, {и еще один}
nil))),
{больше нет определений}
end;
BEGIN
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
Запустив программу на выполнение, вы увидите результат: в статусной строке появились две новые
команды – New и Close с соответствующими им «горячими» клавишами. Правда, обе пока не
отзываются на их нажатие. Причина этого проста – первую команду мы придумали сами и еще не
указали обработчику событий, как на нее реагировать. Вторая же команда, хотя и является внутренней
командой Turbo Vision, но пока не активизирована – на это указывает бледный цвет надписи – так как по
определению команда закрывает окно, а окон у нас еще нет!
Теперь заполним полосу меню. Она описывается переменной MenuBar, которая инициализируется
вложенными вызовами стандартных функций NewMenu (новое меню), NewSubMenu (новое подменю),
NewItem (новая команда), NewLine (новая разделительная линия).
Создадим сначала простую полосу меню с одним элементом, содержащим одну команду. Для этого в
нашу программу потребуется внести следующие изменения:
const
cmFileOpen=200;
{определяем новую команду}
procedure TMyApp.InitMenuBar;
{добавляем новый метод (не забудьте внести
var R:TRect;
изменения в описание TMyApp)}
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
{передвигаем вершину ниже верхней
MenuBar:=New(PMenuBar,Init(R,NewMenu(
{создаем полосу меню}
границы на одну строку}
NewSubMenu('~F~ile',hcNoContext,NewMenu(
{определяем подменю}
NewItem('~O~pen','F3',kbF3,cmFileOpen,
определяем элемент подменю}
�Оглавлен ие
hcNoContext,
nil)),
{больше нет элементов}
nil))))
{больше нет подменю}
end;
Чтобы окончательно разобраться, что к чему в этом фрагменте, достаточно запустить MyFirst1 с
внесенными изменениями и посмотреть на результат.
Чтобы добавить второй элемент в меню File, нужно вложить еще одну функцию NewItem:
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
nil))),
nil))))
end;
Для добавления второго меню вкладываем другую функцию NewSubMenu:
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
nil))),
nil)))));
Добавим еще разделительную линию в меню File, после чего наша процедура примет окончательный
вид:
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
�Оглавлен ие
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
nil))),
nil)))))
end;
Добавим еще в статусную строку команду «F10 Menu» для активизации меню с помощью «горячей
клавиши», и наша программа примет такой вид:
program TFirst2;
uses App,Objects,Menus,Drivers,Views;
const
cmNewWin=199;
cmFileOpen=200;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
end;
var
MyApp: TMyApp;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
�Оглавлен ие
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~ Exit',kbAltX,cmQuit,
NewStatusKey('~F4~ New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~ Close',kbAltF3,cmClose,
NewStatusKey('~F10~ Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
nil))),
nil)))))
end;
BEGIN
MyApp.Init;
�Оглавлен ие
MyApp.Run;
MyApp.Done;
END.
�Оглавлен ие
Задания для самостоятельной работы
1. Выполните программу TFirst2 в пошаговом режиме. Обратите внимание на то, как происходит
инициализация объекта MyApp.
2. Замените в Вашей программе названия команд меню и статусной строки их русскими
эквивалентами. Проверьте, сохранились ли возможности «горячих клавиш».
3. Добавьте новые пункты меню (и подменю) и новые элементы статусной строки по Вашему выбору.
�Оглавлен ие
Лабораторная работа № 24
ОКНА
Как уже отмечалось, окна в Turbo Vision – это видимые объекты, «знающие» правила своего
поведения. Они умеют открываться, изменять размер, перемещаться и закрываться, реагируя на
команды с клавиатуры или от мышки. Для того, чтобы что-то появилось в окне, мы должны вставить в
окно другие видимые элементы, которыми и сможет управлять наше окно. Поэтому начать нужно с
создания стандартного окна, а затем уже добавлять новые возможности. В нашей программе TFirst2
уже зарезервирована клавиша F4 с соответствующей командой NewWin, которая должна открывать
окно. Необходимо лишь написать соответствующие процедуры: для инициализации окна и для
подключения обработки события, возникающего при нажатии клавиши F4.
Поскольку мы включаем в нашу программу новый объект, то необходимо внести добавления в раздел
описания типов:
Type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
end;
Кроме того, нам понадобится новая константа WinCount:
инициализируется счетчик окон.
Integer=0, с помощью которой
Для того, чтобы окно Turbo Vision – его объект TWindow – смогло себя инициализировать, ему
необходимо передать три параметра: его размер и положение на экране, заголовок и номер окна.
Первый параметр – переменная типа TRect – описывает прямоугольный объект в Turbo Vision. Его
метод Assign задает положение верхнего левого угла окна (относительно верхнего левого угла
DeskTop) и положение нижнего правого угла окна. Второй параметр – строка (то есть величина типа
string) – будет выведен на экран в качестве заголовка окна. Наконец, последний параметр –
величина типа integer – задает номер окна. Если он имеет значения от 1 до 9, он выводится в рамке
окна и выбор пронумерованного окна можно осуществлять, нажимая клавиши от Alt+1 до Alt+9.
Если Вы не хотите назначать окну номер, передайте процедуре инициализации в качестве третьего
параметра константу wnNoNumber.
С учетом сказанного процедура создания окна может выглядеть следующим образом:
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
{задаем номер следующего окна}
R.Assign(0,0,30,7);
{задаем положение и размер окна}
R.Move(Random(58),Random(16));
{определяем случайное смещение, чтобы окна не перекрывали
друг друга}
�Оглавлен ие
Window:=New(PDemoWindow,
{инициализируем окно}
Init(R,'Demo Window ', WinCount));
DeskTop^.Insert(Window);
{выводим окно на панель экрана}
end;
Теперь нужно сделать так, чтобы записанная выше процедура начинала свою работу при нажатии
соответствующей клавиши (или при выборе пункта меню). Для этого нужно задействовать обработчик
событий Turbo Vision. Как уже упоминалось, объект TApplication владеет методом
HandleEvent и нам нужно расширить его, включив новую команду (не забудьте добавить новую
процедуру в описание TMyApp):
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
{наследуем старый метод}
if Event.What=evCommand then
begin
case Event.Command of
{но добавляем в него новые команды}
cmNewWin: NewWindow;
else
Exit;
end;
ClearEvent(Event);
{очищает событие после обработки}
end;
end;
Внеся перечисленные дополнения в Вашу программу, Вы получаете возможность открыть любое
число окон. Обратите внимание на то, что после открытия окон немедленно активизируются команды
Close в статусной строке и Next и Zoom в меню Window. Как уже указывалось, окно, кроме того,
умеет перемещаться по экрану и менять свой размер. Если Вы пользуетесь мышкой, то изменить размер
окна или передвинуть его можно с ее помощью, ничего не добавляя в код программы. Если же мышки
нет, то соответствующие возможности появятся лишь после включения стандартной команды
Size/Move, которая обычно связывается с клавишей CtrlF+5. Эту команду можно внести в меню
Window:
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
(напомним, что после выбора команды Size/Move перемещение окна осуществляется курсорными
клавишами, а изменение его размера – курсорными клавишами с нажатой клавишей Shift). После
всех необходимых изменений Ваша программа примет вид:
program TFist3;
�Оглавлен ие
uses App,Objects,Menus,Drivers,Views;
const
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
end;
var
MyApp: TMyApp;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~ Exit',kbAltX,cmQuit,
NewStatusKey('~F4~ New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~ Close',kbAltF3,cmClose,
NewStatusKey('~F10~ Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
�Оглавлен ие
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
nil)))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
DeskTop^.Insert(Window);
end;
�Оглавлен ие
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
else
Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
Окна, которые создаются в Вашей программе, обладают свойствами, установленными по умолчанию
для объектов типа TWindow. Для того, чтобы их изменить, необходимо обратиться к полям, которыми
располагает этот объект (описание всех объектов можно найти в справке помощи Турбо Паскаля –
меню Help). Одно из полей TWindows – Options – это переменная типа Word, которая содержит
флаги, управляющие поведением окон (или других видимых элементов). По умолчанию при создании
окна Options установлено в (ofSelectabl + ofTopSelect). Это означает, что окно может быть
выбрано мышкой (или командой Next), и выбранное окно передвигается наверх других окон. Изменим
поле Options, добавив флаг ofTileable, который позволяет окнам заполнять DeskTop каскадом
или мозаикой. Сделать это нужно после того, как окно создано, то есть в процедуру
TMyApp.NewWindow после строки, вызывающей процедуру инициализации окна, нужно добавить
строку
Window^.Options:=Window^.Options+ofTileable;
Кроме того, добавим соответствующие команды в меню Window
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
�Оглавлен ие
Наконец, мы должны определить реакцию на выбор этих команд, то есть добавить в процедуру
TMyApp.HandleEvent описание действий, которые нужно выполнить:
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end;
Если Вы все сделали правильно, то открытые Вами окна теперь можно будет располагать каскадом или
мозаикой.
Еще одно поле, которым располагает TWindow – поле Palette типа integer. Это поле задает цвет
wpCyanWindow
и
элементов окна. Стандартными являются значения wpBlueWindow,
wpGrayWindow. Легко, например, сделать серыми второе и четвертое из открываемых окон. Для этого
в процедуру TMyApp.NewWindow достаточно добавить строку:
if ((WinCount=2) or (WinCount=4)) then
Window^.Palette:=wpGrayWindow;
Для того, чтобы изменить стандартную “раскраску” окон, необходимо воспользоваться виртуальной
функцией GetPalette: PPalette. Это выглядит так:
function TDemoWindow.GetPalette: PPalette;
const
CDemoWindow=#15#9#5;
PDemoWindow: string[Length(CDemoWindow)]=CDemoWindow;
begin
GetPalette:=@PDemoWindow;
end;
Константа CDemoWindow и содержит описание новой палитры окна. Ее первый бит (#15) определяет
цвет рамки пассивного окна, второй (#9) – цвет рамки активного окна, третий (#5) – цвет кнопок
управления окном. Всего в CDemoWindow содержится восемь бит, определяющих полную окраску
окна. Вы можете удивиться, почему, указав цвет 15, Вы получили не белое окно, а красное (15 номер
соответствует белому цвету в стандартном Паскале). Дело в том, что передача цветов в Turbo
Vision происходит достаточно сложным образом. Во-первых, для отображения некоторого видимого
объекта нужно задать два цвета – цвет фона и цвет изображения. Во-вторых, каждый видимый объект
имеет своего “хозяина”, который этим объектом владеет, соответственно должны быть согласованы
�Оглавлен ие
цвета различных объектов. Поэтому в CDemoWindow на самом деле Вы указываете не сам цвет окна, а
то место, которое нужный Вам цвет (точнее пара – цвет фона + цвет изображения) занимает в палитре
цветов объекта-хозяина. Хозяином всех наших окон является DeskTop, который, однако, собственной
палитры не имеет. Поэтому, поднимаясь по дереву иерархии, мы находим другого хозяина –
TProgram, в палитре которого и находятся выбранные нами цвета. Не вдаваясь в подробности
описания сложной палитры TProgram, Вы можете попробовать «экспериментально» подобрать те
цвета, которые покажутся Вам наиболее удачными.
После всех внесенных изменений Ваша программа должна принять окончательный вид:
program TFirst3;
uses App,Objects,Menus,Drivers,Views;
const
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
function GetPalette: PPalette;virtual;
end;
var
MyApp: TMyApp;
function TDemoWindow.GetPalette: PPalette;
const
CDemoWindow=#15#13#4;
PDemoWindow: string[Length(CDemoWindow)]=CDemoWindow;
begin
GetPalette:=@PDemoWindow;
end;
�Оглавлен ие
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
�Оглавлен ие
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
nil)))))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
�Оглавлен ие
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
end;
end;
BEGIN
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
�Оглавлен ие
Задания для самостоятельной работы
Поупражняйтесь в изменении атрибутов создаваемых программой TFirst3 окон:
а) сделайте так, чтобы первые десять окон имели индивидуальные заголовки (например, Первое
окно, Второе окно и т. д.);
б) сделайте так, чтобы первые четыре окна при их выводе на экран располагались каскадом;
в) сделайте так, чтобы первые четыре окна при выводе их на экран располагались мозаикой.
Измените атрибуты третьего окна так, чтобы оно стало недоступным для пользователя, то есть после
создания не реагировало бы ни на какие команды от мышки или клавиатуры.
�Оглавлен ие
Лабораторная работа № 25
ИНТЕРЬЕР
В предыдущей работе мы научились создавать окна, правда, пока совершенно пустые. Попробуем
теперь заполнить окно, поместив в него для начала какую-нибудь простую фразу, например «Я Вам
пишу». В стандартном Паскале мы воспользовались бы для этой цели оператором Write. Однако в
Turbo Vision он явно не годится – этот оператор просто выведет данную фразу на экран, а нам
этого мало! Наши окна умеют делать множество вещей – перемещаться, изменять свои размеры,
закрываться, а написанная с помощью Write фраза ничего этого не знает. Вместе с тем,
приобретенный в предыдущих работах опыт подсказывает, что нам нужно – нам нужен видимый
объект, который составит с окном группу и, следовательно, будет себя вести в соответствии с
требованиями хозяина (т.е. окна) – перемещаться вместе с ним, исчезать при его закрытии и так далее.
Этот видимый объект и называют интерьером окна или просто интерьером. Как мы уже отмечали, все
видимые объекты являются потомками TView, поэтому его объявление в соответствии с общими
правилами Turbo Vision будет иметь вид:
PInterior=^TInterior;
TInterior=object(TView)
Для инициализации объекта TInterior нам достаточно указать размеры той области, которую он
будет занимать, то есть инициализировать единственное поле, определяемое переменной типа TRect.
Следовательно, в описание объекта войдет конструктор
constructor TInterior.Init(var Bounds: TRect);
Наконец, TInterior должен уметь себя рисовать. Все видимые объекты рисуют себя с помощью
родительского метода Draw, который нам необходимо расширить, поскольку создаем мы наш
собственный интерьер (в предыдущей работе мы создавали стандартные окна и расширение метода
Draw нам не потребовалось). Следовательно, в описание TInterior войдет виртуальная процедура
Draw и раздел описания типов нашей программы TFirst3 пополнится строками:
PInterior=^TInterior;
TInterior=object(TView)
constructor TInterior.Init(var Bounds: TRect);
procedure Draw; virtual;
end;
Входящие сюда конструктор и процедура описываются следующим кодом:
constructor TInterior.Init(var Bounds: TRect);
begin
TView.Init(Bounds);
{вызываем метод Init предка}
GRowMode:=gfGrowHiX+gfGrowHiY;
{и устанавливаем, что при изменении размеров окна его
интерьер будет сохранять постоянное расстояние от правой и нижней границ окна-владельца}
end;
procedure TInterior.Draw;
�Оглавлен ие
var
S: string;
begin
TView.Draw;
{вызываем метод предка}
S:='Я Вам пишу';
WriteStr(4,2,S,6);
{добавляем в интерьер необходимую запись; первые две цифры
— относительные координаты строки S, последняя — код цвета строки}
end;
Теперь нужно подсоединить интерьер к окну. На языке Turbo Vision это означает, что мы должны
снова инициализировать окно, теперь уже с добавлением к нему интерьера. Поэтому придется
написать конструктор Init для нашего объекта TDemoWindow. Он может выглядеть, например, так:
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string; WindowNo:
Integer);
Var
{не забудьте обновить описание типов}
S: string[3];
Interior: PInterior;
begin
Str(WindowNo, S);
{переводим численное значение
номера окна в строку}
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber); {и добавляем его к заголовку окна}
GetClipRect(Bounds);
{запрашиваем размеры доступного
Bounds.Grow(-1,-1);
{устанавливаем размеры интерьера на
Interior:=New(PInterior, Init(Bounds));
{инициализируем интерьер}
Insert(Interior);
{и вставляем его в окно}
пространства окна}
единицу меньше размеров окна}
end;
Если Вы правильно внесли изменения в программу TFirst3, то можете увидеть на экране результат
своих трудов и поупражняться в изменении атрибутов созданного интерьера.
Кроме процедуры WriteStr для записи в окно может использоваться и процедура
WriteChar(X,Y,Ch,Color,Count),
которая позиционирует свой вывод в координаты (X,Y) относительно видимого элемента и пишет
Count копий символа Ch, цветом Color из палитры видимого элемента. Эту процедуру удобно
использовать при создании, например, рамок.
После внесенных изменений Ваша программа должна принять вид:
program TFirst4;
uses App,Objects,Menus,Drivers,Views;
�Оглавлен ие
const
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
end;
type
PInterior=^Tinterior;
TInterior=object(TView)
constructor Init(var Bounds: TRect);
procedure Draw; virtual;
end;
var
MyApp: TMyApp;
S: string;
constructor TInterior.Init(var Bounds: TRect);
begin
TView.Init(Bounds);
GRowMode:=gfGrowHiX+gfGrowHiY;
end;
procedure TInterior.Draw;
var
S: string;
�Оглавлен ие
begin
TView.Draw;
S:='Запись в окно';
WriteStr(4,2,S,6);
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
Interior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetClipRect(Bounds);
Bounds.Grow(-1,-1);
Interior:=New(PInterior, Init(Bounds));
Insert(Interior);
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
�Оглавлен ие
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
nil)))))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
�Оглавлен ие
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var
R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
Выбранный нами способ записи в окно выглядит слишком примитивно и вряд ли может быть полезен
на практике. Очевидно, что гораздо эффективнее записывать нужную для вывода информацию в файл,
�Оглавлен ие
а уж затем помещать ее в окно. Поэтому напишем процедуру чтения информации из файла. Она может
выглядеть так:
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
Эта процедура считывает информацию из файла F и помещает ее в строковый массив Lines:
- 1] of PString. Переменная LineCount типа integer является
счетчиком строк, а постоянная MaxLines задает максимальное значение числа строк в массиве.
Понятно, что эти величины должны быть добавлены в раздел описания данных Вашей программы (как
станет ясным из дальнейшего, это глобальные величины). Кроме того, в раздел описания констант
нужно добавить и путь к файлу, из которого будет читаться информация, то есть задать значение
строковой постоянной FileToRead. В качестве этого файла можно просто использовать файл, в
котором хранится код Вашей программы. Например, если Ваша программа записана на диске С: в
каталоге tp6 под именем MyFirst3.pas, то объявление константы будет иметь вид:
FileToRead='с:\tp6\ MyFirst3.pas'. Однако, для того, чтобы не возникало ощущения, что Вы
наблюдаете через окно редактор Турбо Паскаля, лучше написать с его помощью любой текст и
сохранить его под любым именем с расширением txt. Не забудьте добавить вызов ReadFile в код
основной программы (перед MyApp.Init).
array[0..MaxLines
Поскольку Вы занимаете под хранение информации, считанной из файла, определенную память, то
после использования этой информации память необходимо освободить. Для этого напишем
процедуру DoneFile (в этом тоже проявляется один из принципов Turbo Vision – все, что было
открыто, нужно закрыть!):
procedure DoneFile;
var
I: Integer;
begin
�Оглавлен ие
for I:= 0 to LineCount - 1 do
if Lines[I] <> nil then DisposeStr(Lines[i]);
end;
Осталось изменить код процедуры Draw:
procedure TInterior.Draw;
var
Y: Integer;
begin
for Y:= 0 to Size.Y - 1 do
begin
WriteStr(0, Y, Lines[Y]^, $06);
end;
end;
Запустив после внесенных изменений программу, Вы увидите, что на тех местах, где должны быть
пустые строки, появляются лишние символы. Это произошло потому, что мы нарушили принцип,
согласно которому метод Draw должен покрывать всю площадь, за которую отвечает использующий
его видимый элемент. Поэтому еще раз изменим процедуру Draw, помещая считываемые из файла
Turbo
Vision
строки не
в
массив,
а в
буфер
(буфер
в
–
это
тип
TDrawBuffer=array[0..MaxViewWidth] и постоянная MaxViewWidth равна 132 символам).
Новый Draw будет иметь вид:
procedure TInterior.Draw;
var
Color: Byte;
Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(6);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
{заполняет буфер пробелами}
if (Y < LineCount) and (Lines[Y] <> nil) then
MoveStr(B, Copy(Lines[Y]^, 1, Size.X), Color);
{и копирует строку в буфер}
WriteLine(0, Y, Size.X, 1, B);
{выводит содержимое буфера}
end;
end;
Запустив программу, Вы увидите, что теперь все работает нормально – пустые места заполнены
пробелами, как и должно быть. Для пересылки текста в буфер были использованы две глобальные
�Оглавлен ие
процедуры: MoveChar – для пересылки символов и MoveStr – для пересылки строк. Кроме них могут
использоваться MoveСStr – для пересылки управляющих символов и управляющих строк (с «~» для
элементов меню и статуса) и MoveBuf – для пересылки буфера в буфер.
Для вывода содержимого буфера имеются две процедуры. WriteLine(X, Y, W, H, Buf) выводит
содержимое буфера Buf в строку длиной в W символов, начиная с позиции X, Y. Если параметр H
больше единицы, буфер повторяется H раз. WriteBuf(X, Y, W, H, Buf) также выводит
содержимое буфера, но W и H задают ширину и высоту вывода. Так, если в буфере – «Я Вам пишу», то
процедура WriteBuf(0, 0, 3, 3, Buf) выведет
Я В
ам
пиш
Со всеми внесенными изменениями Ваша программа должна принять вид:
program TFirst4;
uses App,Objects,Menus,Drivers,Views;
const
FileToRead='e:\tp6\tutor\urok.txt';
{здесь должен быть к путь Вашему файлу}
MaxLines = 100;
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
end;
type
PInterior=^Tinterior;
�Оглавлен ие
TInterior=object(TView)
constructor Init(var Bounds: TRect);
procedure Draw; virtual;
end;
var
MyApp: TMyApp;
S: string;
LineCount: Integer;
Lines: array[0..MaxLines - 1] of PString;
constructor TInterior.Init(var Bounds: TRect);
begin
TView.Init(Bounds);
GRowMode:=gfGrowHiX+gfGrowHiY;
end;
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
procedure DoneFile;
var
I: Integer;
begin
for I:= 0 to LineCount - 1 do
�Оглавлен ие
if Lines[I] <> nil then DisposeStr(Lines[i]);
end;
procedure TInterior.Draw;
var
Color: Byte;
Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(6);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
if (Y < LineCount) and (Lines[Y] <> nil) then
MoveStr(B, Copy(Lines[Y]^, 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
Interior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetClipRect(Bounds);
Bounds.Grow(-1,-1);
Interior:=New(PInterior, Init(Bounds));
Insert(Interior);
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
�Оглавлен ие
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
�Оглавлен ие
hcNoContext,
nil)))))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var
R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
�Оглавлен ие
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
ReadFile;
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
�Оглавлен ие
Задания для самостоятельной работы
1. Меняя состояния окон, наблюдайте за изменениями их интерьера.
2. Поэкспериментируйте с процедурами пересылки текста в буфер и вывода из него, меняя их
параметры.
3. Поэкспериментируйте с цветами окон и выводимого текста, добиваясь наилучшего соотношения
цветов.
�Оглавлен ие
Лабораторная работа № 26
СКРОЛЛИНГ
Созданный нами в предыдущей работе интерьер обладает тем недостатком, что позволяет просмотреть
лишь несколько первых строк открываемого файла. Поэтому удобнее использовать в качестве
интерьера другой видимый объект – TScroller. Этот объект позволяет добавить к нему полосы
скроллинга, так что TInterior становится окном, скользящим по текстовому файлу. Для этого нам
придется изменить объявление TInterior:
type
PInterior=^TInterior;
TInterior=object(TScroller)
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
procedure Draw; virtual;
end;
Вы видите, что теперь TInterior объявляется как объект TScroller, при инициализации которого
задаются занимаемая им область (переменная Bounds типа TRect) и полосы вертикальной и
горизонтальной прокрутки (AHScrollBar, AVScrollBar).
Кроме того, удобно изменить и объект TDemoWindow, добавив в него метод MakeInterior, с тем,
чтобы отделить эту процедуру от механизма открытия окна:
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
procedure MakeInterior(Bounds: TRect);
end;
Понятно, что должно измениться и правило инициализации объекта TInterior:
constructor TInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
GrowMode:= gfGrowHiX + gfGrowHiY;
Options:= Options or ofFramed;
SetLimit(128, LineCount);
{горизонтальная и вертикальная границы скроллинга}
�Оглавлен ие
end;
Соответственно, метод Draw для объекта TInterior и конструктор Init для TDemoWindow будут
выглядеть так:
procedure TInterior.Draw;
var
Color: Byte;
I,Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(1);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
i:= Delta.Y + Y;
if (I < LineCount) and (Lines[I] <> nil) then
MoveStr(B, Copy(Lines[I]^, Delta.X + 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
Interior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetExtent(Bounds);
Bounds.Grow(-1,-1);
MakeInterior(Bounds);
end;
Теперь осталось лишь написать процедуру MakeInterior:
procedure TDemoWindow.MakeInterior(Bounds: TRect);
var
�Оглавлен ие
HScrollBar, VScrollBar: PScrollBar;
Interior: PInterior;
R: TRect;
begin
VScrollBar:= StandardScrollBar(sbVertical + sbHandleKeyboard);
HScrollBar:= StandardScrollBar(sbHorizontal + sbHandleKeyboard);
GetExtent(Bounds);
Bounds.Grow(-1,-1);
Interior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
Insert(Interior);
end;
Из записанных выше процедур видно, что вертикальная и горизонтальная полосы скроллинга
инициализируются и вставляются в группу, а затем передаются в TScroller при его инициализации.
Скроллер – это видимый элемент, спроектированный для отображения части большого видимого
элемента. Скроллер и его полосы прокрутки (скроллинга) объединяются для создания скользящего
видимого элемента с незначительными усилиями. Все, что нам нужно сделать – это создать метод
Draw, чтобы он отображал соответствующую часть виртуального видимого элемента. Полосы
скроллинга автоматически управляют значениями Delta.X (колонка, с которой начинается вывод) и
Delta.Y (строка, с которой начинается вывод) скроллера.
Мы должны перекрыть метод Draw в TScroller. Значения Delta изменяются в соответствии с
полосами скроллинга. Метод Draw вызывается каждый раз, когда изменяется Delta.
Если Вы правильно внесли все изменения в Вашу программу TFirst4, то она должна принять вид:
program TFirst5;
uses App,Objects,Menus,Drivers,Views;
const
FileToRead='e:\tp6\tutor\urok.txt';
MaxLines = 100;
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
�Оглавлен ие
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
procedure MakeInterior(Bounds: TRect);
end;
type
PInterior=^Tinterior;
TInterior=object(TScroller)
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
procedure Draw; virtual;
end;
var
MyApp: TMyApp;
S: string;
LineCount: Integer;
Lines: array[0..MaxLines - 1] of PString;
constructor TInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
GrowMode:= gfGrowHiX + gfGrowHiY;
Options:= Options or ofFramed;
SetLimit(128, LineCount);
end;
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
�Оглавлен ие
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
procedure DoneFile;
var
I: Integer;
begin
for I:= 0 to LineCount - 1 do
if Lines[I] <> nil then DisposeStr(Lines[i]);
end;
procedure TInterior.Draw;
var
Color: Byte;
I,Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(1);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
i:= Delta.Y + Y;
if (I < LineCount) and (Lines[I] <> nil) then
MoveStr(B, Copy(Lines[I]^, Delta.X + 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
�Оглавлен ие
WindowNo: Integer);
var
S: string[3];
Interior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
MakeInterior(Bounds);
end;
procedure TDemoWindow.MakeInterior(Bounds: TRect);
var
HScrollBar, VScrollBar: PScrollBar;
Interior: PInterior;
R: TRect;
begin
VScrollBar:= StandardScrollBar(sbVertical + sbHandleKeyboard);
HScrollBar:= StandardScrollBar(sbHorizontal + sbHandleKeyboard);
GetExtent(Bounds);
Bounds.Grow(-1,-1);
Interior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
Insert(Interior);
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
�Оглавлен ие
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
nil)))))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
�Оглавлен ие
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var
R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
�Оглавлен ие
ReadFile;
MyApp.Init;
MyApp.Run;
MyApp.Done;
END.
Попытаемся теперь продублировать интерьер и создадим окно с двумя видимыми элементами для
текстового файла. Мышка или клавиша Tab автоматически выбирает один из двух интерьеров.
Каждый видимый элемент скользит независимо от другого и имеет собственную позицию курсора.
Для того, чтобы сделать это, расширьте метод MakeInterior так, чтобы он знал, какая часть окна
является активным интерьером и сделайте два вызова MakeInterior в TDemoWindow.Init. Это
можно осуществить следующим образом:
function TDemoWindow.MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
{не забудьте изменить объявление MakeInterior}
var
HScrollBar, VScrollBar: PScrollBar;
R: TRect;
begin
R.Assign(Bounds.B.X-1, Bounds.A.Y+1, Bounds.B.X, Bounds.B.Y-1);
VScrollBar:= New(PScrollBar, Init(R));
VScrollBar^.Options:= VScrollBar^.Options or ofPostProcess;
if Left then VScrollBar^.GrowMode:= gfGrowHiY;
Insert(VScrollBar);
R.Assign(Bounds.A.X+2, Bounds.B.Y-1, Bounds.B.X-2, Bounds.B.Y);
HScrollBar:= New(PScrollBar, Init(R));
HScrollBar^.Options:= HScrollBar^.Options or ofPostProcess;
if Left then HScrollBar^.GrowMode:= gfGrowHiY + gfGrowLoY;
Insert(HScrollBar);
Bounds.Grow(-1,-1);
MakeInterior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
R: TRect;
�Оглавлен ие
RInterior, LInserior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetExtent(Bounds);
R.Assign(Bounds.A.X, Bounds.A.Y, Bounds.B.X div 2 + 1,
Bounds.B.Y);
LInterior:= MakeInterior(R, True);
LInterior^.GrowMode:= gfGrowHiY;
Insert(Linterior);
R.Assign(Bounds.B.X div 2, Bounds.A.Y, Bounds.B.X, Bounds.B.Y);
RInterior:= MakeInterior(R,False);
RInterior^.GrowMode:= gfGrowHiX + gfGrowHiY;
Insert(RInterior);
end;
Если Вы правильно внесли изменения в Вашу программу, то, открыв окно, Вы увидите в нем два
интерьера, которые можно выбрать (сделать активными) с помощью мышки или клавиши Tab.
Однако, если Вы уменьшите размер окна, то заметите, что вертикальная полоса скроллинга будет
перекрыта левым интерьером, если правая сторона окна придвинута слишком близко к левой. Это
можно предотвратить, перекрывая метод SizeLimits в TWindow (это виртуальный метод):
procedure TDemoWindow.SizeLimits(var Min,Max:TPoint);
var R: TRect;
begin
TWindow.SizeLimits(Min,Max);
GetExtent(R);
Min.X:=R.B.X div 2;
end;
Заметим, что Вы не вызываете SizeLimits, Вы просто перекрываете его, и он будет вызываться в
соответствующее время. Это похоже на то, что Вы делали с методом Draw: Вы говорите видимому
элементу, как его рисовать, но не когда. Turbo Vision уже знает, когда вызывать Draw. Это же
применимо и к SizeLimits – Вы устанавливаете границы, а видимый элемент знает тот момент,
когда необходимо проверить их. После всех изменений Ваша программа должна принять следующий
окончательный вид:
program TFirst5;
uses App,Objects,Menus,Drivers,Views;
const
FileToRead='e:\tp6\tutor\urok.txt';
�Оглавлен ие
MaxLines
= 100;
cmNewWin=199;
cmFileOpen=200;
winCount: Integer=0;
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PInterior=^Tinterior;
TInterior=object(TScroller)
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
procedure Draw; virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
function MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
procedure SizeLimits(var Min,Max:TPoint);virtual;
end;
var
MyApp: TMyApp;
S: string;
LineCount: Integer;
Lines: array[0..MaxLines - 1] of PString;
procedure TDemoWindow.SizeLimits(var Min,Max:TPoint);
var R: TRect;
begin
�Оглавлен ие
TWindow.SizeLimits(Min,Max);
GetExtent(R);
Min.X:=R.B.X div 2;
end;
constructor TInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
Options:= Options or ofFramed;
SetLimit(128, LineCount);
end;
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
procedure DoneFile;
var
I: Integer;
begin
for I:= 0 to LineCount - 1 do
if Lines[I] <> nil then DisposeStr(Lines[i]);
end;
�Оглавлен ие
procedure TInterior.Draw;
var
Color: Byte;
I,Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(1);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
i:= Delta.Y + Y;
if (I < LineCount) and (Lines[I] <> nil) then
MoveStr(B, Copy(Lines[I]^, Delta.X + 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
R: TRect;
RInterior, LInterior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetExtent(Bounds);
R.Assign(Bounds.A.X, Bounds.A.Y, Bounds.B.X div 2 + 1,
Bounds.B.Y);
LInterior:= MakeInterior(R, True);
LInterior^.GrowMode:= gfGrowHiY;
Insert(Linterior);
R.Assign(Bounds.B.X div 2, Bounds.A.Y, Bounds.B.X, Bounds.B.Y);
RInterior:= MakeInterior(R,False);
RInterior^.GrowMode:= gfGrowHiX + gfGrowHiY;
�Оглавлен ие
Insert(RInterior);
end;
function TDemoWindow.MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
var
HScrollBar, VScrollBar: PScrollBar;
R: TRect;
begin
R.Assign(Bounds.B.X-1, Bounds.A.Y+1, Bounds.B.X, Bounds.B.Y-1);
VScrollBar:= New(PScrollBar, Init(R));
VScrollBar^.Options:= VScrollBar^.Options or ofPostProcess;
if Left then VScrollBar^.GrowMode:= gfGrowHiY;
Insert(VScrollBar);
R.Assign(Bounds.A.X+2, Bounds.B.Y-1, Bounds.B.X-2, Bounds.B.Y);
HScrollBar:= New(PScrollBar, Init(R));
HScrollBar^.Options:= HScrollBar^.Options or ofPostProcess;
if Left then HScrollBar^.GrowMode:= gfGrowHiY + gfGrowLoY;
Insert(HScrollBar);
Bounds.Grow(-1,-1);
MakeInterior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
�Оглавлен ие
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
nil)))))),
nil)))))
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
�Оглавлен ие
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
ReadFile;
MyApp.Init;
MyApp.Run;
MyApp.Done;
�Оглавлен ие
DoneFile;
END.
�Оглавлен ие
Задание для самостоятельной работы
1. Как создать в одном окне два разных интерьера?
�Оглавлен ие
Лабораторная работа № 27
ДИАЛОГОВЫЕ ОКНА
Диалоговые окна представляют собой специальный тип окон. Их назначение – вывод различного рода
сообщений, ввод данных, установка параметров и т. д. Другими словами, диалоговые окна служат для
организации диалога с пользователем. В Turbo Vision диалоговое окно – это объект TDialog.
Заметим, что Вам не придется порождать новый тип объекта от TDialog, как Вы это делали с
TWindow. Вместо создания специального типа диалогового окна Вы добавляете «разумность» в
программу: вместо создания объекта типа «диалоговое окно», который знает «как себя вести», Вы
создаете общее диалоговое окно и говорите ему, что оно должно сделать.
Для того чтобы использовать окно диалога в Вашей программе, необходимо выполнить следующие
действия:
• подключить модуль Dialogs;
• определить константу cmNewDialog, соответствующую команде открытия диалогового окна;
• в меню Window добавить новый элемент меню, который генерирует команду открытия диалогового
окна (связав ее, например, с клавишей F2);
• добавить метод, который знает, как открыть диалоговое окно:
procedure TMyApp.NewDialog;
var
Dialog: PDemoDialog;
R: TRect;
begin
R.Assign(0, 0, 40, 13);
R.Move(Random(39), Random(10));
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
DeskTop^.Insert(Dialog);
end;
• добавить строку
cmNewDialog: NewDialog;
в метод HandleEvent, чтобы связать команду с действием.
Если Вы все сделали правильно, то сможете открыть несколько диалоговых окон и увидеть их отличие
от тех окон, которые использовались ранее:
• цвет диалогового окна по умолчанию серый вместо синего;
• диалоговое окно не может изменять размер;
• диалоговое окно не имеет номера.
�Оглавлен ие
Созданное Вами окно является примером диалогового «немодального» окна, то есть окна без режимов.
Однако в большинстве случаев Вам будут нужны модальные окна – окна, определяющие режим
действия. Если Вы откроете модальное окно, то активным будет только оно. Отметка других окон или
меню не вызывает никаких действий до тех пор, пока Вы не закроете активное модальное окно
(отметим, что клавиша ESC по умолчанию закрывает модальное диалоговое окно).
Для того, чтобы сделать диалоговое окно модальным, нужно изменить метод NewDialog:
procedure TMyApp.NewDialog;
var
Dialog: PDemoDialog;
R: TRect;
C: Word;
begin
R.Assign(0, 0, 40, 13);
R.Move(Random(39), Random(10));
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
C:= DeskTop^.ExecView(Dialog);
Dispose(Dialog, Done);
end;
Модальное окно уже знает, как реагировать на событие по клавише ESC (которое преобразуется в
команду cmCancel) и событие от клавиши Enter (которое обрабатывается кнопкой по умолчанию
TButton). В ответ на команду cmCancel диалоговое окно всегда закрывается.
Вызов ExecView вставляет диалоговое окно в группу и делает его модальным. Выполнение
программы продолжается в ExecView до тех пор, пока диалоговое окно не закроется или не будет
удалено. После этого ExecView удаляет окно из группы и осуществляет выход. Значение,
возвращаемое функцией ExecView, сохраняется в переменной С и может быть использовано в
дальнейшем.
Проверьте теперь правильность внесения изменений в Вашу программу:
Program TFirst6;
uses App,Objects,Menus,Drivers,Views,Dialogs;
const
FileToRead='e:\tp60\urok.txt';
MaxLines = 100;
cmNewWin=199;
cmFileOpen=200;
cmNewDialog = 201;
winCount: Integer = 0;
�Оглавлен ие
type
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure NewDialog;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PInterior=^Tinterior;
TInterior=object(TScroller)
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
procedure Draw; virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
function MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
procedure SizeLimits(var Min,Max:TPoint);virtual;
end;
type
PDemoDialog = ^TDemoDialog;
TDemoDialog = object(TDialog)
end;
var
MyApp: TMyApp;
S: string;
LineCount: Integer;
Lines: array[0..MaxLines - 1] of PString;
procedure TDemoWindow.SizeLimits(var Min,Max:TPoint);
var R: TRect;
�Оглавлен ие
begin
TWindow.SizeLimits(Min,Max);
GetExtent(R);
Min.X:=R.B.X div 2;
end;
constructor TInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
Options:= Options or ofFramed;
SetLimit(128, LineCount);
end;
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
procedure DoneFile;
var
I: Integer;
begin
for I:= 0 to LineCount - 1 do
if Lines[I] <> nil then DisposeStr(Lines[i]);
�Оглавлен ие
end;
procedure TInterior.Draw;
var
Color: Byte;
I,Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(1);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
i:= Delta.Y + Y;
if (I < LineCount) and (Lines[I] <> nil) then
MoveStr(B, Copy(Lines[I]^, Delta.X + 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
R: TRect;
RInterior, LInterior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetExtent(Bounds);
R.Assign(Bounds.A.X, Bounds.A.Y, Bounds.B.X div 2 + 1,
Bounds.B.Y);
LInterior:= MakeInterior(R, True);
LInterior^.GrowMode:= gfGrowHiY;
Insert(Linterior);
R.Assign(Bounds.B.X div 2, Bounds.A.Y, Bounds.B.X, Bounds.B.Y);
RInterior:= MakeInterior(R,False);
�Оглавлен ие
RInterior^.GrowMode:= gfGrowHiX + gfGrowHiY;
Insert(RInterior);
end;
function TDemoWindow.MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
var
HScrollBar, VScrollBar: PScrollBar;
R: TRect;
begin
R.Assign(Bounds.B.X-1, Bounds.A.Y+1, Bounds.B.X, Bounds.B.Y-1);
VScrollBar:= New(PScrollBar, Init(R));
VScrollBar^.Options:= VScrollBar^.Options or ofPostProcess;
if Left then VScrollBar^.GrowMode:= gfGrowHiY;
Insert(VScrollBar);
R.Assign(Bounds.A.X+2, Bounds.B.Y-1, Bounds.B.X-2, Bounds.B.Y);
HScrollBar:= New(PScrollBar, Init(R));
HScrollBar^.Options:= HScrollBar^.Options or ofPostProcess;
if Left then HScrollBar^.GrowMode:= gfGrowHiY + gfGrowLoY;
Insert(HScrollBar);
Bounds.Grow(-1,-1);
MakeInterior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
�Оглавлен ие
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
NewItem('~D~ialog', 'F2', kbF2, cmNewDialog, hcNoContext,
nil))))))),
nil)))))
end;
procedure TMyApp.NewDialog;
var
Dialog: PDemoDialog;
�Оглавлен ие
R: TRect;
C: Word;
begin
R.Assign(0, 0, 40, 13);
R.Move(Random(39), Random(10));
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
C:= DeskTop^.ExecView(Dialog);
Dispose(Dialog, Done);
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
cmNewWin: NewWindow;
cmNewDialog: NewDialog;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
�Оглавлен ие
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
ReadFile;
MyApp.Init;
MyApp.Run;
MyApp.Done;
DoneFile;
END.
�Оглавлен ие
Управление диалоговыми окнами
Созданное нами диалоговое окно обладает существенным недостатком – оно не несет никакой
информации. Чтобы диалоговое окно имело смысл, в него нужно добавить элементы управления.
Элементы управления – это изменяющиеся элементы внутри диалогового окна, которые позволяют
Вам манипулировать информацией. Важно помнить, что элементы управления действуют только
внутри диалогового окна. Существует только одно исключение из этого правила – в случае кнопки в
немодальном диалоговом окне. Поскольку кнопки генерируют команды, эти команды будут
распространяться от текущего модального видимого элемента. Если же диалоговое окно – это
немодальный видимый элемент, то его команды могут распространяться за пределы окна, что
приводит, как правило, к неожиданным эффектам.
Когда элементы управления установлены в диалоговом окне, появляется возможность отделить
видимое представление от обработки данных. Это означает, что Вы можете легко спроектировать все
диалоговое окно без создания кода, который устанавливает или использует данные из этого окна
(точно так же, как Вы устанавливали элементы меню и статуса без кода, реагирующего на
сгенерированные команды). Приступим теперь к рассмотрению основных элементов управления.
�Оглавлен ие
Статический текст
Добавим, прежде всего, в диалоговое окно некоторое сообщение. Для этого нам придется
использовать объект TStaticText, который является потомком от TView. Это видимый элемент,
который просто отображает строку, переданную в него. Строка представляет собой слово,
располагаемое внутри прямоугольника видимого элемента с переносом. Текст будет центрироваться,
если строка начинается с Ctr-C, она может быть разбита с помощью Ctr-М. По умолчанию текст не
может активизироваться и объект не получает данных от него. Для вставки текста изменим процедуру
TMyApp.NewDialog следующим образом:
procedure TMyApp.NewDialog;
var
Bruce: PView;
Dialog: PDemoDialog;
R: TRect;
C: Word;
s: string;
begin
R.Assign(20, 6, 60, 19);
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
s:='Это простое диалоговое окно';
with Dialog^ do
begin
R.Assign(6, 6, 35, 7);
Bruce:=New(PStaticText,Init(R,s));
Insert(Bruce);
end;
C:= DeskTop^.ExecView(Dialog);
Dispose(Dialog, Done);
end;
�Оглавлен ие
Кнопки
Кнопки – это объекты TButton. Они работают во многом аналогично элементам строки статуса: это
закрашенная область с текстовой меткой и, если Вы отметите ее, она генерирует команду. На экране
видна тень от кнопки, так что при ее "нажатии" создается эффект движения. Большинство диалоговых
окон имеет, по крайней мере, одну или две кнопки. Наиболее общие кнопки – ОК (обозначающая «Я
все сделал». Вы можете закрыть диалоговое окно и использовать результаты) и Cancel (означающая
«Я хочу закрыть диалоговое окно и игнорировать изменения, сделанные в нем»). Кнопка Cancel по
умолчанию генерирует ту же команду cmCancel, что и закрывающая кнопка.
Модуль Dialogs определяет пять стандартных диалоговых команд, которые могут быть связаны с
TButton: cmOK, cmCancel, cmYes, cmNo, cmDefault. Первые четыре команды также
закрывают диалоговое окно, вызывая метод EndModel из TDialog, который восстанавливает
предыдущий модальный видимый элемент в статус модальности. Естественно, что кнопки могут
использоваться и для генерации команд, специфичных для Вашей программы.
Из предыдущего примера должно быть ясно, как следует модифицировать метод TMyApp.NewDialog,
для того, чтобы добавить в диалоговое окно кнопки OK и Cancel:
procedure TMyApp.NewDialog;
var
Bruce: PView;
Dialog: PDemoDialog;
R: TRect;
C: Word;
s: string;
begin
R.Assign(20, 6, 60, 19);
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
s:='Это простое диалоговое окно';
with Dialog^ do
begin
R.Assign(6, 6, 35, 7);
Bruce:=New(PStaticText,Init(R,s));
Insert(Bruce);
R.Assign(15, 10, 25, 12);
Insert(New(PButton, Init(R, '~O~k', cmOK, bfDefault)));
R.Assign(28, 10, 38, 12);
Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
end;
�Оглавлен ие
C:= DeskTop^.ExecView(Dialog);
Dispose(Dialog, Done);
end;
Как Вы видите, создание кнопки требует задание четырех параметров в конструкторе Init:
1. Область, закрываемая кнопкой (не забудьте оставить место для тени!).
2. Текст, который появляется в кнопке.
3. Команда, связанная с кнопкой.
4. Флаг типа кнопки (нормальная или по умолчанию).
Заметим, что нет смысла окрашивать букву "С" в слове "Cancel", поскольку уже определена горячая
клавиша (Esc) для этой команды.
Создавая кнопку, Вы устанавливаете ее флаг bfNormal или bfDefault. Большинство кнопок
являются нормальными (bfNormal). Кнопка, помеченная как bfDefault, будет кнопкой по
умолчанию, то есть она «нажимается», когда Вы нажимаете клавишу Enter. Turbo Vision не
проверяет, используете ли Вы только одну кнопку по умолчанию, – за это отвечаете Вы. Если Вы
назначили более чем одну кнопку по умолчанию, результат будет непредсказуемым. Обычно кнопка ОК
в диалоговом окне – это кнопка по умолчанию, и пользователь просто нажимает Enter, чтобы
закрыть диалоговое окно и использовать сделанные изменения.
Когда диалоговое окно открыто, один из элементов управления всегда подсвечен – это активный
элемент управления. Активизация элемента управления наиболее полезна для направления ввода с
клавиатуры. Например, если кнопка активна, пользователь может "нажать" кнопку, нажав пробел.
Символы могут быть введены в строку ввода, только если она активна.
Пользователь может нажать клавишу Tab для того, чтобы сделать активным другой элемент
управления внутри диалогового окна. Метки не могут быть активными, поэтому клавиша Tab
проходит мимо них. Поскольку необходимо, чтобы пользователь мог активизировать элементы в
диалоговом окне в определенном порядке, то клавиша Tab переключает управление элементами в том
порядке, в каком они вставлялись в диалоговое окно. С точки зрения внутреннего представления
объекты поддерживаются в диалоговом окне в циклически связанном списке, с последним
вставленным элементом, связанным с первым.
По умолчанию активизируется последний вставленный объект. Вы можете активизировать другой
элемент управления либо используя метод SelectNext диалогового окна, либо прямо вызывая метод
Select элемента управления. SelectNext позволяет Вам передвигаться вперед или назад по списку
элементов управления. SelectNext(False) передвигает Вас вперед по циклическому списку (в
порядке Tab); SelectNext(True) передвигает в обратном направлении.
�Оглавлен ие
Создание кластеров
Обычно выбор, который Вы хотите предложить пользователю в диалоговом окне, это не просто
выбор, обрабатываемый индивидуальными кнопками. Turbo Vision обеспечивает несколько
полезных стандартных функций управления для выбора ряда опций. Две наиболее полезных – это
зависимые и независимые кнопки. Эти две функции в основном идентичны за тем исключением, что
Вы можете задать несколько независимых, но только одну зависимую кнопку. Идентичность
зависимых и независимых кнопок связана с тем, что они являются потомками одного и того же
объекта TClaster. Для того, чтобы ознакомиться с концепцией зависимых и независимых кнопок, Вы
можете посмотреть меню Options в интегрированной среде Turbo Pascal. Многие диалоговые
окна в этом меню используют такие кнопки.
Поскольку процесс создания кластера независимых кнопок аналогичен созданию кластера зависимых
кнопок, Вам требуется детально просмотреть этот процесс только однажды. Добавим следующий код в
метод TMyApp.NewDialog после создания диалогового окна, но до добавления кнопок. Вставим
кнопки в последнюю очередь в том порядке, в котором они должны обходиться с помощью Tab (для
того, чтобы освободить место в окне, удалите из него статический текст).
R.Assign(3, 3, 18, 6);
Bruce:= New(PCheckBoxes, Init(R,
NewSItem('~H~varti',
NewSItem('~T~ilset',
NewSItem('~J~arlsberg',
nil)))
));
Insert(Bruce);
Инициализация очень проста. Вы устанавливаете прямоугольник, в котором находятся элементы (не
забудьте оставить место для самих независимых кнопок), а затем создаете связанный список указателей
на строки, завершаемый nil, которые будут показаны в следующих независимых кнопках).
Приведенный код создает набор независимых кнопок с тремя выборами. Заметьте, что Вы не дали
указание по установке каждого элемента в списке. По умолчанию они все не установлены. Часто Вам
потребуется установить все или некоторые элементы независимых кнопок. Turbo Vision
предоставляет способ легко устанавливать и сохранять значения (его мы рассмотрим ниже).
Набор независимых кнопок может содержать до 16 элементов. Информация о включенных или
выключенных элементах представляется 16 битным словом, каждый бит которого соответствует
одному элементу.
Добавим теперь набор из трех зависимых кнопок. Для этого понадобится следующий код:
R.Assign(22, 3, 34, 6);
Bruce:= New(PRadioButtons, Init(R,
NewSItem('~S~olid',
NewSItem('~R~unny',
NewSItem('~M~elted',
�Оглавлен ие
nil)))
));
Insert(Bruce);
Главное отличие между зависимыми и независимыми кнопками в том, что Вы можете выбрать только
одну зависимую кнопку в группе и что первый элемент в группе зависимых кнопок выбран по
умолчанию.
Поскольку Вам не требуется знать состояние каждой зависимой кнопки (достаточно знать, какая
именно кнопка выбрана), данные о зависимых кнопках не побитовые. Это означает, что Вы можете
использовать более 16 зависимых кнопок. Данные о зависимых кнопках хранятся в слове и в Вашем
распоряжении 65536 зависимых кнопок на один кластер. Значение 0 указывает, что выбрана первая
зависимая кнопка, 1 – вторая и так далее.
Конечно, установки управляющих элементов может быть недостаточно. Простое предоставление
набора выборов может ничего не говорить пользователю о том, что именно он выбирает. Turbo
Vision предоставляет удобный метод для установки меток управляющих элементов в виде другого
управляющего элемента TLabel.
TLabel делает больше, чем кажется на первый взгляд. TLabel не только отображает текст, но и
связывается с другим видимым элементом. Отметка мышкой метки приведет к активизации
связанного выделенного элемента. Вы также можете определить букву сокращенного набора для
метки, окружив букву символами “~”.
Чтобы пометить независимые кнопки, добавьте следующий код сразу после вставки независимых
кнопок в диалоговое окно:
R.Assign(2, 2, 10, 3);
Insert(New(PLabel, Init(R, 'C~h~eeses', Bruce)));
Вы теперь можете активизировать набор независимых кнопок, отметив слово Cheeses (или нажав
Alt + h). Это слово предоставляет информацию и об элементах в данном окне. Аналогично
добавляется метка к зависимым кнопкам:
R.Assign(21, 2, 33, 3);
Insert(New(PLabel, Init(R, 'Cons~i~stency', Bruce)));
�Оглавлен ие
Строка ввода
Существует еще один тип элемента управления, который Вы можете добавить в диалоговое окно –
TInputLine, называемый строкой ввода. Работа строки ввода чрезвычайно сложна, но с Вашей точки
зрения как программиста, это очень простой для использования объект.
Добавим следующий код после кода, назначающего метку зависимым кнопкам и до выполнения
диалогового окна:
R.Assign(3, 8, 37, 9);
Bruce:= New(PInputLine, Init(R, 34));
Insert(Bruce);
R.Assign(2, 7, 24, 8);
Insert(New(PLabel, Init(R, 'Delivery instructions', Bruce)));
Установка строки ввода проста: Вы назначаете прямоугольник, который определяет длину строки
ввода на экране. Необходим еще один параметр для определения максимальной длины редактируемой
строки. Эта длина может превышать отображаемую длину, поскольку объект TInputLine знает, как
выполнять скроллинг строки. По умолчанию строка ввода может обрабатывать клавиши, команды
редактирования, выбор и движение с помощью мышки. Строка ввода также имеет метку, поскольку
непомеченная строка ввода может быть еще более непонятной для пользователя, чем непомеченный
кластер.
�Оглавлен ие
Установка и получение данных
Сейчас, когда Вы сконструировали достаточно сложное диалоговое окно, Вам нужно узнать, как его
использовать. Вы создали интерфейс пользователя, теперь Вам необходимо связать его с программой.
Элементы управления бесполезны, если Вы не знаете, как получить информацию от них.
Вы должны иметь возможность:
1) установить начальные значения элементов управления при открытии диалогового окна;
2) прочитать значения, когда диалоговое окно закрывается.
Все изменения должны быть учтены лишь тогда, когда окно успешно закрыто. Если же пользователь
решил отменить диалог с окном, то все внесенные изменения должны быть проигнорированы.
Возможности Turbo Vision позволяют сделать это. Ваша программа управляет записью информации
в диалоговое окно при его открытии. Когда пользователь заканчивает работу с диалоговым окном,
Вашей программе требуется проверить, отменено диалоговое окно или было закрыто нормально. Если
оно было отменено, Вы просто работаете без изменения записи. Если диалоговое окно было закрыто
успешно, Вы можете прочитать запись из диалогового окна в той же форме, в которой она была
передана в него.
Для копирования данных в видимый элемент и из него используются методы SetData и GetData.
Каждый видимый элемент имеет эти методы. Когда группа (такая как TDialog) инициализируется с
помощью вызова SetData, она передает данные дальше, вызывая методы SetData для каждого из его
подэлементов. (Заметим, что когда Вы вызываете SetData для группы, Вы передаете ему запись
данных, которая содержит данные для каждого из видимых элементов в группе. Вам необходимо
расположить данные для них в том же порядке, в каком они были вставлены в группу).
Вам также требуется установить правильный размер данных для каждого из видимых элементов. Все
видимые элементы имеют метод DataSize, который возвращает размер данных видимого элемента.
Каждый видимый элемент копирует DataSize данных из этой записи данных, а затем передвигает
указатель, чтобы показать следующему видимому элементу, с какого места следует начинать. Если
данные видимого подэлемента будут иметь неверный размер, каждый последующий подэлемент будет
копировать неверные данные.
Если Вы создаете новый видимый элемент и добавляете в него поля данных, не забудьте перекрыть
методы DataSize, SetData и GetData так, чтобы они обрабатывали правильные значения. Порядок
обработки и размеры данных всецело в Ваших руках. Компилятор не будет возвращать сообщения,
если Вы сделаете ошибку.
После выполнения диалогового окна Ваша программа должна убедиться вначале, что диалоговое окно
не было отменено, затем вызвать GetData для передачи информации в Вашу программу. Так в Вашем
примере Вы инициализируете по порядку кластер независимых кнопок, метку, кластер зависимых
кнопок, метку, строку ввода до 128 символов, метку и две кнопки (ОК и Cancel). Таблица 6.1
приводит все требуемые для этого данные.
�Оглавлен ие
Данные для элементов управления диалогового окна
Таблица 6.1
Элементы управления
Требуемые данные
Независимые кнопки
Word
Метка
Нет
Зависимые кнопки
Word
Метка
Нет
Строка ввода
string[128]
Метка
Нет
Кнопка
Нет
Кнопка
Нет
Видимые элементы, которые не имеют данных (такие, как метки и кнопки), используют метод
GetData, который они наследуют от TView и который ничего не делает. Это означает, что когда Вы
получаете и устанавливаете данные, Вы можете пропустить метки и кнопки.
Вы можете установить запись данных для диалогового окна в глобальном типе:
type
DialogData = record
CheckBoxData: Word;
RadioButtonData: Word;
InputLineData: string[128];
end;
Теперь все, что Вам необходимо сделать, – это инициализировать запись при запуске программы
(например, в MyApp.Init), установить данные, когда Вы входите в диалоговое окно, и прочитать их,
когда диалоговое окно успешно закрыто. Это проще сказать в Паскале, чем по-русски! После того, как
Вы объявите тип, Вы объявляете глобальную переменную:
var
DemoDialogData: DialogData;
затем добавляете одну строку до выполнения диалогового окна и одну после:
Dialog^.SetData(DemoDialogData);
C:= DeskTop^.ExecView(Dialog);
if C <> cmCancel then Dialog^.GetData(DemoDialogData);
и добавляете шесть строк в метод TMyApp.Init, чтобы установить начальные значения для
диалогового окна:
with DemoDialogData do
�Оглавлен ие
begin
CheckboxData:= 1;
RadioButtonData:= 2;
InputLineData:= 'Phone home.';
end;
Сейчас все изменения, которые Вы сделаете в диалоговом должны сохраниться, когда Вы снова его
откроете, если только клавиша Cancel не отменила диалог.
�Оглавлен ие
Другие элементы управления
Модуль TDialog предоставляет дополнительные возможности, которые не были рассмотрены выше.
Они используются аналогично: Вы создаете новый экземпляр, вставляете его в диалоговое окно и
включаете соответствующие данные в запись данных.
Просмотр списка. TListViewer выводит список в одну или несколько колонок, и пользователь
может выбрать элемент из этого списка. TListViewer может взаимодействовать с двумя полосами
скроллинга. Он предназначен для построения блока и не используется отдельно. Он может
обрабатывать список, но сам списка не содержит. Его абстрактный метод GetText загружает
элементы списка для его метода Draw. Наследник TListViewer должен перекрывать GetText для
загрузки актуальных данных.
Окно списка. TListBox наследуется от TListViewer. Он владеет TCollection, который должен
быть указателем на строки. TListBox наследует только одну полосу скроллинга. Примером окна
списка является список выбора файлов в интегрированной среде Turbo Pascal. При получении и
установке данных окна списка удобно пользоваться типом записи TListBoxRec, который хранит
указатель на список строк и слово, указывающее на текущий выбранный элемент списка.
История. THistory реализует объект, который работает со строкой ввода и связанным окном списка.
Нажимая на символ стрелки, стоящей после строки ввода, пользователь вызывает список предыдущих
значений для этой строки и может выбрать любой из них. Это предотвращает повторный набор.
Стандартные диалоговые окна. Модуль StdDlg содержит предопределенное диалоговое окно,
называемое TFileDialog. Вы используете это окно в интегрированной среде, когда открываете
файл. TFileDialog использует ряд других объектов из модуля StdDlg, которые могут быть полезны:
TFileInputLine=object(TInputLine)
TFileCollection=object(TSortedCollection)
TSortedListBox=object(TListBox)
TFileList=object(TSortedListBox)
TFileInfoPane=object(TView).
В заключение приведем окончательный текст программы TFirst6 со всеми внесенными в нее
изменениями.
Program TFirst6;
uses App, Objects, Menus, Drivers, Views, Dialogs;
const
FileToRead='e:\tp60\urok.txt';
MaxLines = 100;
cmNewWin=199;
cmFileOpen=200;
cmNewDialog = 201;
winCount: Integer = 0;
type
�Оглавлен ие
TMyApp=Object(TApplication)
procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual;
procedure NewWindow; virtual;
procedure NewDialog;
procedure HandleEvent(var Event: TEvent); virtual;
end;
type
PInterior=^Tinterior;
TInterior=object(TScroller)
constructor Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
procedure Draw; virtual;
end;
type
PDemoWindow=^TDemoWindow;
TDemoWindow=object(TWindow)
constructor Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
function MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
procedure SizeLimits(var Min,Max:TPoint);virtual;
end;
type
PDemoDialog = ^TDemoDialog;
TDemoDialog = object(TDialog)
end;
type
DialogData = record
CheckBoxData: Word;
RadioButtonData: Word;
InputLineData: string[128];
end;
var
MyApp: TMyApp;
�Оглавлен ие
S: string;
LineCount: Integer;
Lines: array[0..MaxLines - 1] of PString;
DemoDialogData: DialogData;
procedure TDemoWindow.SizeLimits(var Min,Max:TPoint);
var R: TRect;
begin
TWindow.SizeLimits(Min,Max);
GetExtent(R);
Min.X:=R.B.X div 2;
end;
constructor TInterior.Init(var Bounds: TRect; AHScrollBar,
AVScrollBar: PScrollBar);
begin
TScroller.Init(Bounds, AHScrollBar, AVScrollBar);
Options:= Options or ofFramed;
SetLimit(128, LineCount);
end;
procedure ReadFile;
var
F: Text;
S: String;
begin
LineCount:= 0;
Assign(F,FileToRead);
Reset(F);
while not Eof(F) and (LineCount < MaxLines) do
begin
Readln(F, S);
Lines[LineCount]:= NewStr(S);
Inc(LineCount);
end;
Close(F);
end;
�Оглавлен ие
procedure DoneFile;
var
I: Integer;
begin
for I:= 0 to LineCount - 1 do
if Lines[I] <> nil then DisposeStr(Lines[i]);
end;
procedure TInterior.Draw;
var
Color: Byte;
I,Y: Integer;
B: TDrawBuffer;
begin
Color:= GetColor(1);
for Y:= 0 to Size.Y - 1 do
begin
MoveChar(B, ' ', Color, Size.X);
i:= Delta.Y + Y;
if (I < LineCount) and (Lines[I] <> nil) then
MoveStr(B, Copy(Lines[I]^, Delta.X + 1, Size.X), Color);
WriteLine(0, Y, Size.X, 1, B);
end;
end;
constructor TDemoWindow.Init(Bounds: TRect; WinTitle: string;
WindowNo: Integer);
var
S: string[3];
R: TRect;
RInterior, LInterior: PInterior;
begin
Str(WindowNo, S);
TWindow.Init(Bounds, WinTitle+' '+S, wnNoNumber);
GetExtent(Bounds);
R.Assign(Bounds.A.X, Bounds.A.Y, Bounds.B.X div 2 + 1,
�Оглавлен ие
Bounds.B.Y);
LInterior:= MakeInterior(R, True);
LInterior^.GrowMode:= gfGrowHiY;
Insert(Linterior);
R.Assign(Bounds.B.X div 2, Bounds.A.Y, Bounds.B.X, Bounds.B.Y);
RInterior:= MakeInterior(R,False);
RInterior^.GrowMode:= gfGrowHiX + gfGrowHiY;
Insert(RInterior);
end;
function TDemoWindow.MakeInterior(Bounds: TRect; Left: Boolean): PInterior;
var
HScrollBar, VScrollBar: PScrollBar;
R: TRect;
begin
R.Assign(Bounds.B.X-1, Bounds.A.Y+1, Bounds.B.X, Bounds.B.Y-1);
VScrollBar:= New(PScrollBar, Init(R));
VScrollBar^.Options:= VScrollBar^.Options or ofPostProcess;
if Left then VScrollBar^.GrowMode:= gfGrowHiY;
Insert(VScrollBar);
R.Assign(Bounds.A.X+2, Bounds.B.Y-1, Bounds.B.X-2, Bounds.B.Y);
HScrollBar:= New(PScrollBar, Init(R));
HScrollBar^.Options:= HScrollBar^.Options or ofPostProcess;
if Left then HScrollBar^.GrowMode:= gfGrowHiY + gfGrowLoY;
Insert(HScrollBar);
Bounds.Grow(-1,-1);
MakeInterior:= New(PInterior, Init(Bounds, HScrollBar, VScrollBar));
end;
procedure TMyApp.InitStatusLine;
var R:TRect;
begin
GetExtent(R);
R.A.Y:=R.B.Y-1;
StatusLine:=New(PStatusLine,Init(R,
NewStatusDef(0,$FFFF,
�Оглавлен ие
NewStatusKey('~Alt-X~Exit',kbAltX,cmQuit,
NewStatusKey('~F4~New',kbF4,cmNewWin,
NewStatusKey('~Alt-F3~Close',kbAltF3,cmClose,
NewStatusKey('~F10~Menu',kbF10,cmMenu,
nil)))),
nil)))
end;
procedure TMyApp.InitMenuBar;
var R:TRect;
begin
GetExtent(R);
R.B.Y:=R.A.Y+1;
MenuBar:=New(PMenuBar,Init(R,NewMenu(
NewSubMenu('~F~ile',hcNoContext,NewMenu(
NewItem('~O~pen','F3',kbF3,cmFileOpen,
hcNoContext,
NewItem('~N~ew','F4',kbF4,cmNewWin,
hcNoContext,
NewLine(
NewItem('E~x~it','Alt-X',kbAltX,cmQuit,
hcNoContext,
nil))))),
NewSubMenu('~W~indow',hcNoContext,NewMenu(
NewItem('~N~ext','F6',kbF6,cmNext,
hcNoContext,
NewItem('~Z~oom','F5',kbF5,cmZoom,
hcNoContext,
NewItem('~S~ize/Move','Ctr-F5',kbCtrlF5,cmResize,
hcNoContext,
NewItem('~T~ile','',0,cmTile,
hcNoContext,
NewItem('~C~ascade','',0,cmCascade,
hcNoContext,
NewItem('~D~ialog', 'F2', kbF2, cmNewDialog, hcNoContext,
�Оглавлен ие
nil))))))),
nil)))))
end;
procedure TMyApp.NewDialog;
var
Bruce: PView;
Dialog: PDemoDialog;
R: TRect;
C: Word;
begin
R.Assign(20, 6, 60, 19);
Dialog:= New(PDemoDialog, Init(R, 'Demo Dialog'));
with Dialog^ do
begin
R.Assign(3, 3, 18, 6);
Bruce:= New(PCheckBoxes, Init(R,
NewSItem('~H~varti',
NewSItem('~T~ilset',
NewSItem('~J~arlsberg',
nil)))
));
Insert(Bruce);
R.Assign(2, 2, 10, 3);
Insert(New(PLabel, Init(R, 'Cheeses', Bruce)));
R.Assign(22, 3, 34, 6);
Bruce:= New(PRadioButtons, Init(R,
NewSItem('~S~olid',
NewSItem('~R~unny',
NewSItem('~M~elted',
nil)))
));
Insert(Bruce);
R.Assign(21, 2, 33, 3);
Insert(New(PLabel, Init(R, 'Consistency', Bruce)));
�Оглавлен ие
R.Assign(3, 8, 37, 9);
Bruce:= New(PInputLine, Init(R, 34));
Insert(Bruce);
R.Assign(2, 7, 24, 8);
Insert(New(PLabel, Init(R, 'Delivery instructions', Bruce)));
R.Assign(15, 10, 25, 12);
Insert(New(PButton, Init(R, '~O~k', cmOK, bfDefault)));
R.Assign(28, 10, 38, 12);
Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
end;
Dialog^.SetData(DemoDialogData);
C:= DeskTop^.ExecView(Dialog);
if C <> cmCancel then Dialog^.GetData(DemoDialogData);
Dispose(Dialog, Done);
end;
procedure TMyApp.NewWindow;
var
Window: PDemoWindow;
R: TRect;
begin
Inc(WinCount);
R.Assign(0,0,30,7);
R.Move(Random(58),Random(16));
Window:=New(PDemoWindow, Init(R,'Demo Window ', WinCount));
Window^.Options:=Window^.Options+ofTileable;
DeskTop^.Insert(Window);
end;
procedure TMyApp.HandleEvent(var Event: TEvent);
var R: TRect;
begin
TApplication.HandleEvent(Event);
if Event.What=evCommand then
begin
case Event.Command of
�Оглавлен ие
cmNewWin: NewWindow;
cmNewDialog: NewDialog;
cmTile:
begin
DeskTop^.GetExtent(R);
DeskTop^.Tile(R);
end;
cmCascade:
begin
DeskTop^.GetExtent(R);
DeskTop^.Cascade(R);
end
else Exit;
end;
ClearEvent(Event);
end;
end;
BEGIN
with DemoDialogData do
begin
CheckboxData:= 1;
RadioButtonData:= 2;
InputLineData:= 'Phone home.';
end;
ReadFile;
MyApp.Init;
MyApp.Run;
MyApp.Done;
DoneFile;
END.
�Оглавлен ие
Задание для самостоятельной работы
1. Используя вышеприведенный текст программы TFirst6, создайте программу, реализующую идею
электронной записной книжки. Ваша книжка должна содержать сведения о студентах Вашей группы
(фамилия, имя, отчество, год рождения, год поступления, номер зачетной книжки, домашний адрес,
номер телефона, сведения о родителях и т. д.). Предусмотрите возможность просмотра записей и их
изменения и дополнения в режиме диалога с пользователем.
�Оглавлен ие
Приложение
Встроенный ассемблер
Сообщения и коды ошибок
�Оглавлен ие
ВСТРОЕННЫЙ АССЕМБЛЕР
Ассемблером называется машинно-зависимый компилятор, преобразующий специальным образом
составленные текстовые строки в машинные инструкции. Ассемблер упрощает разработку программ за
счет того, что предоставляет пользователю доступ к кодам машинных инструкций и операндам с
помощью символьных имен.
Встроенный ассемблер имеется в версиях 6.0 и 7.0 Турбо Паскаля и представляет собой мощный
инструмент, расширяющий возможности ПК.
ОПИСАНИЕ МП 8086/8088
Встроенный ассемблер дает возможность программировать на уровне отдельных машинных
инструкций. Это – главное отличие ассемблера от Паскаля и в этом сосредоточены его достоинства и
недостатки. Достоинство заключается в том, что, программируя на ассемблере, программист обычно
выбирает последовательность машинных инструкций так, чтобы реализовать нужные вычисления с
максимальной скоростью при минимальных затратах памяти, в то время как даже такой весьма
совершенный компилятор, как компилятор Турбо Паскаля, неизбежно вносит в машинный код
некоторую избыточность, уменьшающую скорость счета и увеличивающую затраты памяти. С другой
стороны, программирование на уровне машинных инструкций – сложное занятие и не может
сравниться по скорости разработки программ на Паскале – в этом заключается главный недостаток
ассемблера.
Чтобы использовать средства ассемблера, необходимо представлять себе детали архитектуры
микропроцессоров Intel 8086. К этому семейству относятся микропроцессоры:
8086 – 16-разрядный микропроцессор, используемый в ПК IBM PC/XT;
8088 – аналог 8086, отличается от него только взаимодействием с памятью: 8086 может
обмениваться с памятью как байтами, так и 16-разрядными словами, в то время как 8088 – только
байтами;
80286 – улучшенный вариант 8086, используемый в ПК IBM AT; может работать в двух режимах: в
реальном режиме, полностью эмулирующем работу МП 8086, и в защищенном режиме, в котором
способен адресовать память до 16 Мбайт (в реальном – до 1 Мбайт);
80386 – 32-разрядный вариант 80286; способен адресовать до 4 Гбайт;
80486 – комбинация 80386/80387, т.е. имеет внутреннюю подсистему реализации операций с
плавающей точкой;
80586
(Pentium) – имеет ряд усовершенствований, обеспечивающих ему увеличение
производительности в 2...3 раза по сравнению с 80486, в том числе возможность обрабатывать 64
– разрядные числа.
Микропроцессоры этого семейства наращивают свои возможности в перечисленном порядке, но
строго совместимы от младших моделей к старшим: все, что может 8086/8088, реализует и Pentium,
но не наоборот. Ниже обсуждается архитектура (внутреннее устройство, способы адресации и система
команд) МП 8086/8088.
Регистры
В МП 8086/8088 имеется 14 регистров. В функциональном отношении они делятся на группы:
регистры общего назначения (AX, BX, CX, DX); предназначены для хранения операндов и
�Оглавлен ие
выполнения основных команд; любой из них может использоваться как совокупность двух
независящих друг от друга 8 – разрядных регистров: старшего байта (АН, ВН, СН, DH) и младшего
байта (AL, BL, CL, DL); например, АХ состоит из АН и AL;
сегментные регистры (CS, DS, SS, ES); используются для указания сегмента при адресации
памяти;
регистры–указатели (SP, BP, IP); используются для указания смещения при адресации памяти;
индексные регистры (SI, DI); применяются для индексной адресации;
регистр флагов; используется для хранения признаков состояния процессора.
Внутри одной и той же функциональной группы регистры используются различным образом. Ниже
описывается специфика использования регистров.
Регистр АХ. Является основным сумматором. Используется во всех арифметических операциях
(сложить, умножить и т.п.). Только с помощью АХ и его полурегистров AH/AL возможен обмен
данными с портами ввода/вывода.
Регистр BX. Используется как сумматор в арифметических операциях, а также как базовый регистр при
индексной адресации.
Регистр CX. В основном используется как счетчик при выполнении операций повторения и сдвига.
Может также участвовать в арифметических операциях.
Регистр DX. Используется как регистр данных в операциях ввода/вывода, а также как сумматор при
обработке длинных целых чисел (32-разрядных).
Регистр CS. Содержит номер сегмента памяти (сегмента кода), в котором располагается текущая
машинная инструкция. Для получения полного адреса следующей команды его содержимое сдвигается
влево на 4 разряда и складывается с регистром-указателем IP. Содержимое CS автоматически
изменяется в командах дальнего (межсегментного) перехода и вызова процедур.
Регистр IP. Определяет смещение относительно начала сегмента кода CS очередной исполняемой
машинной инструкции. Содержимое IP автоматически изменяется в ходе исполнения инструкции,
обеспечивая правильный порядок выборки команд из памяти.
Регистр DS. Содержит номер сегмента памяти (сегмента данных), в котором располагаются данные
(константы и переменные). Все глобальные переменные и типизированные константы программы
Турбо Паскаля всегда располагаются в единственном сегменте, адресуемом этим регистром.
Регистр SS. Содержит номер сегмента стека. Стек – это участок автоматически адресуемой памяти,
предназначенный для временного хранения операндов. С помощью стека Турбо Паскаль организует
обмен данными между программой и процедурами, кроме того, в нем он размещает все локальные
переменные (т.е. переменные, объявленные внутри процедуры). Память стека используется по правилу
«последним пришел – первым ушел»: самый последний помещенный в стек операнд будет первым
извлекаться из него.
Регистр SP. Указывает на вершину стека, т.е. совместно с регистром SS адресует ячейку памяти, куда
будет помещаться операнд или откуда он будет извлекаться. Содержимое этого регистра
автоматически уменьшается после размещения в стеке очередного операнда и увеличивается после
извлечения операнда из стека.
�Оглавлен ие
Регистр ВР. Так называемый указатель базы. Облегчает создание и использование локального стека
(т.е. стека для использования внутри процедуры).
Регистр ES. Дополнительный сегментный регистр ES используется для межсегментного обмена
данными и в некоторых строковых операциях.
Регистр SI. Определяет адрес источника информации при индексной адресации данных (например,
при обработке массивов). Обычно используется в паре с регистром DS.
Регистр DI. В паре с регистром ES определяет приемник информации при межсегментном обмене
данными.
Регистр флагов. Отдельные разряды (биты) этого регистра имеют следующее назначение.
Флаг переноса CF. Содержит 1, если произошел перенос единицы при сложении или заем единицы
при вычитании. Используется также в циклических операциях и операциях сравнения.
Флаг четности PF. Содержит 1, если в результате операции получено число с четным количеством
значащих разрядов, т.е. дополняет результат до нечета – используется в операциях обмена для
контроля данных.
Флаг внешнего переноса АР. Контролирует перенос из 3-го бита данных. Используется при операциях
над упакованными десятичными числами.
Флаг нуля ZF. Равен 1, если в результате операции получен ноль, и равен 0 в противном случае.
Флаг знака SF. Равен 1, если в результате операции получено отрицательное число (с единицей в
старшем разряде).
Флаг трассировки TF. Равен 1, если программа исполняется по шагам, с передачей управления после
каждой выполненной команды по прерыванию с вектором 1.
Флаг прерываний IF. Содержит 1, если микропроцессору разрешена обработка прерываний.
Флаг направления DF. Управляет направлением передачи данных: если он содержит 0, то после
каждой индексной операции содержимое индексных регистров увеличивается на 1, в противном
случае – уменьшается на 1.
Флаг переполнения OF. Устанавливается в единицу, если в результате операции получено число,
выходящее за разрядную сетку микропроцессора.
Адресация
В архитектуре МП 8086/8088 адрес любого байта задается двумя 16-битовыми словами – сегментом и
смещением. При формировании 20-разрядного полного адреса, необходимого для адресации в
пределах 1 Мбайт, сегмент сдвигается влево на 4 разряда (умножается на 16) и складывается со
смещением. Поскольку емкость 16-разрядного смещения составляет 65536 значений, в пределах
одного сегмента можно адресовать до 64 Кбайт.
Архитектура МП позволяет использовать семь различных способов адресации.
Регистровая
Извлекает операнд из регистра или помещает его в регистр. Примеры:
mov ax, bx
{Извлекаем из ВХ и помещаем в АХ}
�Оглавлен ие
add сх, ах
{Содержимое АХ прибавляем к СХ}
push сх
{Заталкиваем в стек содержимое СХ}
Непосредственная
Операнд (8- или 16-разрядная константа) содержится непосредственно в теле команды. Примеры:
mov ах, 100
{Загружаем в АХ значение 100}
add ax, 5
{К содержимому АХ прибавляем 5}
mov cx, $FFFF
{Помещаем в СХ значение 65535}
Прямая
Смещение операнда задается в теле программы и складывается с регистром DS; например:
Var
X: Word;
В: Byte;
………
mov ах, Х
{Пересылаем значение переменной Х в регистр АX}
add ah, В
{К содержимому регистра АН прибавляем значение переменной В}
mov Х, ах
{Пересылаем содержимое регистра АХ в область памяти переменной X}
Косвенная регистровая
Исполнительный адрес операнда (его смещение) содержится в одном из регистров ВХ, ВР, SI или
DI. Для указания косвенной адресации этот регистр должен заключаться в квадратные скобки,
например:
mov ax, [bx]
АХ};
{Содержимое 16-разрядного слова, хранящегося в памяти по адресу DS:BX, пересылаем в регистр
Каждый из регистров BX...DI по умолчанию работает со своим сегментным регистром:
DS:BX, SS:BP, DS:SI, ES:DI
Допускается явное указание сегментного регистра, если он отличается от умалчиваемого, например:
mov ax, es:[bx]
Адресация по базе
Базовый регистр ВХ (или ВР) содержит базу (адрес начала некоторого фрагмента памяти),
относительно которой ассемблер вычисляет смещение, например:
mov ах, [bх]+10 {Загружаем в АХ 10-й по счету байт от начала базы памяти по адресу DS:BX};
Индексная адресация
Один из индексных регистров SI или DI указывает положение элемента относительно начала
некоторой области памяти. Пусть, например, АОВ – имя массива значений типа Byte. Тогда можно
использовать такие фрагменты:
mov si, 15
{Помещаем в SI константу 15}
mov ah, АОВ[si] {Пересылаем в АН 16-й по порядку байт от начала массива}
�Оглавлен ие
mov si, 0
mov АОВ[si], ah {Пересылаем полученное в самый первый элемент массива}
Адресация по базе с индексированием
Вариант индексной адресации для случая, когда индексируемая область памяти задается своей базой.
Например:
mov ax, [bx][si]
Этот тип адресации удобен при обработке двумерных массивов. Если, например, АОВ есть массив из
10ґ10 байт вида
Var
АОВ: array [0..9, 0..9] of Byte;
то для доступа к элементу АОВ [2,3] можно использовать такой фрагмент
Mov bx, 20
{База строки 2}
Mov si, 2
{Номер 3-го элемента}
Mov ax, АОВ[bx][si]
{Доступ к элементу}
Система команд
В приводимых ниже таблицах указывается мнемоника всех допустимых инструкций для МП
8086/8088. Для удобства пользования все команды разбиты на 6 функциональных групп – пересылки
данных, арифметические, битовые, строковые, передачи управления, прерываний. Внутри каждой
группы команды объединяются в подгруппы по общим дополнительным признакам.
Детальный анализ всех команд МП 8086/8088 занял бы слишком много места, поэтому в идущих за
таблицами пояснениях рассматриваются лишь наиболее популярные команды.
Команды пересылки данных
Мне моника
MOV
PUSH
POP
XCHG
XLAT
IN
OUT
LEA
LDS
LES
LAHF
SAHF
PUSHF
POPF
Формат
Поясне ние
КОМАНДЫ ОБЩ ЕГО НАЗНАЧЕНИЯ
MOV приемник, источник
Переслать значение
PUSH источник
Поместить в стек
POP приемник
Извлечь из стека
XCHG приемник, источник
Обменять значения
XLAT таблица
Загрузить в AL байт из таблицы
Команды ввода-вывода
IN аккумулятор, порт
Читать из порта
OUT порт, аккумулятор
Записать в порт
Команды пе ре сылки адре са
LEA регистр 16, память 16
Загрузить исполнительный адрес
LDS регистр 16, память 32
Загрузить в DS регистр 16 полный адрес
LES регистр 16, память 32
Загрузить в ES регистр 16 полный адрес
Команды пе ре сылки флагов
LAHF
Загрузить флаги в АН
SAHF
Установить флаги из АН
PUSHF
Поместить флаги в стек
POPF
Извлечь флаги из стека
�Оглавлен ие
Одна из наиболее часто используемых команд – MOV позволяет в защищенном режиме переслать байт
или слово из регистра в регистр из памяти в регистр или из регистра в память. Тип пересылаемых
данных (байт или слово) определяется регистром, участвующим в пересылке. Ниже приводятся
примеры использования команды:
mov ax, Table
{Пересылка слова из памяти в АХ}
mov Table, ah
{Пересылка байта из АН в память}
mov ds, ax
{Пересылка в сегмент данных}
mov es:[bx], ax {Пересылка слова в память: базовая адресация с заменой сегмента}
mov ch, -17
{Переслать константу в регистр}
mov Table, $FF
{Переслать константу в память}
С помощью MOV нельзя пересылать:
из памяти в память, например, вместо
mov Mem1, Mem2
следует использовать
mov ax, Mem2
mov Mem1, ах
константу или переменную в DS, например, нельзя
mov ds, Data_Seg
нужно:
mov ax, Data_Seg
mov ds, ax
один сегментный регистр в другой, например, нельзя
mov es, ds
но можно
mov ax, ds mov es, ax
в регистр CS; значение этого регистра (сегмента кода) автоматически меняется при выполнении
дальних команд CALL и JMP; кроме того, он загружается из стека при выполнении команды RETF
(выход из дальней процедуры).
Для временного сохранения регистров и данных, а также для обмена значениями между регистрами
широко используются стековые команды PUSH и POP. Каждая из них работает со словом, т.е. в стек
нельзя поместить или извлечь из него одиночный байт. При выполнении PUSH вначале уменьшается
на 2 содержимое указателя SP, а затем операнд помещается по адресу SS:SP. При извлечении из стека
сначала читается память по адресу SS:SP, а затем SP увеличивается на 2. Таким образом, при
заполнении указатель вершины стека SP смещается к младшим адресам, а при освобождении – к
старшим. При работе со стеком следует помнить о специфике использования стековой памяти
(«последним пришел – первым ушел»), а также о том, что эта память интенсивно используется при
вызове процедур, т.е. состояние стека к моменту выхода из процедуры должно быть строго
�Оглавлен ие
согласовано с дальнейшей работой программы. Первое условие определяет порядок извлечения
данных из стека – он должен быть обратным порядку, в котором эти данные помещались в стек.
Второе условие фактически означает, что после выхода из процедуры указатель SP должен содержать
то же смещение, что и к моменту входа в нее. Иными словами, процедура не должна «забыть» в стеке
лишнее слово или взять из него больше нужного.
Команда загрузки адреса LEA загружает в регистр адрес (смещение) нужного участка памяти. Этого же
можно достичь с помощью зарезервированного слова OFFSET, стоящего перед именем переменной.
Например:
Var
X: Word;
………….
Asm
mov ax, OFFSET X
{Загружаем смещение X в АХ}
lea ax, X
{To же действие}
end;
Разница состоит в том, что в случае команды LEA разрешается использовать индексную адресацию,
что особенно удобно при пересылке массивов данных.
Две другие команды адресной загрузки – LDS и LES загружают первое 16-разрядное слово из
источника в регистр-приемник, а затем следующее слово – в регистр DS или ES, т.е. они рассчитаны
на загрузку полного адреса операнда (сегмента и смещения).
Арифметические команды
Мне моника
Формат
Комме нтарий
Команды сложе ния
ADD
ADD приемник, источник
Сложить
ADC
ADC приемник, источник
Сложить, добавить перенос
ААА
ААА
Скорректировать сложение для таблицы ASCII
DAA
DAA
Скорректировать сложение для двоично-десятичных
чисел
INC
INC приемник
Увеличить на единицу
Команды вычитания
SUB
SUB приемник, источник
Вычесть
SBB
SBB приемник, источник
Вычесть с заемом
AAS
AAS
Скорректировать вычитание для таблицы ASCII
DAS
DAS
Скорректировать вычитание для двоично-десятичных
чисел
DEC
DEC приемник
Уменьшить на единицу
NEG
NBG приемник
Обратить знак
�Оглавлен ие
СМР
СМР приемник, источник
Сравнить
Команды умноже ния
MUL
MUL источник
Умножить без знака
IMUL
IMUL источник
Умножить со знаком
ААМ
ААМ
Скорректировать умножение для таблицы ASCII
Команды де ле ния
DIV
DIV источник
Делить без знака
IDIV
IDIV источник
Делить со знаком
AAD
AAD
Скорректировать деление для таблицы ASCII
Команды расшире ния знака
CBW
CBW
Преобразовать байт в слово
CWD
CWD
Преобразовать слово в двойное слово
При использовании арифметических команд следует помнить о том, что МП может обрабатывать
знаковые числа, числа без знака, а также двоично-десятичные числа. В беззнаковых числах для
представления значения используются все биты, т.е. они эквивалентны типам Byte и Word, в то
время как знаковые числа в старшем разряде хранят знак числа и эквивалентны типам Shortint и
Integer. Двоично-десятичные числа используют по 4 бита для каждого десятичного разряда и могут
быть упакованными или неупакованными. В первом случае один байт хранит 2 десятичные цифры
(старшая – в старшем полубайте), во втором – только одну (старший полубайт не используется).
SUB,
MUL,
DIV)
Основные арифметические команды МП (ADD,
не учитывают
двоично-десятичную форму представления чисел, поэтому в архитектуру МП включены команды
коррекции результата.
Битовые команды
Мне моника
Формат
Комме нтарий
Логические команды
AND
AND приемник, источник
Выполнить AND
OR
OR приемник, источник
Выполнить OR
XOR
XOR приемник, источник
Выполнить XOR
NOT
NOT приемник
Выполнить NOT
TEST
TEST приемник, источник
Проверить
Сдвиговые команды
SAL/SHL
SAL приемник, счетчик
Сдвинуть влево
SAR/SHR
SAR приемник, счетчик
Сдвинуть вправо
ROL
ROL приемник, счетчик
Сдвинуть влево циклически
ROR
ROR приемник, счетчик
Сдвинуть вправо циклически
RCL
RCL приемник, счетчик
Сдвинуть влево с переносом
�Оглавлен ие
RCR
RCR приемник, счетчик
Сдвинуть вправо с переносом
Битовые команды используются при исчислении логических выражений, а также в тех случаях, когда
необходимо изменить отдельные разряды операнда. Логические команды AND, OR, XOR и NOT
эквивалентны соответствующим операциям Турбо Паскаля в случае, когда операндами являются
целочисленные выражения. Команда TEST выполняет целочисленную операцию поразрядного
суммирования AND, но не изменяет значения операндов, а лишь устанавливает флаги в соответствии
со значением результата сравнения: обнуляет CF и OF, изменяет PF, ZF, SF и не меняет AF (флаг ZF
установится в 1 в том случае, когда оба операнда содержат по единице хотя бы в одном
соответствующем разряде). Команды сдвига SHL/SHR эквивалентны одноименным операциям Турбо
Паскаля и отличаются от команд циклического сдвига ROL/ROR тем, что вытесненные в ходе их
выполнения значащие разряды теряются, в то время как при циклическом сдвиге эти разряды
появляются «с другой стороны». Например, если выполнить фрагмент
mov a1, 1
{Загружаем в AL единицу}
shr a1, 1
{Сдвигаем вправо на 1 разряд}
регистр AL будет содержать 0 (вытесненная вправо единица будет помещена в CF), в то время как
после замены команды SHR на ROR в нем будет значение $80=128 (вытесненная единица будет
помещена в старший бит регистра).
Заметим, что счетчиком в командах сдвига может быть цифра 1 или количество сдвигов, указываемое
в регистре CL.
Команды передачи управления
Мне моника
Формат
Комме нтарий
Бе зусловные пе ре ходы
CALL
RET
JUMP
CALL имя
Войти в процедуру
RET
[количество_параметров]
Вернуться из процедуры
JUMP имя
Перейти
Условные пе ре ходы
JA/JNBE
JA близкая метка
Перейти, если выше (после сравнения беззнаковых операндов)
JAE/JNB
JAE близкая метка
Перейти если выше или равно
JB близкая метка
Перейти, если ниже
JBE близкая метка
Перейти если ниже или равно
JCXZ
JCXZ близкая метка
Перейти, если СХ=0
JE/JZ
JE близкая метка
Перейти, если равно
JG/JNLE
JG близкая метка
Перейти, если больше (после сравнения знаковых операндов)
JGE/JNL
LGE близкая метка
Перейти, если больше или равно
JL/JNGE
JL близкая метка
Перейти, если меньше
JLE/JNG
JLE близкая метка
Перейти, если меньше или равно
JB/JBAE/JC
JBE/JNA
�Оглавлен ие
JNC
JNC близкая метка
Перейти, если нет переноса
JNE/JNZ
JNE близкая метка
Перейти, если не равно
JNO
JNO близкая метка
Перейти, если нет переполнения
JNP/JPO
JNP близкая метка
Перейти, если нечетный
JO
JO близкая метка
Перейти, если перенос
JP/JPE
JP близкая метка
Перейти, если четный
JS
JS близкая метка
Перейти, если отрицательный
Команды управле ния циклами
LOOP
LOOP близкая метка
LOOPE/LOOPZ LOOPE близкая метка
LOOPNE/LOOPN LOOPNE близкая метка
Z
Повторить цикл
Повторять, пока равны
Повторять, пока не равны
Команды безусловных переходов CALL, RET, JMP могут использовать дальнюю или ближнюю
модель памяти, в то время как команды условных переходов – только малую (в пределах –128...+127
байтов). При дальней модели памяти (устанавливается опцией Options/Compiler/Force far
calls среды Турбо Паскаля или директивой компилятора {F+}) осуществляется как
внутрисегментная, так и межсегментная передача управления, при ближней – только
внутрисегментная.
Инструкция CALL работает следующим образом. Вначале адрес следующей за CALL инструкции (адрес
возврата) помещается в стек, затем в регистр IP (или в пару CS:IP) помещается адрес точки входа в
процедуру, таким образом сразу за командой CALL будет исполняться уже первая команда процедуры.
Оба адреса (точки входа и возврата) будут 16-битовыми смещениями для внутрисегментного вызова
или 32-битовыми полными адресами – для межсегментного. Все процедуры (функции) Паскаля,
оттранслированные в режиме {F+} или содержащие зарезервированное слово FAR в заголовке,
должны вызываться как дальние. Для этого за инструкцией CALL следует указать модель памяти:
Procedure MyProc; Far;
……
Asm
call FAR MyProc {Вызов дальней процедуры}
end;
Таким же способом должны вызываться все библиотечные подпрограммы (т.е. объявленные в
интерфейсных частях модулей). При дальнем вызове в стек сначала заталкивается содержимое
сегмента кода CS, а уже затем – смещение возврата.
При выходе из дальней процедуры команда RET извлекает из стека оба 16-разрядных слова и помещает
первое в IP, а второе в CS, а при выходе из ближней извлекает из стека только смещение и помещает
его в IP.
Команды условных переходов способны передавать управление на метку, расположенную в пределах
ближайших плюс–минус 128 байт от самой команды. Если нужно передать управление на метку,
расположенную дальше в том же сегменте, или на метку в другом сегменте, сразу: а командой условной
�Оглавлен ие
передачи располагают безусловную команду JMP или CAL, например:
cmp ах, 0
{Проверяем АХ}
jne @NotZero
{AX=0 ?}
jmp IsZero
{Да – переходим на дальнюю метку}
……
……
{Нет - продолжаем работу}
В таблице термин «выше/ниже» используется применительно к сравнению беззнаковых операндов, а
«больше/меньше» – знаковых.
Поскольку условные переходы реализуют ветвление программы на основе проверки флагов, обычно
непосредственно перед ними располагаются команды, изменяющие эти флаги, чаще всего – команда
сравнения СМР. Ниже показаны комбинации СМР–условный переход для различных соотношений
приемника и источника (первого и второго операнда) команды СМР:
Условие
Для беззнаковых чисел
Для чисел со знаками
Приемник больше источника
JA
JG
Приемник и источник равны
JE
JE
Приемник меньше источника
JB
JL
Приемник не меньше источника
JAE
JGE
Приемник не больше источника
JBE
JLE
Приемник и источник не равны
JNE
JNE
Например:
cmp ах, 5
{AX>5 ?}
ja @Above5
{Да, больше – переходим}
cmp bx, -3
{ВХ<= – 3 ?}
jle@LessM3
{Да, меньше или равен}
Команды LOOP/LOOPE/LOOPNE служат для организации циклов. Все они используют содержимое
регистра СХ как счетчик числа повторений. Команда LOOP уменьшает СХ на единицу и передает
управление на метку начала цикла, если содержимое этого регистра отлично от нуля. Команды
LOOPE/LOOPNE также уменьшают счетчик СХ, но передают управление в начало цикла при
совместном условии установки (или сброса) флага ZF и неравенства нулю счетчика СХ.
Вот как, например, можно отыскать нулевой байт в массиве АОВ:
Var
АОВ: array [1..1000] of Byte;
……
Asm
�Оглавлен ие
mov сx, 1000
{Инициируем счетчик СХ}
lea bx, AOB
{Помещаем адрес АОВ в BX}
dec bx
{Готовим цикл}
{Здесь начало цикла проверки}
(@Test: inc bx
cmp BYTE PTR
{Адрес очередного байта}
[bx], 0
{Проверяем байт}
loopne @Test
{Замыкаем цикл}
jnz @NotZero
{Если не найден нулевой байт}
……
{Нашли нулевой байт}
end;
Строковые команды
Мне моника
Формат
Комме нтарий
Пе ре сылка строк
MOVSB
MOVSB
Пересылать байты
MOVSW
MOVSW
Пересылать слова
Сравне ние строк
CMPSB
CMPSB
Сравнивать байты
CMPSW
CMPSW
Сравнивать слова
Сканирование
SCASB
SCASB
Искать байт
SCASW
SCASW
Искать слово
Загрузка и сохране ние
LODSB
LODSB
Загружать байты
LODSH
LODSW
Загружать слова
STOSB
STOSB
Сохранять байты
STOSW
STOSW
Сохранять слова
Строковые команды рассчитаны на обработку строк. Заметим, что термин «строка» здесь отнюдь не
эквивалентен аналогичному термину Турбо Паскаля и означает произвольную цепочку байт или
слов длиной до 64 Кбайт. Эти команды оперируют пятью примитивами, каждый из которых
обрабатывает лишь один байт или одно слово за раз. Перед примитивом обычно указывается префикс
повторения REP/REPE/REPNE, заставляющий выполняться примитив до тех пор, пока не обнулится
счетчик повторений СХ или не будет нарушено соответствующее условие.
При использовании строковых команд важно помнить два обстоятельства. Во-первых, эти команды
всегда берут адрес строки-источника из пары DS:SI, а строки-приемника – из пары ES:DI. Таким
образом, перед исполнением строковой команды необходимо инициировать сегментные регистры
нужным образом. Во-вторых, строковые команды используют индексную адресацию с автоматическим
�Оглавлен ие
изменением смещения в SI/DI после однократного исполнения примитива. Содержимое этих
регистров изменяется на 1 при обработке байтов и на 2 при обработке слов, причем наращивается,
если флаг направления DF сброшен, и уменьшается, если он равен 1.
Вот как можно осуществить пересылку массива А в массив В:
Var
А, В: array [1..250] of Integer;
……
Asm
lea si, A
{Смещение А - в SI (источник)}
push ds
pop
es
lea di, B
{Инициируем ES:= DS}
{Смещение В - в DI (приемник)}
mov ex, 250
{Счетчик переноса}
Сld
{Направление переноса – наращивать}
rep movsw
{Переносим 500 байт}
end;
В программе на Турбо Паскале регистр DS всегда содержит сегмент данных, поэтому инициировать
его необязательно. Что касается регистра дополнительного сегмента ES, такого правила нет, и хотя в
большинстве случаев он также ссылается на сегмент данных, рекомендуется проводить его инициацию
перед использованием строковой команды (см. выше команды push ds, pop es).
Команды прерываний
Мне моника
Формат
Комме нтарий
INT номер
Выполнить прерывание
INTO
INTO
Выполнить прерывание по переполнению
IRET
IRET
Вернуться из прерывания
INT
Выполнение прерываний во многом напоминает косвенный вызов дальней процедуры. По команде
INT (INTO) в стек помещается регистр флагов, сегмент CS и указатель IP, а новые значения этих
регистров берутся из 4 байтного вектора прерывания, соответствующего номеру прерывания в
команде INT, или из вектора 4 – для команды INTO. Таким образом, единственным отличием от
команды CALL является то, что в стек предварительно заносится регистр флагов. Следует, правда,
оговориться: перед передачей управления программе обработки прерывания микропроцессор
сбрасывает флаги трассировки TF и прерываний IF; сброс TF необходим для обеспечения нормальной
работы отладчиков, использующих прерывание по вектору 1 или 4, сброс IF блокирует вмешательство
других процессов в ход обработки прерывания.
Команда INTO представляет собой условное прерывание и выполняется, если в этот момент взведен
флаг переполнения OF. Команда IRET реализует правильный выход из программы обработки
прерывания: она считывает из стека 3 двухбайтные слова и помещает их в регистры IP, CS и регистр
�Оглавлен ие
флагов.
Команды управления
Мне моника
Формат
Комме нтарий
Управле ние флагами
STC
STC
Установить перенос
CLC
CLC
Очистить перенос
CMC
CMC
Инвертировать CF
STD
STD
Установить направление
CLD
CLD
Очистить направление
STI
STI
Разрешить прерывания
CLI
CLI
Запретить прерывания
Вне шняя синхронизация
HLT
WAIT
ESC
LOCK
HLT
Остановить вычисления
WAIT
Ждать активности на шине
ESC код, источник
Передать команду
LOCK
Захватить шину
Пустая команда
NOP
NOP
Нет операции
Команды внешней синхронизации работают следующим образом.
HALT переводит МП в состояние останова, из которого его можно вывести только при перезагрузке
системы или при наступлении немаскируемого прерывания.
WAIT заставляет МП выполнять холостой режим работы и каждые 5 тактов проверять уровень сигнала
на входной шине: пока на этой шине нет сигнала активности, процессор выполняет WAIT, но как
только шина активизируется, он продолжит исполнение программы. Эта инструкция обычно
используется для ожидания сигнала обслуживания (прерывания) высокоприоритетного устройства
типа контроллера прямого доступа к памяти.
Команда ESC используется для передачи указанного в ней операнда на шину данных. Тем самым
обеспечивается возможность передачи команд другим процессорам. Эта команда чаще всего
используется для управления работой арифметического сопроцессора. В этом случае код представляет
собой код команды сопроцессора, а источник – используемый в этой команде операнд.
Команда LOCK фактически представляет собой однобайтовый префикс, который можно использовать
совместно с любой другой командой микропроцессора. По этой команде МП активизирует
одноименный сигнал на своей шине, что исключает возможность использования этой шины любым
другим внешним устройством (процессором).
�Оглавлен ие
СПЕЦИФИКА ВСТРОЕННОГО АССЕМБЛЕРА
Приведенное выше общее описание архитектуры МП 8086/8088 является базовым для любого
ассемблера, в том числе и для встроенного ассемблера Турбо Паскаля. Однако ассемблеры содержат
массу дополнительных возможностей, облегчающих разработку готовых к работе программ. Эти
возможности отражаются в директивах и макрокомандах ассемблера. Встроенный ассемблер не
предназначен для написания законченных программ, поэтому в нем отсутствуют макрокоманды и
директивы. Главной особенностью встроенного ассемблера является практически полное отсутствие в
нем средств описания переменных и данных, т.к. эти объекты описываются средствами Турбо
Паскаля.
Оператор ASM
Зарезервированное слово ASM открывает доступ к средствам встроенного ассемблера. Этот оператор
может располагаться только внутри исполняемой части программы (подпрограммы). Область действия
оператора ASM ограничивается ближайшим по тексту зарезервированным словом END. Таким образом,
структура любого ассемблерного оператора такова:
Asm
<Одна или несколько команд встроенного ассемблера>
end;
С точки зрения Турбо Паскаля пара asm... end считается операторными скобками,
ограничивающими единственный оператор Паскаля, например:
if X>10 then
Asm
……
end
else
……;
for
k:= 1 to 5
do
Asm
……
end;
Тело ассемблерного оператора asm... end может быть пустым или содержать несколько
ассемблерных команд. Каждая ассемблерная команда должна располагаться на отдельной строке или
отделяться от следующей за ней команды символом «;». Ниже приводятся два разных способа
написания одной и той же последовательности ассемблерных команд:
Asm
mov ah, 0; int $16; mov ChCode, al; mov ScCode, ah
end;
Asm
�Оглавлен ие
mov ah, 0
int $16
mov ChCode, al
mov ScCode, ah
end;
В конце строки, содержащей единственную ассемблерную команду, или между двумя командами,
располагающимися на одной строке, разрешается вставлять комментарий, который должен
оформляться по обычным правилам Турбо Паскаля, т.е. ограничиваться символами «{», «}» или
«(*», «*)». Таким образом, комментарии разрешены между ассемблерными командами, но не внутри
них. Например, такой оператор будет правильным:
Asm
{Инициируем регистры}
lea si, X; push ds;
pop es;
{ES:= DS}
lea di,Y; mov ex,100
сld
{Перенос - вперед}
rep
{Выполняем Y:= X}
movsw
{Здесь нет ошибки - комментарий можно вставлять между префиксом и командой}
end;
а такой – неправильным:
Asm
{Готовим регистры}
lea si, X; push ds;
pop {ES:=DS} es;
{Ошибка! Комментарий разорвал мнемонику команды и ее операнд}
lea di, Y; mov ex, 100 {и направление} cld
{Комментарий является разделителем команд, поэтому перед ним можно не ставить ";"}
rep movsw
end;
В пределах ассемблерного оператора допускаются любые команды, но Турбо Паскаль требует
выполнения следующего соглашения:
В начале ассемблерного оператора регистр DS содержит сегмент кода, SS - сегмент стека, ВР –
текущий стек, SP указывает на вершину стека. Все эти регистры должны иметь точно такие же
значения к моменту завершения работы ассемблерного оператора.
Программист не должен делать каких-либо предположений о содержимом остальных регистров, и эти
регистры могут иметь произвольное значение после завершения работы ассемблерного оператора.
Исключением является случай ассемблерной функции, которая должна использовать некоторые
�Оглавлен ие
регистры для возврата своего значения.
Синтаксис ассемблерных команд
Здесь и далее ассемблерными командами называются команды на языке встроенного ассемблера,
вставляемые в тело ассемблерного оператора asm... end.
Структура ассемблерной команды такова:
[Метка] [Префикс] [Код [Операнд [/Операнд]]]
В квадратных скобках указываются необязательные элементы структуры.
Метки
Любой команде ассемблерного оператора может предшествовать одна или несколько меток. В
ассемблере используется два типа меток: глобальные и локальные. Глобальные метки – это обычные
метки Турбо Паскаля. Они объявляются в разделе описаний после зарезервированного слова Label.
С помощью глобальной метки можно передать управление в тело ассемблерного оператора
оператором GOTO. Например:
Label
AltEnt;
Begin
Goto AltEnd;
……
{Передаем управление внутрь ассемблерного оператора}
Asm
……
AltEnd:
……
end; {Сюда можно передать управление извне}
Локальные метки объявляются непосредственно в теле ассемблерного оператора. Эти метки обязаны
начинаться символом «@». Поскольку этот символ нельзя использовать в именах Турбо Паскаля, он
позволяет отличить локальную метку от глобальной. Локальная метка не известна нигде вне
ассемблерного оператора, поэтому на нее нельзя передать управление оператором GOTO. По этой же
причине в разных ассемблерных операторах можно использовать одноименные локальные метки.
Префиксы
Встроенный ассемблер поддерживает следующие префиксы команд:
LOCK
Захват шины
REP/REPE/REPME
Повтор строковой команды
REPZ/REPNZ
Синоним REPE/REPNE
SEGCS
Перекрытие CS
SEGSS
Перекрытие DS
SEGES
Перекрытие SS
�Оглавлен ие
SEGDS
Перекрытие ES
Префиксы LOCK/REP/REPE/REPNE описаны выше. Префиксы SEGxx определяют сегментный регистр,
который должен использоваться вместо умалчиваемого, и распространяются только на следующие за
ними ассемблерные команды.
Если префикс указан без кода инструкции, он распространяет свое действие на следующую
ассемблерную команду.
Код инструкции очень редко имеет более одного префикса и никогда – более трех: допускается
следующая последовательность
LOCK SEGxx REPxx
Заметим, что если при обработке строковой команды произошло аппаратное прерывание, МП
8086/8088 «забывает» префиксы LOCK и SEGxx, которые, возможно, определены в той же команде,
так что использовать сложные префиксные конструкции не рекомендуется.
Коды инструкций
Встроенный ассемблер поддерживает мнемонику всех команд, перечисленных выше. Кроме того, в
ассемблерных командах может использоваться мнемоника инструкций процессора 8087, а также
команды процессоров 80286/80287. Заметим, что инструкции 8087 допустимы только при активном
состоянии {$Н+}, 80286 – при {$G+}, a 80287 – в случае {$G+,N+}.
Операнды
Операндами встроенного ассемблера могут быть выражения, состоящие из комбинации регистров,
констант, имен и символов операций.
Регистры
Во встроенном ассемблере используется мнемоника регистров, указанная выше, а также имя ST для
ссылки на регистры арифметического сопроцессора.
Константы
Ассемблер поддерживает строковые и числовые константы. Строковые константы заключаются в
апострофы или кавычки. Если константа объявлена с помощью кавычек, внутри нее символ апостроф
рассматривается наравне с другими символами, т.е. не считается ограничителем константы, точно так
же внутри константы, обрамленной апострофами, не считается ограничителем символ кавычки. Если
внутри константы необходимо указать ограничивающий ее символ, он удваивается. Примеры:
'Строковая константа'
"ЭТО - ТОЖЕ СТРОКОВАЯ КОНСТАНТА"
'Символ '' не считается ограничителем'
'внутри строки, обрамленной кавычками "..." '
Числовые константы могут быть только целыми и их значение не может превосходить емкости
двойного слова, т.е. должно быть внутри диапазона
-2 147 483 648
…
+4 294 967 295.
По умолчанию при записи числовых констант используется десятичная нотация, но ассемблер
поддерживает также двоичные, восьмеричные и шестнадцатеричные константы. Двоичная константа
�Оглавлен ие
составляется как комбинация единиц и нулей, заканчивающаяся символом В (от Binary – двоичный);
при записи восьмеричной константы используются символы 1...7, а в ее конце ставится символ О
(Octal – восьмеричный); шестнадцатеричная константа записывается по правилам Турбо Паскаля
(начинается с символа #) либо по правилам Турбо Ассемблера: начинается с цифры, в конце
ставится символ Н (от Hexadecimal – шестнадцатеричный).
Имена
Локальные метки – это единственные имена, которые разрешается определять внутри ассемблерного
оператора. Имена остальных объектов программы – констант, переменных, подпрограмм – должны
определяться только с помощью средств Турбо Паскаля.
Область определения имен подчиняется тем же правилам, что и в Турбо Паскале – имена должны
быть «видны» в том месте, где они используются, и они локализуются в пределах блока, в котором
описаны. Во встроенном ассемблере могут использоваться три предопределенных имени:
@Code
– текущий сегмент кода
@Data
– начальный сегмент данных
@Result
– ссылка внутри функции на ее результат
Имена @Code и @Data могут использоваться только в сочетании с директивой SEG для ссылки на
нужный сегмент. Например:
asm
mov ax, SEG @Data
mov ds, ax
end;
Имя @Result используется для присвоения результата функции. Например:
Function Min(X,Y: Integer): Integer; {Эта функция сравнивает два целых числа и возвращает
наименьшее из них}
Begin
Asm
mov ах, Х
{Помещаем Х в АХ}
cmp ax, Y
{X<Y ?}
jl @
{Да - на выход}
mov ax, Y
{Нет - помещаем Y в АХ}
@: mov @Result, ax
{AX содержит результат}
End
end;
Для доступа к полям записей разрешается использование составных имен. Например:
Type
Point = record
�Оглавлен ие
X,Y: Integer
end;
Rect = record
A, B: Point
end;
Var
P: Point;
R: Rect;
Begin
Asm
mov ax, P.X
add ax, P.Y
mov R.A.X, ax
End
End.
Идентификаторы типов можно применять к операндам для уточнения данных, о которых идет речь.
Каждая из следующих команд реализует одно и то же действие: загружает в регистр АХ слово по
адресу ES:[DI+4]:
mov ax, (Rect PTR es:[di]).B.X
mov ax, Rect (es: [di]).B.X
mov ax, es:Rect[di].B.X
mov ax, Rect[es:di].B.X
mov ax, es:[di].Rect.B.X
Следующие имена не могут использоваться в операндах встроенного ассемблера:
стандартные процедуры и функции (например, WriteLn, Chr);
предопределенные массивы Mem, MemW, MemL, Port, PortW;
константы с плавающей точкой, строковые и множественного типа;
макросы (процедуры и функции, полностью реализуемые одним InLine – оператором);
символ ©Result вне функции.
Выражения
Встроенный ассемблер использует выражения трех классов: регистровые, ссылки на память и
непосредственные.
Регистровое выражение – это выражение, состоящее из имени регистра. Все следующие команды
содержат только регистровые выражения:
�Оглавлен ие
push ds
pop es
mov ah, bl
add ex,ax
Непосредственные выражения – это нетипизированные константы и имена типов. Примеры
непосредственных выражений:
Const
dec = 10;
……
asm
mov ax, dec
mov bx, 0
add cx, 2*dec+l
sub dh,-5
end;
Все остальные выражения относятся к ссылкам на память. Например
Const
dec: Word = 10;
Step = 12;
Var
X, Y: Byte;
Asm
mov ax, dec
mov ex,[Step]
add ah, X
mov Y, bl
mov ax,[bx]
end;
Важным отличием ассемблерных выражений от выражений Турбо Паскаля является то
обстоятельство, что они должны быть статическими, т.е. разрешены (вычислены) на этапе создания
программы. Если выражение может быть полностью вычислено к моменту его трансляции, т.е. если
оно состоит только из регистровых или непосредственных значений, такое выражение называется
абсолютным, компилятор вычисляет его и использует для создания команды.
В ходе компиляции программы вырабатывается так называемый объектный код, который затем
преобразуется компоновщиком в готовую к работе программу. При создании объектного кода
�Оглавлен ие
компилятор не может вычислить значения выражений типа «ссылка на память», так как не знает
окончательного положения в памяти меток, переменных, подпрограмм. В результате он создает так
называемое перемещаемое выражение, которое затем компоновщиком преобразуется в нужную ссылку
на память.
Встроенный ассемблер разрешает любую операцию над абсолютным значением (см. ниже), но
ограничивает перемещаемые выражения до сложения или вычитания, одним из операндов которого
должна быть константа.
Другое важное отличие ассемблерных выражений от выражений Турбо Паскаля заключается в
способе интерпретации переменных. В выражениях Паскаля любая ссылка на переменную
интерпретируется как текущее содержимое этой переменной. В ассемблерных выражениях это
справедливо только тогда, когда все выражение в целом состоит из имени переменной. Во всех
остальных случаях ссылка на переменную интерпретируется как адрес переменной. Например,
выражение
Х+10
В Паскале означает: «к содержимому переменной Х прибавить 10». В ассемблерной команде это
означает: «к адресу (смещению) переменной Х прибавить 10». Однако команда
mov ах, Х
означает: «поместить в регистр АХ первые два байта переменной X». Если бы нам понадобилось
загрузить в АХ адрес переменной X, мы должны были бы написать
mov ax, OFFSET X
Заметим, что попытка «перехитрить» ассемблер командами типа
mov ах, Х+0
mov ах, Х+1-1
и т.п. не дает желаемого результата: ассемблер просто загружает в АХ содержимое переменной X.
Как и в Паскале, ассемблерные выражения имеют тип, но в отличие от Паскаля этот тип определяет
только размер объекта в памяти и не ограничивает применяемые к нему операции.
Встроенный ассемблер имеет следующие предопределенные типы:
Тип
Длина в памяти
BYTE
1
WORD
2
DWORD
4
QWORD
8
TBYTE
10
NEAR
–
FAR
–
�Оглавлен ие
Имена предопределенных типов можно использовать для приведения типов выражений. Например,
если определены переменные
Var
Flag: Boolean;
X: Word;
то такие ассемблерные выражения недопустимы:
mov Flag, bx
mov ah, X
Для корректного задания последней команды можно использовать следующие варианты:
mov ah, BYTE PTR X
mov ah, Byte(X)
mov ah, X.Byte
Во всех случаях в АН будет загружен первый (младший) байт переменной Х.
Встроенный ассемблер поддерживает операции, перечисленные в следующей таблице (в порядке
убывания приоритета).
Операции встроенного ассемблера
Операция
Комментарий
&
Перекрытие идентификатора
()
Подвыражение
[]
Ссылка на память
. (точка)
Селектор структуры
HIGH LOW
Доступ к байту в слове
+-
Унарные операции задания знака
:
Перекрытие сегмента
OFFSET SEG TYPE PTR *
/ MOD SHL SHR
+-
Бинарные операции
NOT AND OR XOR
Операции над битами
Операция &
Осуществляет перекрытие идентификатора: следующий за знаком & идентификатор считается
определенным в программе, даже если он не совпадает с зарезервированным словом. Например:
�Оглавлен ие
Var
Ch: Byte;
……
mov ch, 0
{Посылаем 0 в регистр CH}
mov &Ch, 0
{Посылаем 0 в переменную Ch}
Операция ( )
Круглые скобки используются обычным для Паскаля образом – для изменения порядка исчисления
выражения (подвыражение, ограниченное скобками, вычисляется в первую очередь). Если перед
скобками стоит имя типа, все выражение приобретает указанный тип. Например:
mov ах, ( (1+2)*3+4)*5
{АХ = 65}
mov bx,1+2*3+4*5
{ВХ = 27}
Операция [ ]
Определяет ссылку на память. Выражение внутри скобок вычисляется в первую очередь. Обычно оно
связывается с регистрами BX, BP, SI, DI и может использовать операции + и – для указания
индексации. Например:
mov ah,100 {АН = 100}
байта по адресу DS:100}
mov ah, [100]
{Загружаем в АН содержимое
Операция . (точка)
Селектор элемента структуры. Результат – сумма выражений до после точки с типом второго
выражения. Например:
Var
R: record
X: Word; Y: Byte
end;
……
mov ax, R.X
mov R.A, ai
Операции HIGH и LOW
HIGH возвращает старший, a LOW – младший байт выражения типа слова, следующего за символами
операции. Выражение должно иметь абсолютное непосредственное значение. Например:
mov al, High $1000
{AL = $10}
Операция : (двоеточие)
Указывает ассемблеру, что выражение после операции должно относиться к сегменту, указанному до
операции. Результат – ссылка на память со значением второго выражения. Например:
�Оглавлен ие
Mov ах, [10]
{AX = слово по адресу DS:10}
Mov ax, BS:[10] {АХ = слово по адресу BS:10}
Операция OFFSET
Возвращает смещение выражения, следующего за операцией. Результат имеет непосредственное
значение. Например:
mov ах, Х
{АХ = слово по адресу переменной X}
mov ax, offset Х
{АХ = смещение адреса X}
Операция SEG
Возвращает сегмент выражения, следующего за операцией. Результат имеет непосредственное
значение.
Операция PTR
Осуществляет приведение типа. Результат – ссылка на память со значением выражения после
операции и типом выражения до операции. Например:
Function SwapfX: Integer): Integer;
{Меняет местами байты в слове X}
begin
asm
mov ax, X
mov BYTE PTR @Result, ah
mov BYTE PTR @Result+l, al
end;
end;
Операции * и /
* – умножение, / – целочисленное деление. Оба выражения должны иметь непосредственные
абсолютные значения, такое же значение имеет и результат операции. Например:
mov ах, 2*2
{АХ = 4}
mov ах, 17/3
{АХ = 5}
Операция MOD
Возвращает остаток от целочисленного деления. Оба выражения должны иметь непосредственные
абсолютные значения, такое же значение имеет и результат операции. Например:
mov ax, 17 mod 3
{AX = 2}
Операции SHL и SHR
Осуществляют логический сдвиг влево (SHL) или вправо (SHR) выражения, стоящего до операции, на
количество разрядов, определяемое выражением после операции. Оба выражения должны иметь
непосредственные абсолютные значения, такое же значение имеет и результат операции. Например:
mov ah, 1 shl 7 {Ah = $80 = 128}
�Оглавлен ие
Бинарная операция +
Осуществляет сложение двух выражений. Выражения могут быть непосредственными значениями или
ссылками на память, но только одно из них может быть перемещаемым. Если одно из выражений –
ссылка на память, результат также определяет ссылку на память, а если одно из выражений –
перемещаемое, результат будет перемещаемым.
Бинарная операция –
Вычитание двух выражений. Первое выражение может быть любого класса, а второе должно быть
абсолютным непосредственным значением. Результат относится к тому же классу, что и первое
выражение.
Побитовые операции NOT, AND, OR, XOR
Имеют такой же смысл, что и одноименные операции Турбо Паскаля над целыми числами. Оба
выражения должны иметь непосредственные с абсолютные значения, такое же значение имеет и
результат операции.
Директивы ассемблера
Встроенный ассемблер не поддерживает никакие директивы, обычно используемые в других
ассемблерах, за исключением DB, DW, DD. Структура директив такова:
Dx <константа> [,<константа>,...,<константа>]
Здесь Dx – DB, DW или DD; <константа> – ассемблерная константа или константное выражение.
DB определяет цепочку байт, DW – слов, DD – двойных слов. Например:
db
'Турбо Паскаль',13,10
dw
0,$ FFFF, NearProc
dd
'ABCD',999999999, FarProc
В качестве константных выражений разрешается использовать любые ассемблерные константы со
значением, не выходящим из диапазона байта (DB), слова (DW) или двойного слова (DD). В любой
директиве можно определять строковую константу, которая приводит к побайтовому заполнению
памяти ASCII – кодами символов. Поскольку слово (двойное слово) размещается в памяти, начиная со
своего младшего байта, старший (старшие) байт в директивах DW и DD при размещении строкой
константы могжет остаться неопределенным и заполняется нулем. Например, два следующих
объявления эквивалентны:
dw
'5'
dw
$35
{$35 - ASCII-код символа '5'}
В директивах DW и DD разрешается также указывать имена, которые в этом случае интерпретируются
как адреса соответствующих объектов, причем для DW это – ближний адрес (смещение), а для DD –
дальний. Например:
dw X
{Размещает смещение переменной X}
dd Proc
{Размещает FAR-адрес процедуры Proc}
Данные, определяемые директивами Dx, всегда размещаются в текущем кодовом сегменте. Разместить
таким образом данные в сегменте данных (т.е. определить константу или типизированную константу)
�Оглавлен ие
невозможно – для этого используются стандартные средства Турбо Паскаля. Более того, директивы
не могут снабжаться именами, а поэтому использовать размещаемые с их помощью данные не так – то
просто. В следующем примере на экран выводится текстовое сообщение. Для этого используется
функция 9 вызова DOS, в соответствии с которой в регистрах DS:DX должен содержаться адрес
текстовой строки, а сама строка должна заканчиваться символом «$»:
asm
jmp @NextCode
{Обходим фрагмент данных}
@:
db 'Текстовая строка,13,10,'$'
@NextCode:
push ds
{Сохраняем DS}
push cs
pop ds
{DS = CS}
mov dx, OFFSET @
{DS:DX - адрес строки}
mov ah, 9
{АН - код функции вывода}
int 21h
{Выводим строку}
pop ds
{Восстанавливаем DS}
end;
Обратите внимание на использование регистра DS. В соответствии с требованиями функции 9, он
должен содержать сегмент выводимой строки. В нашем случае строка располагается в кодовом
сегменте, поэтому мы вынуждены сначала сохранить значение DS в стеке, а затем восстановить его.
Если бы мы этого не сделали, по завершении ассемблерного оператора регистр DS указывал бы на
сегмент кода и была бы потеряна связь программы Турбо Паскаля с глобальными переменными и
константами.
Ассемблерные подпрограммы
Ассемблерные подпрограммы – это процедуры и функции, объявленные с директивой Assembler. В
таких подпрограммах исполняемая часть не содержит begin... end и состоит из единственного
ассемблерного оператора asm... end. Например:
Function LongMul(X,Y:Integer):LongInt; Assembler;
asm
mov ax, X
imul Y
{DX/AX содержат "длинный" результат}
end;
При компиляции ассемблерных подпрограмм выполняется ряд оптимизаций кода, в том числе:
параметры-значения строкового типа, а также длиной в 1, 2 и 4 байта не копируются во временную
память, т.е. внутри подпрограммы они считаются параметрами-переменными;
�Оглавлен ие
компилятор не создает переменную @Result для результата функции, и ссылка на эту переменную
в ассемблерной функции недопустима;
исключением являются функции, возвращающие значения строкового типа, для них разрешается
использовать ссылку на @Result;
генерируются следующие команды на входе в подпрограмму и на ее выходе:
push bp
{Сохраняется ВР}
mov bp, sp
{ВР содержит текущую границу стека}
sub sp, Locals
{Резервируется часть стека для размещения локальных переменных}
……
mov sp, bp
{Восстанавливается граница стека}
pop bp
{Восстанавливается ВР}
ret Params
{Из стека удаляются параметры подпрограммы и осуществляется выход из нее}
Здесь Locals – общая длина в байтах всех объявленных в подпрограмме локальных переменных, а
Params – длина (в байтах) всех формальных параметров. Если Locals и Params равны нулю,
входной код не создается, а выходной содержит единственную инструкцию RET.
Все локальные переменные Турбо Паскаль размещает в стеке. Это относится как к обычным, так и к
ассемблерным подпрограммам. Для ссылки на локальные переменные используется адресация по базе,
задаваемой парой DS:ВР, поэтому при входе в процедуру всегда создается так называемый локальный
стек: в регистр ВР помещается текущая граница стека, а сама эта граница смещается вверх на
суммарную длину всех локальных переменных, чтобы работа со стеком внутри подпрограммы не
разрушила локальные переменные. Например:
Procedure ....; Assembler;
var
X: Word;
Y: Byte;
asm
mov X, ax
{Компилируется в mov [BP-2], ax}
mov ah,Y
{Компилируется в mov ah,[BP-3]}
end;
Ассемблерные функции должны следующим образом возвращать результат своей работы:
длиной 1 байт (Byte, Char и т.п.) – в регистре AL;
длиной 2 байта (Integer, Word) – в регистре АХ;
длиной 4 байта (Pointer, Longint) – в регистрах DX (старшее слово) и АХ (младшее слово);
типа Real – в регистрах DX, BX, АХ (старшее слово – в DX, младшее в АХ);
вещественных типов Single, Double, Extended, Comp – в регистре ST(0) сопроцессора;
�Оглавлен ие
строкового типа – во временной области памяти, на которую ссылается @Result.
Использование языка ассемблера в программах на Turbo Pascal 7.0
Turbo Pascal позволяет писать отдельные части программы (подпрограммы или части
подпрограмм) на языке ассемблера. Здесь возможны четыре варианта.
Во-первых, можно написать подпрограмму на языке ассемблера, скомпилировать ее отдельно
компилятором TASM (Turbo Assembler) с получением объектного файла, а затем скомпоновать его
с основной программой, написанной на Turbo Pascal, используя при этом директиву компилятора
{$L <имя файла>}, где <имя файла> – имя файла с подпрограммой на ассемблере, и директиву
external.
Во-вторых, используя встроенный ассемблер пакета Turbo Pascal, отдельные части текста
программы можно написать непосредственно на языке ассемблера, заключив их в операторные
скобки asm...end.
В-третьих, ту или иную подпрограмму (процедуру или функцию) можно полностью, за исключением
заголовка, написать на языке ассемблера, используя при этом директиву assembler. В этом случае
также используется встроенный ассемблер.
В-четвертых, небольшую подпрограмму можно написать непосредственно в кодах процессора,
используя оператор или директиву inline.
При написании отдельных частей программы на языке ассемблера следует иметь в виду, что
необходимо сохранить содержимое регистров ВР, SP, SS и DS. Если их необходимо изменить, то
исходные значения следует запомнить, а затем восстановить. Остальные регистры можно
безболезненно изменять.
Основным вопросом стыковки программы с подпрограммой, написанной на ассемблере, является
передача параметров в подпрограмму и обратно. Именно этому вопросу и будет здесь уделено
основное внимание.
Ниже будут рассмотрены особенности использования этих вариантов. В качестве примера их
использования будут приведены различные варианты подпрограммы-функции, определяющей
максимальный элемент из массива целых чисел.
Использование компилятора TASM
Как правило, этот вариант применяется, когда та или иная программа имеет большой размер и ее
целесообразно и написать, и скомпилировать отдельно, используя компилятор TASM. В этом случае
можно использовать все возможности языка и компилятора TASM.
Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из
массива целых чисел и написанную на языке ассемблера.
Основная программа, использующая подпрограмму, написанную на языке ассемблера, содержит
инициализированный массив, в котором будет определяться максимальное число, а сама программа
выводит на экран значение максимального числа из этого массива:
Program EXAMPLE1;
Const N=7;
{Размер массива}
Massiv: Array [1… n] of Integer = (1, 2, 3, 2, 17, 7, 2);
{Исходный массив}
�Оглавлен ие
{$L SUBR}
{Подключение
SUBR.OBJ}
файла
Function Max (var Mas; N: Integer): Integer; External;
Begin
WriteLn('Максимальное число массива равно: ', Max(Massiv, N));
ReadLn
End.
Используя стандартную модель памяти, подпрограмму, определяющую максимальное число из
массива, можно написать следующим образом:
CODE
SEGMENT
BYTE
ASSUME
CS:CODE
PUBLIC
Max
AdrMas
EQU
DWORD
PTR[BP+ ;адрес первого параметра
6]
N
EQU
WORD
PTR[BP+ ;второй параметр
4]
PROC
NEAR
Max
M1:
PUBLIC
;внешний идентификатор
PUSH
ВР
;сохранение регистра ВР
MOV
BP, SP
;указатель стека
LDS
SI, AdrMas
;адрес массива
XOR
AX, AX
;0 - в регистр АХ
MOV
BX, 8001h
;минимальное целое число
MOV
CX, N
;число элементов массива
CMP
CX, AX
;сравнение с 0
JLE
M3
;0 или отрицательное число
LODSW
;загрузка элемента массива
CMP
AX, BX
;сравнение с текущим максимумом
JLE
M2
;не больше
MOV
BX, AX
;новое максимальное число
M2:
LOOP
M1
;цикл
M3:
MOV
AX, BX
;результат функции
POP
ВР
;восстановление регистра
RET
6
;возврат из подпрограммы
ВР
Max
ENDP
�Оглавлен ие
CODE
ENDS
END
По приведенной подпрограмме следует сделать следующие замечания.
Первые две команды – сохранение регистра ВР и загрузка в него указателя стека – являются
типичными командами, с помощью которых можно установить доступ к передаваемым параметрам
через регистр ВР.
Параметры передаются в подпрограмму следующим образом. Параметры-значения размером в один
байт передаются одним 16-разрядным словом, причем информативным является младший байт,
параметры-значения в 2 байта передаются одним 16-разрядным словом, в 4 байта – двумя
16-разрядными словами, параметры-значения типа Real передаются тремя 16-разрядными словами,
все остальные параметры-значения (в том числе и 3-байтовые) передаются своими полными
адресами. Из этого правила есть некоторые исключения: параметры-переменные и
параметры-константы всегда передаются своими полными адресами.
Т.к. в подпрограмме первый параметр является параметром-переменной, то он передается своим
адресом, с помощью которого в дальнейшем и извлекаются элементы массива. Второй параметр
подпрограммы – параметр-значение, и он передается своим значением. Первый параметр находится
по адресу ВР+6, а второй – ВР+4. Указанные смещения определяются наличием в стеке адреса
возврата (при ближней адресации - 2 байта), размещенным в стеке значением регистра ВР (2 байта) и
для первого параметра - размером второго параметра (2 байта).
Если подпрограмма является подпрограммой-функцией, то возвращаемый параметр передается
различным образом в зависимости от своего размера. Параметр размером в байт передается в регистре
AL, параметр размером в 2 байта - в регистре АХ, параметр размером в 4 байта - в регистрах DX
(старшая часть или адрес сегмента) и АХ (младшая часть или смещение), параметры размером в 6
байтов (типа Real) - в регистрах DX (старшая часть), ВХ (средняя часть) и АХ (младшая часть).
Параметры других вещественных типов передаются в нулевом элементе стека сопроцессора ST(0).
Если функция возвращает значение типа string, то при обращении к функции резервируется память
для размещения возвращаемой строки, а адрес этой области размещается в стеке выше всех
передаваемых параметров.
В рассматриваемом примере возвращаемый параметр – типа Integer, и он возвращается в регистре
АХ.
При возвращении из подпрограммы в команде RET записан аргумент 6 для удаления из стека
передаваемых параметров, которые в данном примере имеют именно этот размер.
Turbo Assembler предполагает и другое оформление подпрограмм, используемых затем в
программах, написанных на языке Паскаль. Для этого используется специальная модель памяти
Large (большая), задаваемая в виде:
.MODEL Large, PASCAL.
Она позволяет несколько упростить оформление входа в подпрограмму и выхода из нее.
Подпрограмма дополняется необходимыми командами на этапе компиляции.
Пример. Вариант предыдущей подпрограммы, использующий специальную модель памяти.
.MODEL
.CODE
LARGE, PASCAL
;специальная модель памяти
�MAX
@@1
PUBLIC
MAX
PROC
LDS
SI, MAS
;адрес массива
XOR
AX, AX
;0 - в регистр АХ
MOV
BX,8001H
;минимальное целое число
MOV
CX, N
;число элементов массива
CMP
CX, AX
;сравнение с 0
JLE
@@3
;0 или отрицательное число
LODSW
;внешний идентификатор
NEAR mas:DWORD, N:WORD
;загрузка элементов массива
CMP
AX, BX
;сравнение с текущим максимумом
JLE
@@2
;не больше
MOV
BX, AX
;новое максимальное число
@@2
LOOP
@@1
;цикл
@@3
MOV
AX, BX
;результат функции
RET
MAX
Оглавлен ие
;возврат из подпрограммы
ENDP
END
В этом примере не сохраняется и не восстанавливается регистр ВР – эти операции добавляются к
программе на этапе компиляции. Не указывается также и размер передаваемых параметров – они при
выходе из подпрограммы удаляются автоматически. В строке, где начинается описание подпрограммы
(начинается с имени подпрограммы – Мах), необходимо перечислить все передаваемые параметры в
том же порядке, как они заданы в заголовке, написанном на языке Паскаль с указанием их размеров (о
размерах передаваемых параметров см. выше).
Здесь показана также возможность использования в подпрограммах локальных меток, начинающихся
символами @@.
В подпрограмме, написанной на языке ассемблера, можно использовать подпрограммы, написанные
на языке Паскаль. Несколько модифицированная подпрограмма определения максимального элемента
массива, которая в случае недопустимого числа элементов массива (0 или отрицательное число)
вызывает подпрограмму, написанную на языке Паскаль для выдачи сообщения, приведена в
следующем примере.
Пример. Модифицированный вариант программы, в котором подпрограмма, написанная на языке
ассемблера, в случае недопустимого числа элементов массива (равно 0 или отрицательное) вызывает
подпрограмму, написанную на языке Паскаль, выводящую соответствующее сообщение.
Основная программа, содержащая подпрограмму на языке Паскаль, будет иметь следующий вид:
Program EXAMPLE2;
Сonst N = 7;
{Размер массива}
Massiv: array [1..n] of Integer = (1, 2, 3, 2, 17, 7, 2);
�Оглавлен ие
{Исходный массив}
($L SUBR)
{Подключение файла SUBR.OBJ}
Function Max (var Mas; N: Integer): Integer; External;
Procedure ErrorReport (N: Integer);
begin
WriteLn;
WriteLn('Недопустимое число элементов: ', N);
ReadLn
end;
begin
WriteLn('Максимальное число массива равно: ', Max(Massiv, N));
ReadLn
end.
Подпрограмма, написанная на языке ассемблера, будет в этом случае иметь следующий вид:
.MODEL
Large, PASCAL
;специальная модель памяти
EXTRN
ErrorReport: Near
;внешняя подпрограмма
PUBLIC
Max
;внешний идентификатор
.CODE
Max
PROC NEAR Mas: DWORD, N: Word
;передаваемые параметры
LDS
SI, Mas
;адрес массива
XOR
AX, AX
;0 - в регистр AX
MOV
BX, 8001h
;минимальное целое число
MOV
CX, N
;число элементов массива
CMP
CX, AX
;сравнение с 0
JG
@@1
;допустимое число
PUSH
BX
;сохранение регистра BX
PUSH
CX
;передаваемый параметр
CALL
ErrorReport
;обращение к подпрограмме
POP
BX
;восстановление регистра BX
JMP
@@3
;на завершение
@@1: LODSW
;загрузка элемента массива
�Оглавлен ие
CMP
AX, BX
;сравнение с текущим максимумом
JLE
@@2
;не больше
MOV
BX, AX
;новое максимальное число
@@2: LOOP
@@1
;цикл
@@3: MOV
AX, BX
;результат функции
RET
Max
;возврат из подпрограммы
ENDP
END
Перед обращением к подпрограмме, написанной на языке Паскаль, в стек в соответствующем порядке
следует поместить передаваемые параметры. В данном случае такой параметр один - число элементов
массива.
Т.к. подпрограмма, написанная на языке Паскаль, не гарантирует сохранение регистров AX, BX, CX
и DX, то в случае необходимости сохранения их значений следует перед обращением к подпрограмме,
написанной на языке Паскаль, сохранить в стеке значения соответствующих регистров, а после
возвращения из подпрограммы - восстановить их. В данном примере сохраняется содержимое
регистра BX, в котором записано минимальное целое число.
При написании программ, содержащих отдельные части, написанные на языках ассемблера и
Паскаль, следует обращать внимание на способ адресации (дальний – far или ближний – near).
Здесь существует следующее правило: если подпрограмма объявляется в интерфейсной части
какого-либо модуля, то она должна иметь дальнюю адресацию, в других случаях (подпрограмма
объявляется в файле, содержащем основную программу, или в исполнительной части модуля) следует
использовать ближнюю адресацию.
И еще одно замечание: внешнюю подпрограмму нельзя объявлять внутри другой подпрограммы.
Использование встроенного ассемблера
Начиная с версии 6.0 Turbo Pascal содержит встроенный ассемблер, позволяющий писать
отдельные части программ на языке ассемблера. Встроенный ассемблер обладает многими
возможностями языка Turbo Assembler, но приспособлен к использованию в программах,
написанных на языке Паскаль (позволяет использовать идентификаторы программы, написанные на
языке Паскаль, комментарии, имеющие такой же вид, как в языке Паскаль, позволяет
воспользоваться встроенным отладчиком для пошагового выполнения программы, контроля
содержимого регистров и параметров программы и т.д.).
Так же как и Turbo Аssembler, встроенный ассемблер предполагает использование ряда
предопределенных стандартных идентификаторов, имеющих специальное назначение. Если в
программе будет введен идентификатор с таким же именем, но имеющий другое назначение, в частях
программы, написанных на встроенном ассемблере, будет отдано предпочтение стандартному
назначению этого идентификатора. Перечень стандартных идентификаторов встроенного ассемблера
приведен в приложении В.
Наряду с возможностью использования идентификаторов языка Паскаль встроенный ассемблер
использует три дополнительных идентификатора:
@Code – текущий кодовый сегмент (используется только с оператором SEG);
�Оглавлен ие
@Data – текущий сегмент данных (используется только с оператором SEG);
@Result – результат, полученный функцией (можно использовать только внутри функции).
Со встроенным ассемблером нельзя использовать:
стандартные процедуры и функции;
специальные массивы Men, MemW, MemL, Port и PortW;
константы типа string, вещественных типов и типа-множества;
процедуры и функции, объявленные с директивой inline;
метки, объявленные не в данном блоке.
Часть программы, написанная на языке ассемблера, помещается в операторные скобки asm...end.
В следующем примере приведена программа, выполняющая те же функции, что и предыдущие
программы, но использующая встроенный ассемблер.
Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из
массива целых чисел и написанную на языке ассемблера, но использующую встроенный ассемблер.
Program EXAMPLE3;
const N=7;
{Размер массива}
Massiv: array [1…n] of Integer = (1, 2, 3, 2, 17, 7, 2);{Исходный массив}
Function Max(var Mas; N:Integer):Integer;
begin
asm
LDS
SI, Mas
{адрес массива}
XOR
AХ, АХ
{(0 - в регистр AX}
MOV
BX, 8001h
{минимальное целое число}
MOV
СХ, N
{число элементов массива}
СMР
СХ, АХ
{сравнение с 0}
JLE
@@3
{0 или отрицательное число}
@@1: LODSW
{загрузка элемента массива}
СМР
АХ, ВХ
{сравнение с текущим максимумом}
JLE
@@2
{не больше}
MOV
ВХ, АХ
{новое максимальное число}
@@2: LOOP
@@1
{цикл}
@@3: MOV
@Result, ВХ
{результат функции}
еnd
�Оглавлен ие
end;
begin
WriteLn('Максимальное число массива равно: ', Max(Massiv, N));
ReadLn
end.
Следует заметить, что при использовании встроенного ассемблера комментарии пишутся таким же
образом, как и в языке Паскаль (в фигурных скобках). Назначение же точки с запятой несколько другое
– этим знаком отделяются друг от друга команды, написанные на одной строке (такая возможность при
использовании встроенного ассемблера существует), например:
LDS
SI, Mas;
XOR
AX, AX;
MOV
BX, 8001h
Как видно из примера, можно использовать идентификаторы, объявленные на языке Паскаль
(параметры Mas, N). Нет необходимости сохранять и восстанавливать регистр ВР, удалять из стека
передаваемые параметры, включая и локальные, и т. д.
Использование директивы ASSEMBLER
Если ту или иную подпрограмму нужно полностью написать на языке ассемблера, используя
встроенный ассемблер, можно вместо операторных скобок asm...end использовать директиву
assembler, которая имеет ряд особенностей.
Во-первых, все передаваемые параметры, размером отличные от 1, 2 или 4 байт, передаются всегда
своим адресом без создания копии в стеке.
Во-вторых, нельзя использовать для передачи результата функции переменную @Result. Результат
передается точно так же, как и при использовании TASM. Исключение составляет результат типа string.
В этом случае в переменной @Result находится адрес строки, в которую следует поместить
полученную информацию.
В-третьих, для процедур и функций, не имеющих формальных и локальных параметров, вообще не
выделяется область стека.
В-четвертых, так же как и в предыдущем случае, автоматически оформляется начало и конец
подпрограммы, связанные с сохранением регистра ВР и освобождением стека от передаваемых
параметров.
Ниже приведен пример использования такой директивы.
Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из
массива целых чисел и написанную на языке ассемблера, но использующую встроенный ассемблер и
директиву assembler.
Program EXAMPLE4;
const N=7;
{Размер массива}
Massiv: array [1…n] of Integer = (1, 2, 3, 2, 17, 7, 2);
массив}
Function Max(var Mas; N:Integer):Integer; Assembler;
asm
{Исходный
�Оглавлен ие
LDS
SI, Mas
{адрес массива}
XOR
AХ, AX
{(0 - в регистр AX}
MOV
BX, 8001h
{минимальное целое число}
MOV
СХ, N
{число элементов массива}
СMР
СХ, АХ
{сравнение с 0}
JLE
@@3
{0 или отрицательное число}
@@1: LODSW
{загрузка элемента массива)
СМР
АХ, ВХ
{сравнение с текущим максимумом}
JLE
@@2
{не больше}
MOV
ВХ, АХ
{новое максимальное число}
@@2: LOOP
@@1
{цикл}
@@3: MOV
@Result, ВХ
{результат функции}
end;
begin
WriteLn('Максимальное число массива равно: ', Max(Massiv, N));
ReadLn
end.
Использование оператора или директивы INLINE
Для коротких подпрограмм (до десятка операторов) можно использовать непосредственное задание
всей подпрограммы или ее части в кодах процессора, используя оператор или директиву inline.
Отличие оператора от директивы заключается в том, что оператор может быть использован в
подпрограмме совместно с другими операторами, написанными на языках Паскаль или ассемблера, а
директива предполагает, что подпрограмма целиком состоит лишь из нее одной.
Само написание оператора или использование директивы inline практически ничем не отличается
друг от друга. Каждый из них начинается с зарезервированного слова inline, за которым в круглых
скобках через прямой слэш (/) записываются байты или слова кодов команд. При этом каждый
элемент будет либо байтом, либо словом в зависимости от фактического значения (байт, если значение
в пределах 0..255, слово – в остальных случаях). Этот стандартный размер можно изменить, используя
указатель размера <или>. Если используется указатель размера <, информация размещается в одном
байте, причем, если ее размер больше одного байта, используется только младший байт. Указатель
размера > всегда размещает информацию в одном 16-разрядном слове (см. пример ниже). В качестве
элементов оператора или директивы inline можно использовать идентификаторы языка Паскаль (в
директиве нельзя только использовать идентификаторы передаваемых в подпрограмму параметров).
Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из
массива целых чисел, написанную на языке ассемблера и использующую оператор inline.
Program EXAMPLE5;
const
N=7;
{Размер массива}
�Оглавлен ие
Massiv: array [1…n] of Integer = (1, 2, 3, 2, 17, 7, 2);
{Исходный массив}
Function Max(var Mas; N:Integer):Integer;
Begin
inline(
$C5/$76/6/
{LDS SI, Mas}
$B8/>$0/
{MOV AX, 0}
$BB/$8001/
{MOV ВХ, 8001h}
$8B/$4E/4/
{MOV CX, N}
$3B/$C8/
{CMP CX, AX}
$7E/$09/
{JLE @@3}
$AD/
{@@1:
$3B/$C3/
{CMP AX, BX}
$7E/$02/
{JLE @@2}
$8B/$D8/
{MOV BX, AX}
$E2/$F7);
{@@2: LOOP@@1}
LODSW}
{@@3: MOV AX, BX}
asm
MOV AX, BX
end
end;
Begin
WriteLn('Максимальное число массива равно: ',
Max(Massiv, N));
ReadLn
End.
Несколько иначе используется директива inline. При использовании этой директивы подпрограмма
представляет собой макроопределение ассемблера, и при обращении к ней ее коды помещаются в
место обращения. В этом случае не формируются команды обращения к подпрограмме и выхода из нее.
Если подпрограмме передаются параметры, они, как обычно, передаются через стек, из которого их
можно взять. Такой вариант используется для очень коротких подпрограмм и дает наиболее
эффективный результат. В качестве примера рассмотрим все ту же задачу поиска в массиве
максимального числа, хотя используемая здесь подпрограмма и несколько великовата для данного
варианта.
Пример. Программа, использующая подпрограмму-функцию, определяющую максимальный элемент из
массива целых чисел, написанную на языке ассемблера и использующую директиву inline.
Program EXAMPLE6;
�Оглавлен ие
const
N=7;
{Размер массива}
Massiv: array [1…n] of Integer = (1, 2, 3, 2, 17, 7, 2);
{Исходный массив}
Function Max(var Mas; N:Integer):Integer;
Inline(
$59/
{POP CX
число элементов}
$5E/
{POP SI
смещение массива}
$1F/
{POP DS адрес сегмента}
$33/$C0/
{XOR AX, AX}
$BB/$8001/
{MOV BX, 8001h}
$3B/$C8/
{CMP CX, AX}
$7E/$09/
{JLE @@3
$AD/
{@@1: LODW}
$3B/$C3/
{CMP AX, BX}
$7E/$02/
{JLE @@2}
$8B/$D8/
{MOV BX, AX}
$E2/$F7);
{@@2: LOOP@@1}
$8B/$C3);
Begin
WriteLn('Максимальное
ReadLn
end.
число массива равно: ',
Max(Massiv, N));
�Оглавлен ие
Сообщения и коды ошибок
СООБЩЕНИЯ ОБ ОШИБКАХ ПЕРИОДА КОМПИЛЯЦИИ
Среда Турбо Паскаля дает исчерпывающую информацию о характере и месте обнаруженной
компилятором ошибки. При обнаружении ошибки среда автоматически загружает в окно редактора
исходный файл и помещает курсор около того места, где в исходном тексте обнаружена ошибка. При
этом в верхней строке редактора появляется диагностическое сообщение. После нажатия на любую
клавишу (кроме F1) верхняя строка восстанавливает свой первоначальный вид и среда переходит к
режиму редактирования; Если после появления сообщения об ошибке нажать F1, на экране появится
окно справочной службы с детальной информацией об ошибке и рекомендациями по ее устранению.
Некоторые ошибки в исходном тексте обнаруживаются не сразу, а в ходе продолжающегося
контекстного разбора. Например, несоответствие типов в операторе присваивания не может быть
обнаружено до тех пор, пока не будет вычислено целиком выражение в правой части этого оператора.
В таких случаях ищите ошибку слева от курсора или в предыдущей строке текста.
Ниже приводятся сообщения об ошибках в том виде, в каком они появляются в верхней строке
редактора, а также перевод сообщений справочной службы.
1 Out of memory (Выход за границы памяти).
Компилятору не хватает памяти. Имеется ряд возможных решений этой проблемы:
• если в опции COMPILE/DESTINATION установлено значение MEMORY, замените эту опцию на
DISK;
• если в опции OPTIONS/UNKER/LINK BUFFER установлено значение MEMORY, замените эту
опцию на DISK;
• если Вы используете резидентные обслуживающие программы, такие как SIDEKICK, NORTON,
удалите их из памяти;
• если Вы используете интегрированную среду TURBO.EXE, то попробуйте воспользоваться
компилятором ТРС.ЕХЕ – он занимает меньше памяти.
Если ни одна из рекомендаций не помогает, то, возможно, Ваша программа просто слишком велика,
чтобы компилировать ее в таком объеме памяти. В этом случае Вы должны разбить ее на два или
более модулей.
2 Identifier expected (Не указан идентификатор).
В этом месте должен находиться идентификатор. Возможно, Вы пытаетесь использовать в качестве
идентификатора зарезервированное слово.
3 Unknown identifier (Неизвестный идентификатор).
Этот идентификатор не был описан.
4 Duplicate identifier (Двойной идентификатор).
Попытка дважды описать один и тот же идентификатор.
5 Syntax error (Синтаксическая ошибка).
В исходном тексте найден недопустимый символ. Возможно, Вы забыли заключить в апострофы
строковую константу.
6 Error in real constant (Ошибка в вещественной константе).
7 Error in integer constant (Ошибка в целой константе).
Учтите, что после целых действительных чисел, превышающих диапазон представления целых чисел
�Оглавлен ие
(–2147483648..+2147483647), должны ставиться точка и ноль, например, 12345678912.0.
8 String constant exceeds line (Строковая константа превышает допустимые размеры).
Вероятно, Вы забыли поставить апостроф в конце строковой константы.
9 Too many nested files (Слишком много вложенных файлов).
Компилятор допускает не более пяти уровней вложенности включаемых файлов (т.е. в исходном
файле есть ссылка на включаемый файл, в котором есть ссылка на еще один включаемый файл и т.д.).
10 Unexpected end of file (He найден конец файла).
Вы могли получить это сообщение об ошибке по одной из следующих причин:
• Ваш исходный файл закончился перед последним END основного раздела операторов;
• вероятно, в Вашей программе неодинаковое количество операторов BEGIN и END;
• включаемый файл заканчивается в середине раздела операторов; каждый раздел операторов должен
целиком помещаться в одном файле;
• Вы не закончили комментарий.
11 Line too long (Слишком длинная строка).
Максимальная длина строки, обрабатываемой компилятором, равна 126 символам (обратите
внимание: редактор среды может обрабатывать строки практически неограниченной длины).
12 Type identifier expected (Здесь нужен идентификатор типа).
Не указан тип идентификатора.
13 Too many open files (Слишком много открытых файлов).
Появление этой ошибки означает, что конфигурационный файл CONFIG.SYS операционной системы
не включает параметр FILES=xx или этот параметр указывает слишком мало файлов. Увеличьте число
файлов до нужного значения, например, до 80.
14 Invalid file name (Неверное имя файла).
Имя файла неверно или указан несуществующий путь.
15 File not found (Файл не найден).
Файл не был найден в просмотренных каталогах.
16 Disk full (Диск заполнен).
Удалите некоторые файлы или воспользуйтесь новым диском.
17 Invalid compiler directive (Неправильная директива компилятора).
Неверная буква в директиве компилятора, один из параметров директивы компилятора неверный, или
Вы пользуетесь глобальной директивой компилятора, когда компиляция тела программы уже началась.
18 Too many files (Слишком много файлов).
В компиляции программы или программного модуля участвуют слишком много файлов. Попытайтесь
не использовать так много файлов, например, объединяя включаемые файлы или делая короче имена
файлов.
19 Undefined type in pointer definition (Неопределенный тип в объявлении указателя).
Попытка объявить типизированный указатель, связанный с ранее не объявленным типом данных.
20 Variable identifier expected (Отсутствует идентификатор переменной).
На этом месте должен быть идентификатор переменной.
21 Error in type (Ошибка в объявлении типа).
�Оглавлен ие
Объявление типа не может начинаться с этого символа.
22 Structure too large (Слишком большая структура).
Максимально допустимый размер любого структурного типа составляет 65520 байт.
23 Set base type of range (Базовый тип множества нарушает границы).
Базовый тип множества должен представлять собой тип–диапазон с границами в пределах от 0 до 255
или перечисляемый тип с не более чем 256 значениями.
24 File components may not be files (Компонентами файла не могут быть файлы) .
Конструкции типа file of file (файл файлов) или file of object (файл объектов) не допускаются. Нельзя
объявлять любые структурные типы, которые используют в качестве компонентов объекты или файлы.
25 Invalid string length (Неверная длина строки).
Объявляемая длина строки должна находиться в диапазоне от 1 до 255.
26 Type mismatch (Несоответствие типов).
Это сообщение может быть вызвано следующими причинами:
• несовместимые типы переменной и выражения в операторе присваивания;
• несовместимые типы фактического и формального параметров в обращении к процедуре или
функции;
• тип выражения не совместим с типом индекса при индексировании массива;
• несовместимые типы операндов в выражении.
27 Invalid subrange base type (Неправильный базовый тип для типа-диапазона) .
Допустимыми базовыми типами являются все порядковые типы.
28 Lower bound greater than upper bound (Нижняя граница больше верхней).
Описание типа–диапазона содержит неправильные границы.
29 Ordinal type expected (Нужен порядковый тип).
Вещественные, строковые, структурные, процедурные типы и указатели в данном месте программы не
допускаются.
30 Integer constant expected (Нужна целая константа).
31 Constant expected (Нужна константа).
32 Integer or real constant expected (Нужна целая или вещественная константа) .
33 Type identifier expected (Нужен идентификатор типа).
34 Invalid function result type (Неправильный тип результата функции).
Правильными типами результата функции являются все простые типы, строковые типы и указатели.
35 Label identifier expected (Нужен идентификатор метки).
Метка не обозначена с помощью идентификатора, как это требуется из контекста программы.
36 BEGIN expected (Нужен BEGIN).
37 END expected (Нужен END).
38 Integer expression expected (Нужно выражение типа INTEGER).
39 Ordinal expression expected (Нужно выражение перечисляемого типа).
40 Boolean expression expected (Нужно выражение типа BOOLEAN).
41 Operand types do not match operator (Типы операндов не соответствуют операции).
�Оглавлен ие
Данная операция не может быть применена к указанным операндам, например, 'A' div '2' .
42 Error in expression (Ошибка в выражении).
Данный символ не может участвовать в выражении указанным образом. Возможно, Вы забыли указать
операцию между двумя операндами.
43 Illegal assignment (Неверное присваивание).
Файлам и нетипизированным переменным нельзя присваивать значения. Идентификатору функции
можно присвоить значение только внутри раздела операторов данной функции.
44 Field identifier expected (Нужен идентификатор поля).
Попытка использовать запись целиком в том месте, где требуется ссылка на какое-либо поле записи.
45 Object file too large (Объектный файл слишком большой).
Турбо Паскаль не может компоновать файлы *.OBJ больше 64 Кбайт.
46 Undefined external (Неопределенная внешняя процедура).
Внешняя процедура или функция не имеет соответствующего определения PUBLIC в объектном файле.
Убедитесь, что Вы указали все объектные файлы в директивах {$L <имя .OBJ– файла>} и проверьте
написание идентификаторов процедуры или функции в файле *.ASM.
47 Invalid object file record (Неправильная запись объектного файла).
Файл .OBJ содержит неверную объектную запись. Убедитесь, что данный файл является
действительно файлом *.OBJ.
48 Code segment too large (Сегмент кода слишком большой).
Максимальный размер кода программы или программного модуля равняется 65520 байтам. Разбейте
Вашу программу или модуль на два или более модулей.
49 Data segment too large (Сегмент данных слишком велик).
Максимальный размер сегмента данных программы равен 65520 байтам, включая данные,
используемые программными модулями. Если Вам нужно большее количество глобальных данных,
опишите большие структуры с помощью указателей и выделяйте для них память динамически с
помощью процедуры NEW.
50 DO expected (Нужен оператор DO).
51 Invalid PUBLIC definition (Неверное PUBLIC-определение).
Возможные причины сообщения:
• данный идентификатор получил тип PUBLIC с помощью соответствующей директивы языка
ассемблера, но не соответствует описанию EXTERNAL в программе или программном модуле
Паскаля;
• две или более директивы PUBLIC языка ассемблера определяют один и тот же идентификатор;
• файлы *.OBJ определяют символы PUBLIC, не находящиеся в сегменте CODE.
52 Invalid EXTRN definition (Неправильное EXTRN-определение).
Возможные причины сообщения:
• программа на ассемблере ссылается с помощью директивы EXTRN на идентификатор, который не
описан в программе на Паскале и не был описан в интерфейсных секциях используемых программных
модулей;
• ассемблерная программа ссылается на идентификатор, обозначающий абсолютную переменную (т.е.
определенную словом ABSOLUTE);
�Оглавлен ие
• ассемблерная программа ссылается на идентификатор процедуры или функции типа INLINE.
53 Too many EXTRN definition (Слишком много EXTRN–определений). Турбо Паскаль не может
обрабатывать файлы *.OBJ при более чем 256 определениях EXTRN.
54 OF expected (Требуется OF).
55 INTERFACE expected (Требуется интерфейсная секция).
56 Invalid relocatable reference (Неправильная перемещаемая ссылка).
Возможные причины сообщения.
• файл *.OBJ содержит данные и перемещаемые ссылки в сегментах, отличных от CODE. Например,
Вы пытаетесь описать инициализированные переменные в сегменте DATA;
• файл *.OBJ содержит ссылки с размерами в байтах на перемещаемые символы. Такая ошибка
происходит в случае, если Вы используете операторы HIGH и LOW с перемещаемыми символами или
если Вы ссылаетесь в директивах DB на перемещаемые символы;
• операнд ссылается на перемещаемый символ, который не был определен в сегменте CODE или в
сегменте DATA;
• операнд ссылается на процедуру EXTRN или функцию EXTRN со сдвигом, например, CALL
SortProc+8.
57 THEN expected (Требуется THEN).
58 TO or DOWNTO expected (Требуется ТО или DOWNTO).
59 Undefined forward (Неопределенное опережающее описание).
Возможные причины сообщения:
• была описана процедура или функция в интерфейсной секции программного модуля, но ее
определение отсутствует в секции реализации;
• процедуры или функции были описаны с помощью опережающего описания, но их определение не
найдено.
60 Too many procedures (Слишком много процедур).
Турбо Паскаль допускает не более 512 процедур или функций в одном модуле. Если Вы компилируете
программу, то поместите некоторые процедуры или функции в модули. Если Вы компилируете модуль,
то разбейте его на два или несколько модулей.
61 Invalid typecast (Неверное преобразование типа).
Возможные причины сообщения:
• Вы пытаетесь разместить в памяти, занимаемой некоторой переменной, значение выражения другого
типа в случае, когда размер размещаемого значения не равен размеру переменной;
• Вы пытаетесь осуществить преобразование типа выражения, когда разрешается только ссылка на
переменную; процедуру или функцию.
62 Division by zero (Деление на ноль).
Предшествующая операция пытается выполнить деление на ноль.
63 Invalid file type (Неверный файловый тип).
Данный файловый тип не обслуживается процедурой обработки файлов. Например, процедура
READLN используется для типизированного файла или процедура SEEK – для текстового файла.
64 Cannot Read or Write variables of this type (Нет возможности считать или записать переменные
данного типа).
�Оглавлен ие
Нарушены следующие ограничения:
• процедуры READ и READLN могут считывать переменные символьного, целого, действительного и
строкового типов;
• процедуры WRITE и WRITELN могут выводить переменные символьного, целого, действительного,
булевского и строкового типов.
65 Pointer variable expected (Нужно использовать переменную-указатель).
Предыдущая переменная должна быть указателем.
66 String variable expected (Нужна строковая переменная).
Предшествующая переменная должна иметь строковый тип.
67 String expression expected (Нужно выражение строкового типа).
Предшествующее выражение должно иметь строковый тип.
68 Circular unit reference (Перекрестная ссылка модулей).
Два модуля ссылаются друг на друга:
Unit A; Unit В;
Uses В; Uses A;
69 Unit name mismatch (Несоответствие имен программных модулей).
Имя программного модуля, найденное в файле *.TPU, не соответствует имени, указанному в
предложении USES.
70 Unit version mismatch (Несоответствие версий модулей).
Один или несколько программных модулей, используемых данной программой, были изменены после
их компиляции. Воспользуйтесь опцией COMPILE/MAKE или COMPILE/BUILD в интегрированной
среде или опциями /М или /В в компиляторе ТРС, что позволит автоматически скомпилировать
программные модули, нуждающиеся в перекомпиляции.
71 Duplicate unit name (Повторное имя программного модуля).
Вы уже указали этот программный модуль в операторе USES.
72 Unit file format error (Ошибка формата файла модуля).
Файл *.TPU не соответствует стандарту Турбо Паскаля.
73 IMPLEMENTATION expected (Отсутствует исполняемая часть модуля).
74 Constant and case types do not match (Типы констант и тип выражения оператора CASE не
соответствуют друг другу).
Тип константы оператора CASE не совместим с выражением в операторе варианта.
75 Record variable expected (Нужна переменная типа запись).
Предшествующая переменная должна иметь тип запись.
76 Constant out of range (Константа нарушает границы).
Возможные причины сообщения:
• Вы пытаетесь указать индекс массива, выходящий за его границы;
• Вы пытаетесь присвоить переменной значение, выходящее за границы, допустимые для типа этой
переменной;
• Вы пытаетесь передать в качестве фактического параметра процедуре или функции константу,
выходящую за границы, допустимые для типа соответствующего формального параметра.
�Оглавлен ие
77 File variable expected (Нужна файловая переменная).
Предшествующая переменная должна иметь файловый тип.
78 Pointer expression expected (Нужно выражение типа указатель).
Предшествующее выражение должно иметь тип указателя.
79 Integer or real expression expected (Нужно выражение вещественного или целого типа).
Предшествующее выражение должно иметь тип REAL или INTEGER.
80 Label not within current block (Метка не находится внутри текущего блока).
Оператор GOTO не может ссылаться на метку, находящуюся вне текущего блока.
81 Label already defined (Метка уже определена).
Данная метка уже помечает оператор.
82 Undefined label in processing statement part (Неопределенная метка в предшествующем разделе
операторов) .
Данная метка была описана, и на нее осуществлялась ссылка в предшествующем разделе операторов,
но она не указана в тексте программы.
83 Invalid @ argument (Неправильный аргумент операции @).
Правильными аргументами являются идентификаторы переменных, процедур и функций.
84 Unit expected (Нужно кодовое слово UNIT).
85 «;» expected (Нужно указать «;»).
86 «:» expected (Нужно указать «:»).
87 «,» expected (Нужно указать «,»).
88 «(» expected (Нужно указать «(»).
89 «)» expected (Нужно указать «)»).
90 «=» expected (Нужно указать «=»).
91 «:=» expected (Нужно указать «:=») .
92 «[» or «(.» expected (Нужно указать «[» или «(.»).
93 «]» or «.)» expected (Нужно указать «]» или «.)»).
94 «.» expected (Нужно указать «.»).
95 «..» expected (Нужно указать «..») .
96 Too many variables (Слишком много переменных).
Нарушены следующие ограничения:
• общий размер глобальных переменных, описанных в программе или программном модуле, не может
превышать 64 Кбайт;
• размер локальных переменных, описанных в процедуре или функции, не может превышать 64 Кбайт.
97 Invalid FOR control variable (Неправильный параметр цикла оператора FOR) .
Параметр цикла оператора FOR должен быть переменной порядкового типа, определенной в разделе
описаний текущей подпрограммы.
98 Integer variable expected (Нужна переменная целого типа).
Предшествующая переменная должна иметь целый тип.
99 File and procedure types are not allowed here (Здесь не могут использоваться файлы или
�Оглавлен ие
процедурные типы).
Типизированная константа не может иметь файловый или процедурный тип.
100 String length mismatch (Несоответствие длины строки).
Длина строковой константы не соответствует количеству элементов символьного массива.
101 Invalid ordering of fields (Неверный порядок полей).
Поля в константе типа запись должны записываться в порядке их описания.
102 String constant expected (Нужна константа строкового типа).
103 Integer or real variable expected (Нужна переменная типа INTEGER или REAL).
Предшествующая переменная должна иметь целый или вещественный тип.
104 Ordinal variable expected (Нужна переменная порядкового типа).
Предшествующая переменная должна иметь порядковый тип.
105 INLINE error (Ошибка в операторе INLINE).
Оператор «<» не допускается в сочетании с перемещаемыми ссылками на переменные. Такие ссылки
всегда имеют размер в слово.
106 Character expression expected (Предшествующее выражение должно иметь символьный тип).
107 Too many relocation items (Слишком много перемещаемых элементов).
Размер таблицы перемещения файла *.ЕХЕ превышает 64 Кбайта, что является верхним пределом в
Турбо Паскале. Если Вы обнаружили эту ошибку, то это значит, что программа просто слишком велика
для обработки компоновщиком Турбо Паскаля. Возможно также, что она слишком велика для
выполнения в MS-DOS. В таком случае нужно выделить в программе основной раздел, который
выполнял бы обращение к двум или более вспомогательным разделам с помощью процедуры ЕХЕС из
модуля DOS.
108 Overflow in arithmetic operator (Переполнение при выполнении арифметического оператора).
Результат предыдущей арифметической операции не лежит в диапазоне –2146483648 ...+2147483647.
Исправьте операцию или используйте вещественные типы вместо целочисленных.
109 No enclosing FOR, WHILE or REPEAT statement (Нет операторов, заканчивающих операторы
FOR, WHILE или REPEAT).
Процедуры BREAK и CONTINUE не могут вызываться вне тела оператора цикла.
110 Debug information table overflow (Переполнение информационной таблицы отладки).
Возможно, программа содержит более 65536 имен или 65536 строк. Отключите генерацию таблиц
отладки директивой компилятора {$D–} или исправьте один или более модулей.
111 Ошибка с этим кодом не описана в версии 7.0 системы Турбо Паскаль.
112 CASE constant out of range (Константа CASE нарушает допустимые границы).
Целочисленные константы оператора CASE должны находиться в диапазоне от – 32768 до 32767.
113 Error in statement (Ошибка в операторе).
Данный символ не может быть первым символом в операторе.
114 Cannot call an interrupt procedure (Невозможно вызвать процедуру прерывания).
Вы не можете непосредственно вызвать процедуру обработки прерывания.
115 Ошибка с этим кодом не описана в версии 7.0 системы Турбо Паскаль.
116 Must be in 8087 mode to compile this (Для компиляции необходим режим 8087) .
�Оглавлен ие
Данная программа может быть скомпилирована только в режиме {$N+}. В состоянии {$N–} операции
с типами SINGLE, DOUBLE, EXTENDED и СОМР не допускаются.
117 Target address not found (Указанный адрес не найден).
Команда COMPILE/FIND ERROR в среде Турбо Паскаля (или поиск с помощью опции /F в командной
строке компилятора ТРС.ЕХЕ) не обнаружила оператор, соответствующий заданному адресу.
118 Include files are not allowed here (Здесь не допускаются включаемые файлы).
Раздел операторов должен целиком размещаться в одном файле.
119 No inherited methods are accessible here (В этом месте программы нет унаследованных методов).
Вы используете зарезервированное слово INHERITED вне метода объекта или в методе, который не
унаследован от родительского объекта.
120 Ошибка с этим кодом не описана в версии 7.0 системы Турбо Паскаль.
121 Invalid qualifier (Неверный квалификатор).
Возможные причины сообщения:
• Вы пытаетесь индексировать переменную, которая не является массивом,
• Вы пытаетесь указать поля в переменной, которая не является записью,
• Вы используете в качестве указателя переменную, которая не является указателем.
122 Invalid variable reference (Недействительная ссылка на переменную).
Предыдущая конструкция удовлетворяет синтаксису ссылки на переменную, но она не указывает адрес
памяти. Возможно Вы вызываете функцию-указатель, но забываете сослаться на результат с помощью
знака ^.
123 Too many symbols (Слишком много символов).
Программа или программный модуль содержат более 64 Кбайт символов. Если Вы компилируете
программу с директивой {$D+}, то попробуйте отключить эту директиву или разбейте программу на
несколько модулей.
124 Statement part too large (Слишком большой раздел операторов).
Турбо Паскаль ограничивает размер раздела операторов до величины примерно 24 Кбайта. Если Вы
обнаружили эту ошибку, поместите части раздела операторов в одну или несколько процедур и вообще
сделайте Вашу программу более структурированной.
125 Ошибка с этим кодом не описана в версии 7.0 системы Турбо Паскаль.
126 Files must be var parameters (Файлы должны передаваться как параметры-переменные).
Вы пытаетесь передать процедуре или функции параметр-значение файлового типа. Параметры
файлового типа должны быть параметрами-переменными.
127 Too many conditional symbols (Слишком много условных символов).
Недостаточно памяти для определения условных символов (слов, управляющих командами условной
компиляции). Попытайтесь удалить некоторые символы или уменьшить их длину.
128 Misplaced conditional directive (Пропущена условная директива).
Компилятор обнаружил директиву {$ELSE} или {$ENDIF) без соответствующих директив {$IFDEF},
{$IFNDEF} или {$IFOPT}.
129 ENDIF directive missing (Пропущена директива ENDIF).
Исходный файл закончился внутри конструкции условной компиляции. В исходном файле должно
быть равное количество директив {$IFxxx} и {$ENDIF}.
�Оглавлен ие
130 Error in initial conditional defines (Ошибка в условных определениях).
Исходные условные символы указанные в опции OPTIONS/COMPILER /CONDITIONAL DEFINES
являются недействительными. Турбо Паскаль требует нуля или более идентификаторов, разделенных
пробелами, запятыми или точками с запятой.
131 Header does not match previous definition (Заголовок не соответствует предыдущему определению).
Возможные причины сообщения:
• заголовок процедуры или функции, указанный в интерфейсной секции, не соответствует заголовку в
исполняемой части.
• заголовок процедуры или функции, указанный с помощью опережающего описания FORWARD, не
соответствует заголовку найденной далее одноименной процедуры или функции.
132 Critical disk error (Критическая ошибка диска).
Во время компиляции произошла критическая ошибка диска (например, дисковод находится в
состоянии «не готов»).
133 Cannot evaluate this expression (Нельзя вычислить данное выражение).
В выражении–константе или в отладочном выражении Вы пытаетесь использовать
неподдерживаемые средства, например, в описании константы пытаетесь использовать функцию SIN
или вызвать в отладочном выражении определенную пользователем функцию.
134 Expression incorrectly terminated (Некорректное завершение выражения).
Контекстуально в данном месте программы должен быть конец выражения или оператора.
135 Invalid format specifier (Неверный спецификатор формата).
Используется неверный спецификатор формата или числовой аргумент спецификатора формата
выходит за допустимые границы.
136 Invalid indirect reference (Недопустимая косвенная ссылка).
Оператор пытается осуществить недопустимую косвенную ссылку. Например, Вы используете
абсолютную переменную, базовая переменная которой в текущем модуле неизвестна, или используете
программу типа INLINE, в которой делается ссылка на переменную, неопределенную в текущем
модуле.
137 Structured variable are not allowed here (Здесь нельзя использовать переменную структурного
типа).
Делается попытка выполнить над переменной структурного типа неподдерживаемую операцию.
Например, Вы пытаетесь перемножить две записи.
138 Cannot evaluate without System unit (Нельзя вычислить выражение без модуля SYSTEM).
Чтобы отладчик смог вычислить выражение, в файле TURBO.TPL должен содержаться модуль
SYSTEM.
139 Cannot access this symbol (Нет доступа к данному символу).
Как только Вы скомпилируете программу, все множество ее символов становится доступным. Однако
к отдельным символам (например, к переменным) нельзя получить доступ, пока Вы не запустите
программу.
140 Invalid floating-point operation (Недопустимая операция с плавающей запятой).
При выполнении операции с плавающей запятой произошло переполнение или деление на ноль.
141 Cannot compile overlay to memory (Нельзя выполнить компиляцию оверлейных модулей в память).
�Оглавлен ие
Программа, использующая оверлейные модули, должна компилироваться на диск.
142 Procedure or function variable expected (Должна использоваться переменная процедурного типа).
В этом контексте оператор получения адреса @ может использоваться только с переменной
процедурного типа.
143 Invalid procedure or function reference (Недопустимая ссылка на процедуру или функцию).
Возможные причины сообщения:
• Вы пытаетесь вызвать процедуру в выражении;
• процедура или функция, использующаяся в качестве параметра вызова другой процедуры или
функции, должна компилироваться в состоянии {$F+} и не может описываться с помощью
зарезервированных слов INLINE или INTERRUPT.
144 Cannot overlay this unit (Этот модуль не может использоваться в качестве оверлейного).
Попытка использовать в качестве оверлейного модуль, который не был скомпилирован с директивой
{$О+}.
145 Too many nested scopes (Слишком много вложений). В программе не может быть больше 512
вложений с не более чем 128 вложениями в каждом модуле. Вложениями считаются:
• каждый модуль в предложении USES;
• каждая вложенная запись в типе RECORD;
• каждый вложенный оператор WITH.
146 File access denied (Отказано в доступе к файлу).
Возможные причины:
• Вы пытаетесь использовать файл с атрибутом «только для чтения» в качестве выводного файла;
• Вы используете имя каталога вместо имени выводного файла.
147 Object type expected (Здесь должен быть тип OBJECT).
Этот идентификатор должен принадлежать к типу OBJECT.
148 Local object types are not allowed (Нельзя объявлять локальные объекты).
Нельзя объявить объект в процедуре (функции).
149 VIRTUAL expected (Пропущено слово VIRTUAL).
150 Method identifier expected (Пропущен идентификатор инкапсулированного правила).
151 Virtual constructor are not allowed (Конструктор не может быть виртуальным).
153 Destructor identifier expected (Пропущен идентификатор деструктора).
154 Fail only allowed within constructor (Обращение к стандартной процедуре FAIL может содержаться
только в конструкторе).
155 Invalid combination of opcode and operands (Недопустимая комбинация кода команды и
операндов).
Код ассемблерной команды не может иметь такие операнды. Причины ошибки:
• указано слишком много или слишком мало операндов для данной команды, например,
• INC AX, ВХ ИЛИ MOV АХ;
• количество операндов правильное, но их типы или порядок следования не соответствуют данной
команде, например, DEC 1, MOV AX, CL или MOV 1, AX.
156 Memory reference expected (Отсутствует адрес).
�Оглавлен ие
Операнд ассемблерной команды не содержит адрес. Вероятно, Вы забыли выделить квадратными
скобками индексный регистр, например, MOV AX, BX+SI вместо MOV AX, [BX+SI].
157 Cannot add or subtract relocatable symbols (Нельзя складывать или вычитать перемещаемые
символы).
В ассемблерных выражениях обоими операндами в операциях сложения или вычитания могут быть
только ссылки на константу. Идентификаторы переменных, процедур, функций и меток являются
перемещаемыми символами, и не могут использоваться в качестве двух операндов одновременно в
таких операциях. Если VAR – идентификатор переменной, a CONSТ – константы, то предложения
MOV AX, CONST+CONST и MOVE AX, VAR+CONST будут правильными, в то время как выражение
MOV AX, VAR+VAR недопустимо.
158 Invalid register combination (Недопустимая комбинация регистров).
Допустимыми комбинациями индексных регистров являются [ВХ], [ВР], [SI], [DI], [BX+SI], [BX+DI],
[BP+SI] и [BP+DI]. Другие комбинации (например, [АХ], [ВР+ВХ], [SI+DX]) недопустимы. Заметим,
что локальные переменные размещаются в стеке и доступ к ним организуется через регистр ВР.
Ассемблер автоматически добавляет [ВР] в ссылках на такие переменные, поэтому в операндах типа
LOCAL [ВХ], где LOCAL – локальная переменная, образуется недопустимая ссылка LOCAL [ВР+ВХ] .
159 286/287 instructions are not enabled (Недоступен набор команд микропроцессоров 286/287).
Используйте директиву {$G+}, но учтите, что такую программу можно исполнять только на ПК,
оснащенных микропроцессором Intel 80286/80287 или более поздним.
160 Invalid symbol reference (Недопустимая ссылка на символ).
К указанному символу нельзя обратиться в ассемблерной программе. Это может быть следствием
таких причин:
• Вы пытаетесь использовать ссылки на стандартные процедуры (функции) или специальные массивы
MEM, MEMW, MEML, PORT и PORTW в ассемблерных операндах;
• Вы обращаетесь к строковой, вещественной константе или константе типа SET в операнде
ассемблерной команды;
• в ассемблерном операнде Вы обращаетесь к процедуре или функции, написанной в режиме INLINE;
• Вы пытаетесь получить с помощью операции ©Result доступ к результату, возвращаемому функцией;
• Вы пытаетесь использовать короткую форму команды JMP для передачи управления в непомеченный
оператор программы.
161 Code generation error (Ошибка генерации кода).
Ошибка возникает, в частности, при компиляции ассемблерных фрагментов, содержащих команды
LOOP, LOOPE, LOOPNE, JCXZ, если команда ссылается на недоступную метку.
162 ASM expected (Отсутствует зарезервированное слово ASM).
ОШИБКИ, ВОЗНИКАЮЩИЕ ВО ВРЕМЯ ВЫПОЛНЕНИЯ ПРОГРАММ
Некоторые ошибки, обнаруженные во время выполнения программы, приводят к появлению на экране
сообщения вида
Runtime error nnn at хххх:уууу
(Ошибка периода исполнения nnn по адресу хххх:уууу)
где nnn – номер ошибки; xxxx:уууу – адрес (сегмент и смещение). После этого сообщения программа
завершает свою работу.
�Оглавлен ие
Ошибки периода исполнения делятся на четыре категории: ошибки, обнаруживаемые ДОС (коды
ошибок с 1 до 99), ошибки ввода–вывода (с 100 по 149), критические ошибки (с 150 по 199) и
фатальные ошибки (коды ошибок с 200 до 255).
Ошибки, обнаруживаемые ДОС
1 Invalid function number (Неверный номер функции).
Вы пытаетесь вызвать несуществующую функцию ДОС.
2 File not found (He найден файл).
Ошибка генерируется процедурами RESET, APPEND, RENAME или ERASE в случае, если имя,
присвоенное файловой переменной, указывает несуществующий файл.
3 Path not found (Путь не найден).
Ошибка генерируется процедурами:
• RESET. REWRITE, APPEND или ERASE в случае, если имя, присвоенное файловой переменной,
является недействительным или указывает на несуществующий подкаталог;
• CHDIR, MKDIR или RMDIR в случае, если путь является недействительным или указывает
несуществующий подкаталог.
4 Too many open files (Слишком много открытых файлов).
Ошибка генерируется процедурами RESET, REWRITE или APPEND в случае, если программа имеет
слишком много открытых файлов. ДОС не позволяет использовать более 15 открытых файлов для
каждого процесса. Если ошибка возникла при наличии менее 15 открытых файлов, то она может
указывать на то, что файл CONFIG.SYS не содержит параметра FILES =ххх или что этот параметр
задает слишком мало файлов. Увеличьте параметр FILES=ххх до какого-либо подходящего значения,
например, до 80.
5 File access defined (Отказано в доступе к файлу).
Данная ошибка генерируется процедурами:
• RESET или APPEND в случае, когда имя, присвоенное файловой переменной, указывает каталог или
файл, доступный только для чтения, в то время как параметр FILEMODE файловой переменной
содержит указание на запись данных;
• REWRITE в случае, когда каталог заполнен, или если имя, присвоенное файловой переменной, задает
каталог или существующий файл, доступный только для чтения;
• RENAME в случае, если имя, присвоенное файловой переменной, указывает каталог или если новое
имя указывает существующий файл;
• ERASE в случае, если имя, присвоенное файловой переменной, указывает каталог или файл,
доступный только для чтения;
• MKDIR в случае, если файл с тем же именем уже существует в порождающем каталоге, если нет места
в порождающем каталоге или если путь к каталогу содержит имя логического устройства;
• RMDIR в случае, если каталог не является пустым, если путь не определяет каталог или если путь
задает корневой каталог;
• READ или BLOCKREAD в случае типизированного или нетипизированного файла, если файл не
открыт для чтения;
• WRITE или BLOCKWR1TE для типизированного или нетипизированного файла в случае, если этот
файл не открыт для записи.
6 Invalid file handle (Недопустимый файловый канал).
�Оглавлен ие
Данная ошибка генерируется в случае, когда системному вызову ДОС передается недопустимый
файловый канал. Эта ошибка не должна возникать в правильно работающей программе. Ее появление
является свидетельством того, что файловая переменная каким-либо образом испорчена.
12 Invalid file access code (Недействительный код доступа к файлам).
Ошибка генерируется процедурами RESET или APPEND, если значение параметра FILEMODE в
файловой переменной не является допустимым.
15 Invalid drive number (Недопустимый номер дисковода).
Ошибка генерируется процедурой GETDIR в случае, если номер дисковода не является допустимым.
16 Cannot remove current directory (Нельзя удалить текущий каталог).
Ошибка генерируется процедурой RMDIR в случае, если путь указывает текущий каталог.
17 Cannot rename across drives (Нельзя при переименовании указывать разные дисководы).
Генерируется процедурой RENAME в случае, если оба файла не находятся на одном и том же диске.
Ошибки ввода-вывода
Если один из операторов компилировался с директивой {$I+}, то ошибка ввода–вывода приводит к
прекращению выполнения программы. В состоянии {$I–} программа продолжает выполняться, а
ошибка возвращается функцией IORESULT.
100 Disk read error (Ошибка чтения с диска).
Генерируется процедурой READ в типизированном файле в случае, если Вы пытаетесь осуществить
считывание из полностью прочитанного файла.
101 Disk write error (Ошибка записи на диск).
Ошибка генерируется процедурами CLOSE, WRITE, WRITELN, FLUSH в случае, если диск заполнен.
102 File not assigned (Файлу не присвоено имя).
Ошибка генерируется процедурами RESET, REWRITE, APPEND, RENAME и ERASE в случае, если
файловой переменной не было присвоено имя файла с помощью обращения к процедуре ASSIGN.
103 File not open (Файл не открыт).
Ошибка генерируется процедурами CLOSE, READ, WRITE, SEEK, EOF, FILEPOS, FILESIZE, FLUSH,
BLOCKREAD, BLOCKWR1TE в случае, если файл не открыт.
104 File not open for input (Файл не открыт для ввода).
Ошибка генерируется процедурами READ, READLN, EOF, EOLN, SEEKEOF или SEEKEOLN в
текстовом файле в случае, если файл не открыт для ввода.
105 File not open foe output (Файл не открыт для вывода).
Ошибка генерируется процедурами WRITE или WRITELN в текстовом файле в случае, если файл не
открыт для вывода.
106 Invalid numeric format (Неверный числовой формат).
Генерируется процедурами READ или READLN в случае, если числовое значение, считанное из
текстового файла, не соответствует правильному числовому формату.
Критические ошибки
150 Disk is write protected (Диск защищен от записи).
151 Unknown unit (Неизвестный модуль).
152 Drive not ready (Дисковод находится в состоянии «не готов»).
�Оглавлен ие
153 Unknown command (Неопознанная команда).
154 CRC error in data (Ошибка в исходных данных).
155 Bad drive requiest structure length (При обращении к диску указана неверная длина структуры).
156 Disk seek error (Ошибка при операции установки головок на диске).
157 Unknown media type (Неизвестный тип носителя).
158 Sector not found (Сектор не найден).
159 Printer out of paper (Кончилась бумага на принтере).
160 Device write fault (Ошибка при записи на устройство).
161 Device read fault (Ошибка при чтении с устройства).
162 Hardware failure (Сбой аппаратуры).
Фатальные ошибки
Эти ошибки всегда приводят к немедленной остановке программы.
200 Division by zero (Деление на ноль).
201 Range check error (Ошибка при проверке границ).
Ошибка генерируется операторами, скомпилированными в состоянии {$R+} при возникновении
одной из следующих ситуаций:
• индексное выражение массива находилось вне допустимого диапазона;
• была осуществлена попытка присвоить переменной значение, находящееся вне диапазона
переменной;
• была осуществлена попытка передать значение, находящееся вне допустимого диапазона, в качестве
параметра процедуре или функции.
202 Stack overflow error (Переполнение стека).
Эта ошибка генерируется на входе в процедуру или функцию, скомпилированную в режиме {$S+}, в
случае, если нет достаточной области для размещения локальных переменных подпрограммы.
Увеличьте размер стека, используя директиву компилятора {$М}.
203 Heap overflow error (Переполнение кучи).
Эта ошибка генерируется процедурами NEW или GЕТМЕМ в случае, если в куче нет свободной памяти
требуемого размера.
204 Invalid pointer operation (Недействительная операция с указателем).
Эта ошибка генерируется процедурами DISPOSE или FREEMEM в случае, когда указатель имеет
значение NIL или указывает на адрес, лежащий за пределами динамически распределяемой области
памяти.
205 Floating point overflow (Переполнение при операции с плавающей запятой).
В результате выполнения операции с плавающей запятой получено слишком большое вещественное
число.
206 Floating point underflow (Исчезновение порядка при операции с плавающей запятой).
Эта ошибка генерируется только в том случае, если используется сопроцессор 8087/80287/80387 с
управляющим словом, которое демаскирует ошибку исчезновения порядка. По умолчанию
исчезновение порядка приводит к возвращению результата, равного нулю.
207 Invalid floating point operation (Недопустимая операция с плавающей запятой).
�Оглавлен ие
Возможные причины сообщения:
• аргумент функций TRUNC или ROUND не может быть преобразован в целое число, находящееся
внутри диапазона типа LONGINT (от –2147483648 до +2147483647);
• отрицательный аргумент функции SORT (извлечение квадратного корня);
• аргумент функции LN (логарифм) равен нулю или имеет отрицательное значение;
• произошло переполнение стека сопроцессора.
208 Overlay manager not installed (Не установлена подсистема управления оверлеем).
Ваша программа вызывает оверлейную процедуру или функцию, а подсистема управления оверлеем не
инициирована. Вероятнее всего, в программе отсутствует обращение к процедуре OVRINIT или
обращение к этой процедуре завершилось с ошибкой. Нужно иметь в виду, что если в каком-либо из
оверлейных модулей содержится раздел инициации, то в программе необходимо создать
дополнительный или использовать имеющийся не оверлейный модуль, вызывающий процедуру
OVRINIT в своем разделе инициализации, и указать этот модуль в предложении USES перед любым
из оверлейных модулей.
209 Overlay file read error (Ошибка чтения оверлейного файла).
Ошибка чтения произошла, когда подсистема управления оверлеем пыталась считать оверлейный
модуль из оверлейного файла.
210 Object not initialized (He инициирован объект).
Вы обращаетесь к виртуальному правилу применительно к неинициированному объекту (до вызова
конструктора).
211 Call to abstract method (Вызов абстрактного правила).
Эта ошибка генерируется правилом ABSTRACT модуля OBJECT при работе в среде Turbo Vision в
случае обращения к абстрактному правилу, т.е. к виртуальному правилу, которое разработано
специально для его замены в объектах–потомках.
212 Stream registration error (Ошибка в регистрируемом потоке).
Эта ошибка генерируется правилом REGISTERTYPE модуля OBJECT при работе в среде Turbo Vision в
случае возникновения одной из следующих ошибок:
• запись регистрируемого потока не содержит сегмента данных;
• поле OBJTYPE записи регистрируемого потока нулевое;
• указанный тип уже был зарегистрирован;
• существует другой тип с таким же полем OBJTYPE.
213 Collection index out of range (Набираемый индекс выходит из границ диапазона).
Индекс, передаваемый объекту TCOLLECTION при работе в среде Turbo Vision, выходит за границы
диапазона.
214 Collection overflow error (Переполнение коллекции).
Эта ошибка генерируется объектом TCOLLECTION при работе в среде Turbo Vision в случае, если
делается попытка добавить элемент к коллекции, которую нельзя расширять.
�Оглавлен ие
Библиографический список
Библиографический список
1. Андреева, Т.А. Программирование на языке Pascal / Т.А. Андреева. – М. : Бином, 2006. – 240 с.
2. Зеленяк, О.П. Современный задачник по Турбо Паскалю / О.П. Зеленяк. – М. : ДМК Пресс, 2010. –
312 с.
3. Златопольский, Д.М. Программирование / Д.М. Златопольский. – М. : Бином. Лаборатория знаний,
2007. – 223 с.
4. Камаев, В.А. Технологии программирования / В.А. Камаев, В.В. Костерин. – М. : Высшая школа,
2005. – 359 с.
5. Кассера, В. Turbo Pascal 7.0 / В. Кассера, Ф. Кассера. – М. : DiaSoft, 2003. – 425 с.
6. Клатте, Р. PASCAL-XSC. Язык численного программирования / Р. Клатте, У. Кулиш, М. Неага и
др. – Изд-во : Журнал «Регулярная и хаотическая динамика», 2006. – 352 с.
7. Климова, Л.М. Pascal 7.0. Практическое программирование. Решение типовых задач /
Л.М. Климова. – М. : КУДИЦ-Образ, 2003. – 528 с.
8. Ковтанюк, Ю. Программирование на Turbo Pascal / Ю. Ковтанюк. – М. : Эксмо, 2008. – 592 с.
9. Культин, Н.Б. Turbo Pascal в задачах и примерах / Н.Б. Культин. – СПб. : BHV-Санкт-Петербург,
2005. – 256 с.
10. Лукин, С.Н. Turbo Pascal 7.0. Самоучитель для начинающих / С.Н. Лукин. – М. : Диалог-МИФИ,
2002. – 384 с.
11. Малыхина, М.П. Программирование на языке высокого уровня Turbo Pascal / М.П. Малыхина. –
СПб. : БХВ-Петербург, 2006. – 544 с.
12. Марченко, А.И. Программирование в среде Turbo Pascal 7.0 / А.И. Марченко, Л.А. Марченко. – М. :
Корона-Век, 2007. – 464 с.
13. Меженный, О.А. Turbo Pascal. Самоучитель / О.А. Меженный. – М. : Диалектика, 2008. – 336 с.
14. Моргун, А.Н. Справочник по Turbo Pascal для студентов / А.Н. Моргун. – М. : Вильямс, 2006. – 608
с.
15. Моргун, А.Н. Программирование на языке Паскаль. Основы обработки структур данных /
А.Н. Моргун, И.А. Кривель. – М. : Вильямс, 2006. – 576 с.
16. Окулов, С.М. Программирование в алгоритмах / С.М. Окулов. – М. : БИНОМ, 2002. – 341 с.
17. Потопахин, В.В. Turbo Pascal. Освой на примерах / В.В. Потопахин. – М. : BHV, 2005. – 240 с.
18. Рапаков, Г.Г. Программирование на языке Pascal / Г.Г. Рапаков, С.Ю. Ржеуцкая. – СПб. : БХВПетербург, 2004. – 480 с.
19. Сухарев, М. Turbo Pascal 7.0. Теория и практика программирования / М. Сухарев. – М. : Наука и
техника, 2007. – 544 с.
20. Тарануха, Н.Л. Обучение программированию. Язык Pascal / Н.Л. Тарануха, Л.С. Гринкруг,
А.Д. Бурменский и др. – М. : Солон-Пресс, 2009. – 384с.
21. Фаронов, В.В. TurboPascal 7.0. Практика программирования / В.В. Фарафонов. – М. : КноРус, 2009.
– 416 с.
22. Фаронов, В.В. Турбо Паскаль / В.В. Фарафонов. – М. : BHV, 2007. – 1056 с.
23. Фаронов, В.В. Турбо Паскаль. Начальный курс / В.В. Фарафонов. – М. : ОМД Групп, 2003. – 578 с.
24. Шелест, В.Д. Программирование / В.Д. Шелест. – СПб. : БХВ-Петербург. – 592 с.
25. Шпак, Ю.А. Программирование в Turbo Pascal. Переход к Delphi (+ CD-ROM) / Ю.А Шпак. – М. :
МК-Пресс, 2006. – 416 с.
26. Элиот, Б. Коффман. Turbo Pascal / Б. Элиот. – М. : Вильямс, 2005.
�
Dublin Core
The Dublin Core metadata element set is common to all Omeka records, including items, files, and collections. For more information see, http://dublincore.org/documents/dces/.
Title
A name given to the resource
Абрамкин Геннадий Петрович
Dublin Core
The Dublin Core metadata element set is common to all Omeka records, including items, files, and collections. For more information see, http://dublincore.org/documents/dces/.
Title
A name given to the resource
Программирование в среде Турбо Паскаль
Subject
The topic of the resource
1. Вычислительная техника. 2. Программирование ЭВМ. Компьютерные программы. Программотехника. 3. Турбо Паскаль.
Description
An account of the resource
Программирование в среде Турбо Паскаль [Электронный ресурс] : учебное пособие / Г. П. Абрамкин, Ю. С. Ефремов, О. В. Токарева ; Алтайский государственный педагогический университет. — 1 компьютерный файл (57.3 MB). — Барнаул : АлтГПУ, 2015. — 378 с.
Учебное пособие содержит систематическое изложение курса «Программирование» с использованием среды Турбо Паскаль. Оно написано в соответствии с требованиями государственного стандарта по специальности 050203.65 (физика с дополнительной специальностью информатика) и специальности 050203 (физика).
Creator
An entity primarily responsible for making the resource
Абрамкин, Геннадий Петрович
Source
A related resource from which the described resource is derived
Алтайский государственный педагогический университет, 2015
Publisher
An entity responsible for making the resource available
Алтайский государственный педагогический университет
Contributor
An entity responsible for making contributions to the resource
Юрий Сергеевич Ефремов
Ольга Викторовна Токарева
Format
The file format, physical medium, or dimensions of the resource
pdf, exe
Language
A language of the resource
русский
Identifier
An unambiguous reference to the resource within a given context
<a href="http://library.altspu.ru/dc/exe/abramkin.exe">http://library.altspu.ru/dc/exe/abramkin.exe</a><br /><a href="http://library.altspu.ru/dc/pdf/abramkin.pdf">http://library.altspu.ru/dc/pdf/abramkin.pdf</a>
Rights
Information about rights held in and over the resource
©Алтайский государственный педагогический университет, 2015
Type
The nature or genre of the resource
Учебное пособие.
Date
A point or period of time associated with an event in the lifecycle of the resource
01.06.2015
Вычислительная техника
Компьютерные программы
Программирование ЭВМ
Программотехника
Турбо Паскаль