244
Министерство общего и профессионального образования РФ Шадринский государственный педагогический институт Слинкин Д.А. ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕ Учебно-методическое пособие для студентов Вузов Шадринск, 2003

ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

  • Upload
    others

  • View
    29

  • Download
    0

Embed Size (px)

Citation preview

Page 1: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Министерство общего и профессионального образования РФШадринский государственный педагогический институт

Слинкин Д.А.

ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕ

Учебно-методическое пособиедля студентов Вузов

Шадринск, 2003

Page 2: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

681.3.066.3C47

Слинкин Д.А.Основы программирования на Турбо-Паскале: Учебно-методическое пособие

для студентов вузов. Шадринск: Изд-во Шадринского пединститута, 2003. - 244 с.

Учебно-методическое пособие подготовлено на основе многолетнего опыта преподавания дисциплины "Языки и методы программирования" на младших курсах факультета информатики и физико-математического факультета ШГПИ, и объединяет в себе расширенные, исправленные и дополненные материалы, опубликованные в учебных пособиях "Программирование. Часть 1. Язык программирования Турбо-Паскаль" и "Программирование. Часть 2. Методы программирования на Турбо-Паскале". В пособии приводится полное описание синтаксиса и семантики Турбо-Паскаля 7.0 для программирования в реальном режиме микропроцессора, рассматриваются методы программирования графики и объектно-ориентированного программирования, методы разработки больших программных проектов, более 60 подробно разобранных задач и более 200 задач для самостоятельно решения.

Пособие предназначено для студентов физико-математических факультетов и факультетов информатики педагогических вузов, может быть использовано в качестве методического пособия для учителей информатики старших классов средней школы, в классах с углубленным изучением информатики, а также для всех, кто в своей деятельности сталкивается с программированием персональных компьютеров.

Рекомендовано к печати кафедрой теории и методики информатики Шадринского пединститута.

ISBN

© Шадринский государственный педагогический институт© Слинкин Д.А.

2

Page 3: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

ОглавлениеВведение.......................................................................................................................................................9Глава 1. Язык программирования Турбо-Паскаль..........................................................................10

1.1 Ключевые понятия языков программирования............................................................................101.1.1 Алгоритм..................................................................................................................................10

1.1.1.1 Свойства алгоритма.........................................................................................................101.1.2 Программа................................................................................................................................11

1.1.2.1 Данные..............................................................................................................................111.1.2.2 Оператор...........................................................................................................................121.1.2.3 Подпрограмма..................................................................................................................121.1.2.4 Модуль..............................................................................................................................13

1.1.3 Язык программирования.........................................................................................................131.1.4 Текстовый редактор................................................................................................................131.1.5 Транслятор...............................................................................................................................131.1.6 Отладчик...................................................................................................................................141.1.7 Интегрированная среда...........................................................................................................14

1.2 Синтаксис и семантика языков программирования....................................................................151.3 Подготовка и запуск программ......................................................................................................16

1.3.1 Интегрированная среда Турбо-Паскаля 7.0..........................................................................161.3.2 Свойства интегрированной среды.........................................................................................171.3.3 Имена и расширения файлов для работы в интегрированной среде..................................181.3.4 Некоторые комбинации клавиш, используемых при работе с ИС.....................................18

1.4 Лексемы Турбо-Паскаля ................................................................................................................201.4.1 Специальные символы............................................................................................................201.4.2 Зарезервированные слова.......................................................................................................201.4.3 Директивы................................................................................................................................201.4.4 Идентификаторы.....................................................................................................................211.4.5 Метки........................................................................................................................................211.4.6 Числа.........................................................................................................................................211.4.7 Строковые константы.............................................................................................................22Задачи для раздела "Лексемы Турбо-Паскаля"..............................................................................22

1.5 Структура программы.....................................................................................................................241.5.1 Низкоуровневая структура программы.................................................................................241.5.2 Важнейшие операторы Турбо-Паскаля.................................................................................24

1.5.2.1 Оператор присваивания..................................................................................................241.5.2.2 Составной оператор.........................................................................................................251.5.2.3 Оператор вызова процедуры...........................................................................................25

1.5.3 Высокоуровневая структура программы...............................................................................261.5.3.1 Заголовок программы......................................................................................................271.5.3.2 Тело программы...............................................................................................................27

Раздел объявлений..................................................................................................................27Раздел объявления переменных........................................................................................28Раздел объявления констант..............................................................................................29Раздел объявления процедур и функций..........................................................................29

1.5.4 Примеры небольших программ.............................................................................................31Задачи для раздела "Структура программы".................................................................................32

1.6 Выражения.......................................................................................................................................33

3

Page 4: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

1.6.1 Структура выражений.............................................................................................................331.6.2 Приоритет операций................................................................................................................331.6.3 Типы операций.........................................................................................................................34

1.6.3.1 Арифметические операции.............................................................................................341.6.3.2 Логические операции......................................................................................................341.6.3.3 Строковые операции........................................................................................................351.6.3.4 Операции над множеством.............................................................................................351.6.3.5 Операции отношения......................................................................................................351.6.3.6 Операция @......................................................................................................................36

Задачи для раздела "Выражения"....................................................................................................361.7 Стандартные функции и процедуры.............................................................................................37

1.7.1 Процедуры и функции модуля System...................................................................................371.7.1.1 Арифметические функции..............................................................................................371.7.1.2 Процедуры выхода...........................................................................................................381.7.1.3 Обработка больших объемов данных (до 64К).............................................................381.7.1.4 Манипуляция байтами одного слова.............................................................................391.7.1.5 Генератор случайных чисел............................................................................................391.7.1.6 Границы и размеры типов данных.................................................................................401.7.1.7 Обработка параметров командной строки....................................................................401.7.1.8 Обзор дополнительных процедур и функций ..............................................................41

1.7.2 Процедуры и функции модуля Crt.........................................................................................41Задачи для раздела "Процедуры и функции модуля Crt".........................................................43

1.8 Операторы........................................................................................................................................441.8.1 Простые операторы.................................................................................................................441.8.2 Структурные операторы..........................................................................................................45

1.8.2.1 Условные операторы.......................................................................................................45Оператор IF..............................................................................................................................45Оператор CASE.......................................................................................................................47Задачи для раздела "Условные операторы"..........................................................................47

1.8.2.2 Операторы цикла.............................................................................................................49Цикл For...................................................................................................................................49Цикл While...............................................................................................................................52Цикл Repeat..............................................................................................................................53Вложенные циклы...................................................................................................................54Выбор вида цикла при решении задач..................................................................................57Процедуры break и continue....................................................................................................57Задачи для раздела "Операторы цикла"................................................................................59

1.9 Типы.................................................................................................................................................601.9.1 Простой тип..............................................................................................................................60

1.9.1.1 Порядковый тип...............................................................................................................60Встроенный порядковый тип.................................................................................................61

Целочисленный тип...........................................................................................................61Логический тип...................................................................................................................62Символьный тип.................................................................................................................63Перечислимый тип ............................................................................................................63Тип поддиапазона...............................................................................................................64Свойства порядковых типов..............................................................................................64

1.9.1.2 Вещественный тип...........................................................................................................66Задачи для раздела "Простой тип".............................................................................................69

1.9.2 Структурные типы...................................................................................................................71

4

Page 5: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

1.9.2.1 Массивы............................................................................................................................71Заполнение и обработка массивов.........................................................................................72Определение содержимого массива в разделе типированных констант...........................74Задачи для раздела "Массивы"..............................................................................................74

1.9.2.2 Строковый тип.................................................................................................................76Стандартный строковый тип..................................................................................................76ASCIIZ строковый тип............................................................................................................80Задачи для раздела "Строковый тип"....................................................................................83

1.9.2.3 Записи...............................................................................................................................84Определение содержимого записи в разделе типированных констант.............................85Задачи для раздела "Записи"..................................................................................................86

1.9.2.4 Множества........................................................................................................................86Задачи для раздела "Множества"...........................................................................................89

1.9.2.5 Файловые типы................................................................................................................90Принципы работы с файлами................................................................................................90Файловая позиция...................................................................................................................94Дополнительные процедуры и функции для работы с файлами........................................97Задачи для раздела "Файловые типы"...................................................................................98

1.9.2.6 Объектные типы (обзор).................................................................................................991.9.3 Указатели................................................................................................................................100

Задачи для раздела "Указатели"..........................................................................................1041.9.4 Процедурные типы (обзор)...................................................................................................1051.9.5 Приведение типов..................................................................................................................1051.9.6 Совместимость типов............................................................................................................106

1.10 Процедуры и функции................................................................................................................1081.10.1 Объявление процедур и функций......................................................................................1081.10.2 Формальные и фактические параметры............................................................................1091.10.3 Открытые массивы и строки..............................................................................................1141.10.4 Процедурные типы..............................................................................................................1161.10.5 Процедурные директивы....................................................................................................118

1.10.5.1 Директивы Near и Far..................................................................................................1181.10.5.2 Опережающие объявления..........................................................................................1181.10.5.3 Interrupt объявления.....................................................................................................1201.10.5.4 Внешние объявления (external)..................................................................................1201.10.5.5 Блок asm........................................................................................................................1201.10.5.6 Объявление inline.........................................................................................................120

Задачи для раздела "Процедуры и функции"...............................................................................1211.11 Модули........................................................................................................................................122

1.11.1 Интерфейсная секция..........................................................................................................1231.11.2 Секция реализации..............................................................................................................1231.11.3 Секция инициализации.......................................................................................................1241.11.4 Косвенные ссылки на модули............................................................................................1241.11.5 Циклические ссылки модулей............................................................................................1251.11.6 Пример разработки модуля.................................................................................................1271.11.7 Стандартные модули (обзор)..............................................................................................1291.11.8 Задачи для раздела "Модули".............................................................................................130

Глава 2. Методы программирования на Турбо-Паскале...............................................................1322.1 Программный проект (фаза 0)......................................................................................................1322.2 Графика..........................................................................................................................................134

2.2.1 Графические режимы............................................................................................................134

5

Page 6: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

2.2.1.1 Характеристики графических режимов.......................................................................1342.2.1.2 Видеоадаптеры EGA и VGA.........................................................................................1352.2.1.3 Этапы работы в графическом режиме.........................................................................136

2.2.2 Программирование в графическом режиме........................................................................1362.2.2.1 Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы.................................................................................................137

Задания для раздела "Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы" ......................................................................................................................139

2.2.2.2 Анализ ошибок...............................................................................................................140Задания для раздела "Анализ ошибок" ..............................................................................140

2.2.2.3 Графический указатель.................................................................................................140Задания для раздела "Графический указатель"..................................................................141

2.2.2.4 Графические инструменты............................................................................................141Свойства карандаша..............................................................................................................142

Задания для раздела "Свойства карандаша"..................................................................143Программный проект (фаза 1).........................................................................................144

Свойства кисти......................................................................................................................144Задания для раздела "Свойства кисти"...........................................................................145Программный проект (2).................................................................................................146

2.2.2.5 Фигуры............................................................................................................................146Точки, линии, многоугольники...........................................................................................146

Задания для раздела "Точки, линии, многоугольники"................................................148Программный проект (3).................................................................................................148

Дуги, окружности, эллипсы.................................................................................................149Задания для раздела "Дуги, окружности, эллипсы" (129-132).....................................151Программный проект (4).................................................................................................151

Заполнения.............................................................................................................................151Задания для раздела "Заполнения" (133-137)................................................................153

2.2.2.6 Вывод текста..................................................................................................................154Задания для раздела "Вывод текста"...................................................................................157Программный проект (5)......................................................................................................157

2.2.2.7 Сохранение и выдача изображений.............................................................................157Задания для раздела "Сохранение и выдача изображений"..............................................158Программный проект (6)......................................................................................................158

2.2.2.8 Холст...............................................................................................................................159Задания для раздела "Холст"................................................................................................161

2.2.2.9 Палитры..........................................................................................................................161Задания для раздела "Палитры" (150-153)..........................................................................163

2.2.2.10 Регистрация нестандартных графических драйверов и шрифтов..........................1642.2.2.11 Инкапсуляция файлов графических драйверов и шрифтов в исполняемый файл............................................................................165

2.3 Объектно-ориентированное программирование (ООП)...........................................................1662.3.1 Основные парадигмы ООП...................................................................................................1662.3.2 Реализация ООП средствами Турбо-Паскаля.....................................................................166

2.3.2.1 Класс Турбо-Паскаля.....................................................................................................166Программный проект (7)......................................................................................................173Задания для программного проекта (154- 164)..................................................................180

2.3.2.2 Динамические объекты.................................................................................................1812.3.2.3 Модуль OBJECTS..........................................................................................................184

Потоки....................................................................................................................................184

6

Page 7: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Хранение данных в потоках............................................................................................188Задания для раздела "Хранение данных в потоках".....................................................189Хранение объектов в потоках.........................................................................................189

Программный проект (8)......................................................................................................190Задания для программного проекта....................................................................................192Коллекции..............................................................................................................................192Программный проект (9)......................................................................................................194Задания для программного проекта....................................................................................195Ресурсы...................................................................................................................................196Задания для раздела "Ресурсы"............................................................................................198

2.4 Отладка программ.........................................................................................................................1992.4.1 Виды ошибок.........................................................................................................................199

Задания для раздела "Виды ошибок" ......................................................................................2002.4.2 Констатация и локализация ошибок....................................................................................2012.4.3 Использование встроенного отладчика...............................................................................202

2.5 Разработка больших программ....................................................................................................2042.5.1 Общие принципы разработки программ.............................................................................204

2.5.1.1 Метод организации «сверху-вниз». .............................................................................2042.5.1.2 Метод организации «снизу-вверх»...............................................................................2042.5.1.3 Достоинства и недостатки обоих методов:.................................................................204

2.5.2 Концепции разработки больших программных проектов (БПП).....................................2062.5.2.1 Руководство программным проектом и коллектив программистов.........................2062.5.2.2 Концептуальное единство проекта..............................................................................2072.5.2.3 Ошибки при реализации проекта.................................................................................208Задания для раздела "Концепции разработки больших программных проектов (БПП)." ....................................208

2.5.3 Событийная модель программного проекта.......................................................................2092.5.3.1 Понятие события при разработке больших программных проектов........................2092.5.3.2 Реализация механизма получения и обработки событий в однозадачной среде.. . .2092.5.3.3 Реализация механизма получения и обработки событий в многозадачной среде. .2102.5.3.4 Пример реализации получения и обработки событий в однозадачной среде.........2112.5.3.5 Программный проект (10).............................................................................................215

2.5.4 Объектно-событийная модель программы.........................................................................2162.5.4.1 Объектная модель программы .....................................................................................2162.5.4.2 Объединение объектной и событийной модели программ.......................................2172.5.4.3 Программный проект (11).............................................................................................2192.5.4.4 Режим работы объекта в объектно-событийной модели...........................................2262.5.4.5 Программный проект (12).............................................................................................227

Задания для программного проекта....................................................................................2372.5.5 Особенности отладки больших программных проектов (БПП), основанных на объектно-событийной модели........................................................................................................................238

2.5.5.1 Синтаксические ошибки в БПП..................................................................................2382.5.5.2 Семантические ошибки в БПП.....................................................................................238

Предупреждение семантических ошибок в БПП...............................................................238Констатация семантических ошибок в БПП......................................................................239Локализация семантических ошибок в БПП......................................................................240Методы локализации семантических ошибок в БПП.......................................................240Задания для раздела "Методы локализации семантических ошибок в БПП."................243

Список литературы...............................................................................................................................244

7

Page 8: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Введение

ВведениеЯзык программирования Паскаль был задуман и разработан в 1968-1971гг.

Никлаусом Виртом в Швейцарии, в Цюрихском Институте информатики как учебный язык для студентов с ясным синтаксисом и простой семантикой. В дальнейшем, с развитием новейших концепций программирования, появились его новые и более мощные реализации. Прежде всего, это относится к семейству Турбо-Паскаль (в дальнейшем - ТП) фирмы Borland International inc., разработанному для операционных систем DOS и Windows 3.0-3.11, Delphi для операционных систем планок Windows 95 и Windows NT, Kylix для операционной системы Linux, а также к кроссплатформенному компилятору FreePascal.

Мы не случайно выбрали Турбо-Паскаль из всего спектра средств разработки, основанных на Паскале. Цель данного пособия – научить основам программирования, а не, скажем, визуальной разработке программ. К сожалению, начала работы в такой среде, как Delphi или Kylix, имеют множество отвлекающих концепций и понятий, реализация которых сознательно предельно упрощена для повышения скорости создания программ. Эффективное их использование возможно только для профессионала, четко и ясно понимающего и разграничивающего возможности языка и среды разработки.

Знание программирования подразумевает понимание как высоко-, так и низкоуровневых механизмов обработки данных. Среда быстрой разработки приложений (RAD - Rapid Application Development), какой является Delphi, включающая в себя идеи визуального программирования, скрывает все низкоуровневые механизмы, выводя на первый план скорость разработки стандартных приложений. В случае усложнения исходной задачи или возникновения нестандартной ситуации программист, начавший изучение программирования с Delphi, не найдет решения проблемы без высококвалифицированной помощи извне или глубокого изучения принципов, положенных в основу языка и операционной системы. Первый подход применим далеко не всегда, а второй подразумевает значительное удлинение сроков создания программного продукта.

В Турбо-Паскале создание серьезной программной разработки невозможно без столь же серьезных знаний языка, методов и приемов программирования. Поэтому данное пособие является наиболее подходящим для начинающих программистов, рассчитывающих в будущем на применение полученных знаний в профессиональной деятельности, на создание коммерческих продуктов с помощью таких систем RAD, как Delphi и аналогичных сред.

8

Page 9: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Язык программирования Турбо-Паскаль.

Глава 1. Язык программирования Турбо-Паскаль.

1.1 Ключевые понятия языков программированияДля изучения любого языка программирования требуется определить

несколько понятий, как общих для всех языков, так и специфических для Турбо-Паскаля.

1.1.1 Алгоритм.Алгоритмом называется последовательность дискретных шагов (действий), предназначенных для исполнения и приводящих к некоторому конечному результату. Алгоритм обладает определенным набором свойств

1.1.1.1 Свойства алгоритмаЛюбой алгоритм должен обладать следующими основными свойствами:

1) Конечность. Выполнение программы должно быть завершено за некоторый конечный промежуток времени.Существует целый набор операторов, неправильное использование которых может вызвать бесконечный цикл, "зависание" программы. Это касается операторов цикла, условного и безусловного перехода и даже оператора присваивания (например - присваивание произвольной области памяти некоторого значения. Если эта область находится не в области данных программы, то результаты такого действия совершенно непредсказуемы).

2) Определенность. Все операторы, а также любые другие структуры, из которых состоит программа, должны быть известны исполнителю. Из этого следует, что в программе не должно быть отступления от синтаксиса ТП.

3) Возможность ввода данных и вывода результатов. В ТП ввод-вывод организуется с помощью процедур ввода-вывода. Рассмотрим четыре из них. Процедура Write позволяет выводить на экран значения выражений, следующие за ней в скобках через запятую. Процедура Writeln делает то же самое, но после вывода информации переводит строку:begin writeln(1231+4*(231-21),' ',444+23);end.В результате работы этой программы на экране появятся 2 числа:2071 467Все, что заключено в апострофы, выводится на экран без изменений. В данном случае в апострофы заключен пробел, используемый для разделения друг от друга первого и второго результатов.Дополнительно, процедуры Write и Writeln позволяют ставить после каждого числового выражения одно или два натуральных числа через двоеточие. Первое означает общее количество символов в числе (если цифр не хватает, то при выводе значение выражения дополняется слева требуемым количеством пробелов), а второе -

9

Page 10: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Свойства алгоритма

количество выводимых знаков дробной части.Пример:begin writeln (11.32/3:8:3, 4+5+6:5); writeln (11.32/0.3:8:3, 44+55+66:5);end.В результате работы программы на экране появится: 3.773 15 37.733 165Таким методом легко производить форматирование и выравнивание числовых выражений.Процедура Read позволяет вводить с клавиатуры значения и присваивать их переменным, имена которых идут после Read в скобках через запятую. Процедура Readln делает то же самое, но после ввода информации происходит переход на другую строку:var A,B: integer;begin Writeln('Введите два целых числа'); Readln (A,B); Writeln('Произведение чисел ', A, ' и ', B, ' равно ', A*B);end.После запуска данная программа остановится в ожидании ввода двух чисел (разделенных пробелом). После ввода и нажатия на клавишу "Enter" произойдет вывод на экран произведения этих чисел с соответствующими комментариями:Введите два целых числа6 2Произведение чисел 6 и 2 равно 12Процедура Readln без параметров ждет нажатия клавиши "Enter" (что удобно использовать как задержку в конце работы программы), а процедура Writeln - переводит курсор на другую строку. Процедуры Read и Write без параметров ничего не делают.

1.1.2 Программа.В языках программирования синонимом алгоритма служит программа. Создание готовой к исполнению программы проходит через несколько этапов: 1. Подготовка текста программы с помощью текстового редактора2. Трансляция (компиляция и компоновка). 3. При обнаружении ошибок запускается процесс отладки.

1.1.2.1 Данные.Данные программы - это информация, хранимая в памяти ЭВМ и обрабатываемая программой. В ТП данные сохраняются в переменных, а их обработка ведется с помощью операторов (см. ниже). Переменной называется именованная область памяти, содержимое которой программист может произвольно изменять в процессе работы программы. Каждая переменная имеет свой собственный тип, от которого зависит набор

10

Page 11: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Данные.

операций над переменной и занимаемый ею объем памяти компьютера. В ТП переменные могут быть целочисленными, вещественными, логическими, строковыми и т.д.Пример: числовые переменные могут занимать от 1 до 10 байт памяти в зависимости от того, является переменная целочисленной, натуральной, вещественной и т.д. Стандартные строковые переменные по умолчанию занимают 256 байт, однако при определении их размер может быть уменьшен до 1 байта.Любые переменные в ТП должны быть определены до своего использования. Это делается с помощью зарезервированного слова VAR: …Var X,Y:integer; Z,B:real;…В данном примере зарезервированное слово Integer определяет, что переменные X и Y будут иметь целочисленный тип, а слово Real - что переменные Z и B будут вещественными.

1.1.2.2 Оператор.Оператор – это команда или набор команд исполнителю (в данном случае исполнителем является компьютер), некоторое действие над данными программы. Операторы выполняются в программе один за другим до тех пор, пока выполнение не дойдет до самого последнего из них или до оператора, который принудительно заставит программу завершить работу.Чаще всего употребляемый оператор в ТП - это оператор присваивания, который используется для того, чтобы помещать в переменные различные значения:

var A:real;begin a:=7; a:=a+2;end.В этом примере между зарезервированными словами begin и end (последовательность которых также является оператором и означает (в данном случае) начало и конец программы) находятся 2 оператора присваивания, первый из которых присваивает переменной A значение 7, а второй - увеличивает A на 2.

1.1.2.3 Подпрограмма.Процедура (подпрограмма) - это часть программы, которая содержит набор операторов, выполняющих определенные действия над переданными ей данными (параметрами, аргументами). Процедура может быть вызвана из любой точки программы, причем при каждом вызове ей могут передаваться различные значения параметров.Функция - это процедура, возвращающая результат, что позволяет использовать ее в выражениях.В заголовке процедур и функций обычно описывается имя процедуры и список формальных параметров, то есть тех значений, которые анализирует процедура при своем выполнении. Параметры, передаваемые в процедуру из программы при ее вызове называются фактическими. Дополнительно, в

11

Page 12: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Подпрограмма.

заголовке функции описывается тип возвращаемого функцией значения.ТП имеет множество встроенных процедур и функций. Типичным примером могут служить арифметические и алгебраические функции: sin, cos, arctan, abs, sqrt и т.д. Каждая из них имеет только один числовой параметр, передаваемый ей в скобках и возвращает некоторое значение. Например, для получения тангенса некоторой переменной следует составить такую программу:var pi,z:real;begin pi:=3.1415926; z:=sin(pi)/cos(pi);end.Если процедура или функция имеет несколько параметров, то они передаются ей в скобках через запятую.

1.1.2.4 Модуль.Модули - это автономные программные блоки, содержащие в себе объединенные общим принципом такие компоненты программы, как переменные, типы, процедуры, функции и т.д. Модули используются для разбиения больших программ на отдельные, независимо существующие части. Например, в ТП имеется модуль Graph, который содержит в себе все требуемое для работы с графикой, имеется модуль Printer, использование которого позволяет вести вывод на печать стандартными средствами ввода-вывода и т.д.

1.1.3 Язык программирования.Язык программирования - это четкий, не допускающий различных толкований, искусственно созданный язык для точного описания алгоритмов, используемых в вычислительных машинах. Существуют языки программирования низкого и высокого уровней. Под языком низкого уровня понимают язык, синтаксис и семантика которого зависят от типа вычислительной машины, на которой он используется. Таким, например, является язык ассемблер, который имеет различные мнемонику и команды для различных типов машин. Синтаксис и семантика языка высокого уровня едины для любого типа ЭВМ. Результат выполнения программ на Паскале или Си будет одинаков и на IBM PC, и на Ямахе MSX-2. Однако в этом случае для каждого типа ЭВМ должна существовать программа-транслятор (см. ниже).

1.1.4 Текстовый редактор.На первом этапе создания программы используется текстовый редактор - программа подготовки разнообразных текстов.

1.1.5 Транслятор.Транслятор - это переводчик с языка высокого уровня на язык ассемблера.

12

Page 13: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Транслятор.

Трансляторы бывают двух видов - интерпретаторы и компиляторы. Программа-интерпретатор выполняет команды языка строка за строкой. Программа-компилятор переводит всю программу на язык ассемблера и только затем позволяет ее выполнить. Компоновщик - это одно средств разработки программ, входящее в состав транслятора. Под компоновкой понимается процесс объединения различных автономных программных блоков (модулей) в единое целое - готовую к исполнению программу.В поставке Турбо-Паскаля имеется быстродействующий компилятор-компоновщик, результатом работы которого является исполняемый файл.

1.1.6 Отладчик.Отладка - это процесс обнаружения и исправления ошибок. Отладчиком называется инструментальное программное средство, автоматизирующее процесс отладки.

1.1.7 Интегрированная среда.Интегрированная среда (IDE или ИС)- это система разработки программ, объединяющая текстовый редактор, компилятор (интерпретатор), компоновщик и отладчик в единое целое.IDE Турбо-Паскаля - это мощная и удобная система, позволяющая быстро создавать программы небольших и средних размеров. При больших объемах программного текста удобнее использовать автономные средства разработки программ, также входящие в состав ТП.

13

Page 14: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Синтаксис и семантика языков программирования

1.2 Синтаксис и семантика языков программирования

Описание любого языка (и не только языка программирования) всегда начинается с определения его синтаксиса и семантики.

Синтаксис - это правила записи конструкций языка, а также последовательности расположения этих конструкций. Синтаксические правила ничего не говорят о смысловом содержании конструкций, определяя только их форму. Чем строже и формальнее язык, тем меньшим количеством синтаксических правил он описывается. Чем больше свободы вкладывают разработчики языка в его основу, чем больше они предусматривают вариантов организации одних и тех же конструкций, тем сложнее описывается язык.В этом смысле ТП занимает "золотую середину" среди языков программирования. Он достаточно строг, чтобы отслеживать элементарное незнание конструкций и большой набор типовых ошибок, но в то же время достаточно свободен, чтобы создавать на нем профессиональные и высокоэффективные программные продукты.

Семантика - смысл, вкладываемый в каждую конструкцию или последовательность конструкций языка.И синтаксис и семантику любого языка можно описать неформально, приводя варианты всех видов конструкций и примеры их использования в различных ситуациях. Однако для описания синтаксиса существуют формальные методы, применение которых значительно сокращает объем описаний. Формальные методы для описания семантики также существует, однако они достаточно сложны, громоздки и используются, в основном, для доказательства свойств программ.

В дальнейшем, для описания семантики языка мы будем пользоваться неформальными методами, а для описания синтаксиса – одним из вариантов нормальных форм Бэкуса-Наура (БНФ). БНФ служат для определения синтаксиса алгоритмических языков и состоят из некоторого количества правил продукций, с помощью которых синтаксические конструкции определяются через другие синтаксические конструкции и лексемы, где под лексемами понимаются минимальные неделимые смысловые единицы языка.

Правила продукций БНФ:1) Имя определяемой синтаксической конструкции размещается слева, а ее

определение - справа. Имя конструкции и ее определение разделены символом '::='. Друг от друга синтаксические конструкции и лексемы отделяются пробелами.

2) Синтаксические конструкции никак не выделяются, лексемы выделяются с помощью кавычек (либо, если это возможно, жирным шрифтом).

3) Для обозначения возможного выбора из нескольких вариантов используется знак ¦.

4) Для обозначения повторов используются знаки a{}b. Если a отсутствует, то считается, что a=0Если b отсутствует, то считается, что b=∞

5) Для обозначения факультативных возможностей используются знаки [].

14

Page 15: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Синтаксис и семантика языков программирования

6) Для группирования используются знаки ().7) Точка показывает конец определения.Пример 1:В качестве примера рассмотрим определение рационального десятичного числа с

использованием БНФ.Ниже показаны несколько рациональных десятичных чисел с плавающей точкой:1 2.04331 -12 +32.00 -2Объединим все варианты в одной форме:РДЧ ::= Целое_число ["." Натуральное_число].Целое _число::=["+"|"-"] Натуральное_число.Натуральное_число::= 1{Цифра}.Цифра::="0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9".Таким образом, кроме определения рационального десятичного числа с плавающей

десятичной точкой мы определили еще 3 синтаксических конструкций, благодаря которым сократили размер определения, и которыми можно будет воспользоваться в дальнейшем для определения, например, РДЧ с фиксированной точкой.

1.3 Подготовка и запуск программ

1.3.1 Интегрированная среда Турбо-Паскаля 7.0.В комплекте поставки Турбо-Паскаля имеется как интегрированная среда

разработки (TURBO.EXE - для реального режима, BP.EXE - для реального, защищенного режимов и Windows, BPW.EXE - для Windows), так и автономный компилятор-компоновщик (TPC.EXE - для реального режима, BPC.EXE - для реального, защищенного режимов и Windows). Отдельный от IDE текстовый редактор не предусматривается, так как для написания текста программы не требуется никаких специальных возможностей. В принципе, для подготовки текста программы может быть использован любой текстовый редактор любого производителя, с возможностью сохранения текста в формате ASCII.

В дальнейшем мы будем рассматривать программирование в реальном режиме, которое на языках высокого уровня отличается от создания программ для защищенного режима меньшим объемом памяти, выделяемой для программы и некоторым понижением скорости выполнения результирующего кода. Программирование для оконно-ориентированной многозадачной операционной системы или оболочки (Windows, Xfree86 в Linux и т.д.) удобнее изучать с помощью Delphi или Kylix. Практически любая программа, разработанная для реального режима DOS, может быть преобразована для консольного режима многозадачных операционных систем, и даже для графических многооконных режимов таких ОС, после изменения методов ввода-вывода с терминальных (вывод в окно DOS и ввод напрямую с клавиатуры, мыши или других устройств ввода) на оконно-ориентированные (вывод информации в окна, и обработка ввода из очередей событий). В то же время программирование для защищенного режима или Windows в Турбо-Паскале значительно усложняется проблемами отладки. Поиск и

15

Page 16: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Интегрированная среда Турбо-Паскаля 7.0.

анализ ошибок затруднен в первом случае, из-за отсутствия встроенного отладчика, а во втором, дополнительно, из-за событийной модели организации программы, в которой часто невозможно определить, каким образом выполнение программы оказалось в некоторой точке. По этим причинам для первоначального изучения языка программирования проще воспользоваться IDE реального режима. На компьютерах с процессором 80386 и выше более удобна интегрированная среда BP.EXE, которая занимает около 10К обычной памяти компьютера, оставляя всю остальную (до 600 К) для выполнения программы. К сожалению на процессорах ниже 80386 вся интегрированная среда размещается в обычной памяти, поэтому в таких случаях мы предлагаем использовать IDE TURBO.EXE.

1.3.2 Свойства интегрированной среды.В этом параграфе мы коротко рассмотрим интегрированную среду Борланд-

Паскаля (BP.EXE), как наиболее общую и включающую в себя все компоненты Турбо-Паскаля 7.0 для реального режима (TURBO.EXE).

ИС Турбо-Паскаля является многооконной системой. Это означает, что одновременно на экране может быть расположено несколько окон – с текстами программ, информацией для отладки, списком выполняемых в данный момент процедур и функций, значениями регистров микропроцессора и т.д., причем одно из них всегда является активным - т.е. в него производится ввод информации. При открытии или создании нового файла программы происходит открытие нового окна. ИС позволяет произвольно перемещаться по открытым окнам с помощью мыши или специальных комбинаций клавиш.

Сверху находится разветвленная система меню, которая позволяет легко управлять разработкой программы.

Каждый элемент меню может быть выбран с помощью перемещения по меню, с помощью "мыши" или "горячей клавиши" - нажатия комбинации ALT и подсвеченной буквы элемента меню (для главного меню) или просто нажатием подсвеченной буквы элемента подменю.

Например - выход в меню File может быть произведен нажатием Alt-F, а открытие затем файла (подменю File/Open ) - нажатием на клавишу О. Многие элементы меню также могут быть выбраны с помощью специальных комбинаций клавиш. Например, компиляция всей программы выполняется с помощью клавиши F9, а компиляция только текущего модуля программы, который находится в активном окне - с помощью комбинации Alt-F9.

Одним из наиболее полезных свойств интегрированной среды является наличие буфера обмена, который активно используется при написании и редактировании больших программ. Буфер обмена в Турбо-Паскале - это область памяти компьютера, в которую может быть помещен любой текстовый блок и откуда он может быть снова скопирован в программу. Таким образом легко создавать повторяющиеся части программного кода, не переписывая их заново. Буфер обмена Турбо-Паскаля обладает рядом преимуществ по сравнению, например, с аналогичным буфером в операционной системе Windows. Во первых, текст помещаемый в него, не заменяет старого содержимого. а добавляется в конец.

16

Page 17: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Свойства интегрированной среды.

Во вторых, буфер обмена может быть открыт как любое окно и отредактирован стандартными средствами встроенного текстового редактора. Выделенная часть буфера обмена определяет копируемую в дальнейшем область.

1.3.3 Имена и расширения файлов для работы в интегрированной среде.

Файл текста программы на языке Паскаль имеет расширение ".pas" и компилируется средой в исполняемый файл с расширением ".exe". Дополнительно, Турбо-Паскаль поддерживает модули, которые как отдельные, независимые блоки, которые могут включаться в любую программу. Подробное описание многомодульного программирования будет дано в параграфе 1.11, сейчас же нам требуется знать, что расширение файла исходного текста модуля также, как и для программы, ".pas", но в результате компиляции модуля создается еще один файл – с именем модуля, но расширением ".tpu" (в зависимости от того, для какого режима вы компилируете программу - реального, защищенного или Windows, расширения скомпилированного модуля будет соответственно ".tpu", ".tpp" и ".tpw").

Интегрированная среда сохраняет все свои настройки в файле с расширением ".tp" или ".bp", в зависимости от того, какую среду вы запускаете. Расположение окон хранится в файле с расширением ".dsk"

Большое значение для эффективности разработки программ имеет эргономика виртуального рабочего места. Прежде всего, требуется понимать, что нерационально хранить свои программы в том же каталоге, в котором находится Турбо-Паскаль. Мы предлагаем заводить для каждого нового проекта подкаталог, где будут находиться:

1. Файлы проекта (".pas", ".tpu", ".exe")2. Файлы настройки среды (".tp" или ".bp", ".dsk")3. Командные файлы для запуска интегрированной среды (например: bp.bat

или turbo.bat, причем содержимое того и другого может состоять всего из одной строки - c:\bp\bin\bp.exe или c:\bp\bin\turbo.exe)

В дальнейшем, разрабатывая свои собственные модули, вы сможете поместить их в дополнительный каталог, к которому будете обращаться из различных программ.

1.3.4 Некоторые комбинации клавиш, используемых при работе с ИС.

Работа с окнами:Перейти к некоторому окну по его номеру –ALT-номер окнаПерейти к произвольному окну – Alt-0. При этом открывается диалоговое окно со списком открытых в данный момент окон, в котором можно затем производится выбор)

Закрыть активное окно –Alt-F3Компиляция и запуск программы.

17

Page 18: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Некоторые комбинации клавиш, используемых при работе с ИС.

Компиляция программы – Alt-F9Компиляция всех измененных модулей программы –F9Компиляция и запуск программы – Ctrl-F9

Работа с файлами.Открыть файл – F3Сохранить файл – F2

Работа с буфером обмена и блоками.Отметить блок – Shift и клавиши перемещения курсора.Скопировать блок в буфер обмена – Ctrl-InsВставить блок из буфера обмена в программу по положению курсора – Shift-Ins

Полное описание меню, окон, комбинаций клавиш Вы можете найти в справочной системе Турбо-Паскаля.

18

Page 19: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Лексемы Турбо-Паскаля

1.4 Лексемы Турбо-Паскаля Лексемы (минимальные смысловые единицы языка) в ТП подразделяются на

специальные символы, зарезервированные слова, директивы, идентификаторы, метки, числа и строковые константы.

Турбо-Паскаль не различает в лексемах (кроме содержимого строковых констант) прописные и строчные буквы.

Например, зарезервированное слово for будет пониматься правильно и в следующих вариантах написания: FoR, fOR, FOR и т.д.

1.4.1 Специальные символыТаблица специальных символов

+ - * / Знаки арифметических операций

= > < <> >= <= Знаки операций сравнений[ ] . , ( ) : ; ^ @ { } $ # (* *)

1.4.2 Зарезервированные словаЗарезервированные слова в ТП используются для определения структуры

программы и построения всех операторов языка:and, asm, array, begin, case, const, constructor, destructor, div, do, downto,

else, end, exports, file, for, function, goto, if, implementation, in, inherited, inline, interface, label, library, mod, nil, not, object, of, or, packed, procedure, program, record, repeat, set, shl, shr, string, then, to, type, unit, until, uses, var, while, with, xor.

Зарезервированные слова Турбо-Паскаля уникальны и не могут быть переопределены. Например, вы не можете объявить переменную с именем VAR или процедуру с именем uses.

1.4.3 ДирективыДирективы в ТП используются для изменения смысла действия некоторых

операторов. Большинство из них являются процедурными директивами, то есть изменяют синтаксис и семантику процедур и функций:

absolute, assembler, export, external, far, forward, index, interrupt, near, private, public, resident, virtual

В отличие от зарезервированных слов, директивы могут быть переопределены в программе, однако разработчики Турбо-Паскаля не советуют этого делать.

Действительно, определив, например, переменную с именем absolute, мы не сможем в дальнейшем воспользоваться этой директивой в ее первоначальном значении.

В ТП имеются также директивы компилятора, которые не являются лексемами, так как имеют сложную структуру, практически идентичную

19

Page 20: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Директивы

комментариям (см. параграф 1.5.1). В то же время, как и обычные директивы, директивы компилятора вносят изменения, только на этот раз, в процесс компиляции программы.

Примеры директив компилятора: {$I+} {$I include.pas} {$L objfile.obj} {$O-} {$define debug}

1.4.4 ИдентификаторыИдентификаторы позволяют ссылаться на используемые объекты.

Выступают в качестве имен констант, типов, переменных, процедур, функций, модулей и полей в записях.

ИД::=(лат_буква| "_"){ лат_буква | "_" | цифра}.Это означает, что любой идентификатор начинается с буквы или знака подчеркивания и

продолжается буквами, знаками подчеркивания или цифрами, расположенными в произвольном порядке

Примеры идентификаторов:R23_34TTTtttR4fDdGПри этом второй и третий идентификатор идентичны.

1.4.5 МеткиМетки являются либо числами от 0 до 9999 либо идентификаторами и

используются совместно с оператором перехода goto.Примеры меток: 0, 4532, Ff34

1.4.6 ЧислаТП использует следующие виды чисел: целые десятичные и

шестнадцатеричные, вещественные десятичные. Вещественные числа могут быть как с плавающей, так и с фиксированной точкой.

Шестнадцатеричное число ::= ["+"|"–"] "$" послед.шестн.цифр.

Последовательность шестнадцатеричных цифр представляет собой набор из цифр и первых 6 латинских букв в произвольном порядке (A означает 10, B - 11, C - 12, D - 13, E - 14, F - 15)

Примеры вещественных десятичных чисел:123.561.0034E+0032 (что означает 1.0034•1032)

Примеры шестнадцатеричных чисел:+$1F0–$117

20

Page 21: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Числа

$ADFAПринципы работы с различными системами счисления Вы можете узнать из

приложения.

1.4.7 Строковые константыСтроковые константы используются в ТП, чтобы определять произвольный

(даже многострочный) текст. Строковые константы должны располагаться в пределах одной строки и быть заключенными в апострофы.

Строковая_константа::= Простая_строка | Упр_символ | {Простая_строка | упр_символ}.

Пробелы между простыми строками и управляющими символами не ставятся.Простая_строка ::= " ' " {символ_строки} " ' ".Под символом строки понимается любой видимый на экране символ, кроме

знака апострофа.Пример: 'Запасайтесь, дьяволы, гробами, стрелять буду!'

{Зощенко}А следующий пример синтаксически неверен!

'Коль подарите нас своим вниманьем,Изъяны все загладим мы стараньем.'

{Вильям Шекспир "Ромео и Джульетта"}В случае, если строка должна включать в себя знак апострофа, требуется

ставить два таких знака подряд.Пример: строковая константа, состоящая из простой строки

'Вы даже, если хотите знать, нес''едобны' {Стругацкие, "Сказка о тройке"}

при выводе на экран будет выглядеть следующим образом: Вы даже, если хотите знать, нес'едобны

Упр_символ ::= "#" натуральное_однобайтовое_числоУправляющие символы позволяют использовать знаки, которые имеют

специальное предназначение. Так как в стандартной таблице символов ASCII всего 256 знаков, то для определения любого символа достаточно однобайтового числа.

С помощью пары управляющих символов можно создавать многострочный текст, заключенный в одну строковую константу. Символ с номером 13 означает переход на следующую строку, а символ с номером 10 - возврат на начало строки. Таким образом, строковая константа'Бьется в тесной печурке огонь'#10#13'На поленьях смола как слеза'на экране будет выглядеть так

Бьется в тесной печурке огоньНа поленьях смола как слеза

Задачи для раздела "Лексемы Турбо-Паскаля"Задание 1. Какие из нижеперечисленных наборов символов являются идентификаторами?1) ПАСКАЛЬ d10 DIV !g1w $1 322) monday mod xor insert absolute 132D2

21

Page 22: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Задачи для раздела "Лексемы Турбо-Паскаля"

3) XxXxX #YY -.-.- 1_1_1 _1_1_1 RTRЗадание 2. Какие из нижеперечисленных наборов символов являются числами?1) 345.43 23,56 $G12F -$34A 12.4E-01 123452) $FFFF +$12 $12.4 78.789 4321234 FFF3) 43,56 $HF2 1$3 111111 1A2B3C $1A2B3CЗадание 3. Какие из нижеперечисленных наборов символов являются строковыми константами?1) "Утро вечера мудренее"2) 'Без труда не вытащишь и рыбку из пруда' 3) 'Пришлось с'ехать с дороги'4) 'Строковая' #10 #13 'константа'5) #10#13'Попробуем другой вариант'#10#136) ' '#0' '#1' '#2Задание 4. Какие из нижеперечисленных наборов символов являются метками, числами, идентификаторами? Может ли набор символов относится одновременно к первому, второму и третьему типам лексем?1) dsewя 1023 45302 $g23 a1111 43.5D+12 DFF $12.52) 34,34 -$45f 12 A!!!! RTD 1097999 F12043 32D.3143) рык FdFe $345 +319 913 combat 32sd3 33e.31

22

Page 23: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Структура программы

1.5 Структура программы

1.5.1 Низкоуровневая структура программыНа низком уровне программа состоит из лексем и разделителей,

размещаемых в строках, где разделители представляют собой пробелы или комментарии. Строки программы не могут быть длиннее 126 символов.

Под комментарием в ТП понимается любой набор знаков, заключенный между специальными символами { } или (* *). Комментарии и директивы компилятора визуально очень схожи друг с другом, однако имеется очевидное отличие в синтаксисе (если после открывающей скобки сразу идет знак "$", то данный набор скобок считается директивой компилятора). Комментарии игнорируются компилятором. Они не могут быть вложенными при использовании только первого или только второго набора скобок.

Пример:{Это правильный комментарий}(* Это тоже правильный комментарий *){А {здесь} ошибка!!! }Тем не менее ТП позволяет вкладывать одни комментарии в другие при

использовании различных видов скобок. Эта особенность позволяет легко исключить из программы большой блок, даже если в нем уже имеются комментарии. Общее правило, по которому можно определить набор символов, допустимый внутри комментария, состоит в следующем: "Внутри комментария допустим любой набор символов, кроме закрывающей скобки комментария".

Пример:{Демонстрируем (*первый*) уровень (*вложенности*)}(*Снова {демонстрируем первый} {уровень} вложенности*){Демонстрируем (*типичную {ошибку}, которую допускают*) начинающие

программисты}

1.5.2 Важнейшие операторы Турбо-ПаскаляВсе действия в программе выполняются с помощью операторов. Операторы в

ТП подразделяются на простые и структурные.В этом параграфе среди простых операторов мы рассмотрим оператор

присваивания и вызова процедур (функций), среди структурных - только составной оператор. Более подробно эти и другие операторы будут рассмотрены позднее, в параграфе 1.8.

1.5.2.1 Оператор присваиванияОператор присваивания используется в основном для присвоения значений

переменным. Оператор_присваивания::=

(ИД_переменной | ИД_функции) ":=" выражение.

23

Page 24: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Оператор присваивания

ИД_переменной - идентификатор (имя) некоторой переменной, которой присваивается значение выражения. Естественно, что выражение должно возвращать значение такого же типа, какой определен для переменной (или совместимого по присваиванию - см. параграф 1.9.6). Это означает, например, что если переменная описана в разделе объявлений как целочисленная, то ей можно присваивать выражения только целочисленного или натурального типа, а если переменная строковая, то выражение должно быть строковым или символьным, но никак, например, не вещественным.

Использование ИД_функции мы рассмотрим в позднее, в параграфе .Пример:Пусть A - переменная целочисленного типа, а B - строкового. Тогда оператор

присваивания можно использовать следующим образом: A:=7+23-A;B:='Утро вечера мудренее';A:=B; {ОШИБКА!!!}B:='3415';B:=12; {ОШИБКА!!!}

1.5.2.2 Составной операторСоставной_оператор::=

"begin" оператор {";" оператор} [";"]"end"Обратите внимание, что составной оператор может включать в свое тело

произвольное количество других операторов, а так как он сам также является оператором, то включение одного составного оператора в тело другого не является ошибкой. Составной оператор используется, чтобы сгруппировать в единый блок несколько действий. Правила хорошего тона в программировании требуют, чтобы тело составного оператора было сдвинуто вправо на один или несколько символов.

Примерbegin A:=7; c:=a+6; begin a:=8; c:=c+a; end;end;

1.5.2.3 Оператор вызова процедурыОператор вызова процедуры производит вызов ранее определенной или

встроенной процедуры, передавая ей список фактических параметров. Процедура ОБЯЗАТЕЛЬНО должна быть определена либо в разделе объявления процедур и функций программы, либо в одном из подключаемых модулей (в том числе и объектных, присоединяемых к программе с помощью директивы компилятора $L).

Вызов функций в ТП производится аналогично оператору вызова процедуры. Отличие состоит в том, что функции используются только в выражениях (исключение составляет применение директивы компилятора {$X+}, после чего

24

Page 25: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Оператор вызова процедуры

любая функция может быть вызвана как процедура).Оператор_процедуры ::=

ИД_процедуры список_фактических_параметров.Список_фактических_параметров ::=

["(" выражение {"," выражение}")"]Например:begin…RunError(111);…Exit;…Writeln('Вы истратили ', N, ' рублей из ', S1+S2);…Dec(A,5+b);…MyProc(10, A+X+Z, 34);

end.Выражения в списке фактических параметров должны быть совместимыми

по типу с формальными параметрами процедуры, заданными при ее определении. Количество формальных и фактических параметров также должно совпадать.

Например:Процедура Bar, определенная в модуле Graph, рисует на экране закрашенный

прямоугольник и имеет следующий заголовок:procedure Bar(x1, y1, x2, y2: Integer);x1, y1, x2, y2 - формальные параметры процедуры Bar.Ниже приводятся правильные и неправильные примеры вызовов этой процедуры.var a,b:integer;c:real; x:boolean;

begin…{вызывая процедуры, подставляем вместо формальных параметров фактические}bar(a,b,15,23+b);bar(x,12,34,a+b); {неверно!}bar(c+a,1,a,a+b); {неверно!}bar(a+10,b,x,30+b); {неверно!}bar(a/b,b,a,10); {неверно!}bar(a div b,b,a,10); bar(a+b,a+b,a*b,a*b);…

end.Более подробно о процедурах и функциях будет рассказано в параграфе ------,

а также ниже, при анализе раздела объявлений процедур и функций.

1.5.3 Высокоуровневая структура программыНа высоком уровне программа состоит из необязательного заголовка

программы и блока, который собственно является телом программы.

25

Page 26: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Высокоуровневая структура программы

Программа::=Заголовок_программы Блок "."Заголовок_программы::=

["program" идентификатор ";"] [подключение_модулей]Блок ::= Раздел_объявлений Составной_оператор

1.5.3.1 Заголовок программыПервая часть заголовка программы служит для ее идентификации и никак не

влияет на содержимое. Вторая часть (подключение модулей) используется, чтобы сделать доступными разработанные ранее процедуры, функции, переменные, типы и т.д.

Подключение_модулей::= "uses" список_модулей ";".Под списком модулей мы понимаем имена модулей, перечисленных через

запятую.Пример:Program Grafik; Uses Graph, Dos, Printer; ...В ТП существует специальный, автоматически подключаемый модуль

System.tpu, содержащий в себе множество стандартных процедур и функций и не требующий указания в списке подключаемых модулей. Если в дальнейшем, объясняя работу той или иной функции, процедуры, смысл переменой, константы и т.д., мы не будем приводить имя модуля, в котором она находится, значит данный объект определен в модуле System.

1.5.3.2 Тело программы.Тело программы состоит из блока, содержащего в себе раздел объявлений и

составной оператор. В разделе объявлений происходит описание всех идентификаторов и меток,

которые будут использоваться в составном операторе блока. Раздел объявления действителен только для этого блока и всех внутри

лежащих.Это означает, что если, например, переменная объявлена в некотором внутреннем блоке, и,

следовательно, является локальной для него (например - в теле процедуры или функции), то во внешнем блоке она не может быть использована. Если же переменная объявлена во внешнем блоке то в любом из внутренних она может быть использована.

Из этого правила есть одно исключение. Если идентификатор или метка с одним и тем же именем объявлены как в основном, так и во вложенном блоках, то последний будет иметь доступ только к своему идентификатору или метке. Более подробно этот нюанс будет рассмотрен при изучении процедур и функций в параграфе .

Раздел объявлений.

Раздел_объявления::={раздел_объявления_переменных

26

Page 27: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Тело программы.

| раздел_объявления_констант| раздел_объявления_меток| раздел_объявления_типов| раздел_объявления_проц_и_функц}

В разделе объявления меток определяются используемые в блоке метки, а в остальных разделах - различные идентификаторы.

В этом параграфе мы рассмотрим разделы объявления переменных, констант и, частично, процедур и функций.

Раздел объявления переменных

Раздел объявления переменных служит для определения всех переменных, используемых в текущем и всех вложенных блоках.Раздел_объявления_переменных::=

"VAR" 1{ объявление_переменных }.Объявление_переменных::=

ИД_перем { "," ИД_перем } ":" тип [местоположение]";".Местоположение::= "absolute" (адрес | ИД_переменной)

Тип переменной указывает набор значений, которые она может принимать и действия, которые могут быть над ней выполнены. В ТП определено множество различных типов, из которых в этом параграфе мы рассмотрим только один из целочисленных, один из вещественных и логический: INTEGER является типом с диапазоном значений от -32768 до 32768, занимающим 2 байта памяти. REAL является вещественным типом с диапазоном значений от 2 .9⋅10−39 до 1 . 7⋅1038 в положительной области и с таким же диапазоном в отрицательной. При этом количество значащих десятичных цифр 11-12 при 6 байтах занимаемой памяти. BOOLEAN представляет собой логический тип и имеет только 2 значения - true(истина) и false(ложь). Логические типы используется по большей части в условных операторах, которые позволяют выполнить то или иное действие в зависимости от значения выражения логического типа, а также в операторах цикла, которые повторяют один или группу операторов до тех пор пока выражение логического типа не примет значение true или false (в зависимости от типа цикла).

Местоположение позволяет определять абсолютные переменные. Если после слова absolute стоит адрес памяти в виде СЕГМЕНТ:СМЕЩЕНИЕ (например $40:$17), это означает адрес расположения абсолютной переменной в памяти компьютера. Если после absolute находится имя ранее определенной переменной, то и эта переменная и абсолютная будут ссылаться на одну и ту же область памяти.

Пример раздела объявления переменных:Var x, y : integer;k1:integer absolute $40:$17;xx:integer absolute x;Z:real; bool:boolean;

B123FG_34, XXX, yyy : integer;MyVar, Temporary_Variable : real;

В данном примере, обращаясь к переменной X, мы будем автоматически обращаться к значению

27

Page 28: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Тело программы.

переменной XX и наоборот. А обращаясь к переменной K1, мы будем обращаться к ячейке памяти по адресу $40:$17, в которой находится статус нажатия таких клавиш, как Alt, Shift, Ctrl, а также статус режимов Scroll Lock, Num Lock и Caps Lock.

Раздел объявления констант.

Константа - это именованное, рассчитываемое при компиляции и неизменяемое в процессе работы программы значение.

Типированная константа - это переменная, инициализируемая первоначальным значением в разделе объявления констант.Раздел_объявления_констант:=

"CONST" 1{ объявление_констант }.Объявление_ констант::=

ИД_константы [":" тип] "=" значение_константы ";".ИД_константы - это идентификатор (имя) константы.Если при объявлении константы используется тип, то константа является

типированной.Значение константы должно представлять собой выражение, которое можно

вычислить еще во время компиляции программы, до ее запуска.Пример:Var a,b:integer;Const X=7+2;Y=6-x*2;Z=A+x+y; { Неверно! A является переменной с неизвестным в момент компиляции

значением, поэтому не может быть использована для расчета константы}CS:integer=5+x; {типированная константа}D=CS+X; { Неверно! Несмотря на то что значение типированной константы CS известно

во время компиляции, оно может изменяться в процессе работы программы. Однако значение константы D должно оставаться постоянным, что невозможно при изменяемости CS }

Раздел объявления процедур и функций.

В разделе объявлений также можно определить пользовательские процедуры и функции. Более подробно данный пункт мы рассмотрим в параграфе , а здесь коротко разберем их заголовки.

Заголовок любой процедуры выглядит следующим образом:Заголовок_процедуры ::= "procedure" ИД

["(" объявление_параметра {";" объявление_параметра }")"] ";".

объявление_параметра::=["var" | "const"] список_ИД [":" тип_параметра].

Если в объявлении формального параметра присутствует зарезервированное слово VAR, то процедуре в качестве этого параметра может передаваться только переменная, так как во время выполнения процедура будет сама помещать в нее и возвращать основной программе значение. Если VAR или CONST отсутствует, то

28

Page 29: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Тело программы.

передаваться может любое выражение соответствующего типа. Если отсутствует тип параметра и в пояснении к процедуре он специально не оговорен, то передаваться может переменная любого типа. Формальные параметры, предваряемые зарезервированным словом CONST мы рассмотрим в параграфе 1.10.2.

Пример: В модуле Graph определена следующая процедура для инициализации графического

режима:procedure InitGraph( var GraphDriver:Integer;

var GraphMode: Integer;PathToDriver: string);

При вызове процедуры ей передаются три параметра - два целочисленных и один строковый. Первые два параметра обязаны быть переменными, третий - произвольным строковым выражением:

var a,b:integer;begin a:=0; InitGraph(a,b,'c:\bgi'); …end.Процедура InitGraph при таком вызове проанализирует графическую подсистему,

установит максимально возможный графический режим, считав файл графического драйвера из подкаталога 'c:\bgi' и возвратит в переменной a номер видеоадаптера, а в переменной b - номер установленного графического режима.

Заголовок функции несколько отличается от заголовка процедуры:Заголовок_функции ::= "function" ИД

["(" объявление_параметра {";" объявление_параметра }")"] ":" ИД_типа ";".

Идентификатор типа, стоящий после двоеточия, определяет тип возвращаемого функцией значения.

Пример:Заголовки функций Sin и Cos выглядят следующим образом:function Sin(X: Real): Real;function Cos(X: Real): Real;Функции принимают в качестве аргумента угол в радианах (вещественный) и возвращает в

качестве результата синус и косинус этого угла (также вещественный).var x:real;begin x:=0.5; writeln(sin(x)*sin(x)+ cos(x)*cos(x)); x:=0.7; writeln(sin(x)*sin(x)+ cos(x)*cos(x)); x:=1.97; writeln(sin(x)*sin(x)+ cos(x)*cos(x)); readln; {для задержки}end.Предскажите значения чисел, которые появятся на экране после выполнения программы.

29

Page 30: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Примеры небольших программ

1.5.4 Примеры небольших программНа данный момент нам известно уже достаточно, чтобы составить несколько

небольших программ.Задача 1 [1, № 31]. Дано действительное число A. Не пользуясь никакими операциями, кроме умножения, получить A6 за 3 операции.

Решение:Для решения данной задачи нам потребуется промежуточная переменная, так как простым

умножением мы сможем получить A6 только за 5 операций, а не за 3, как требуется по условию задачи.

Var A,B:real;begin readln(a); b:=a*a; {первая операция} b:=b*b*b; {еще две операции} writeln(b);readln;end.

Задача 2 . Даны действительные числа X и Y. Найти: sin x y *cos xy sin x y cos x y tg x y

Решение:Решение данной задачи не представляет особой сложности. Однако для ускорения работы

программы требуется избежать "холостого" выполнения, подсчета выражений, уже вычисленных. Поэтому мы вводим несколько переменных, отвечающих за промежуточные результаты.

PROGRAM Calc; VAR rXY,rX,rY,rSinXY,rCosXY:Real; BEGIN readLn(rX); readLn(rY); rXY:=rX+rY; rSinXY:=sin(rXY); rCosXY:=cos(rXY); WriteLn((rSinXY*rCosXY)/(rCosXY+rSinXY+(rSinXY/rCosXY))); readln; END.

Задача 3 . Треугольник задан своими сторонами. Найти площадь окружности, описанной около треугольника.

Решение:Для решения данной задачи нам потребуется несколько математических формул, чтобы

свести площадь описанной около треугольника окружности к его сторонам.

Sокр=π R2 ; R=abc

4⋅Sтр;

Sтр= p p−a p−b p−c ; p=12abc

Теперь можно составить программу (опишем ее подробнее, чем предыдущие):var a,b,c,p,s,r:real; {определяем требуемые переменные} const Pi=3.1415926; {определяем константу Pi}begin

30

Page 31: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Примеры небольших программ

readln(a,b,c); { вводим стороны треугольника} p:=(a+b+c)/2; { находим полупериметр} s:=sqrt(p*(p-a)*(p-b)*(p-c)); {находим площадь треугольника

SQRT - функция длявычисления квадратного корня}

writeln('Площадь треугольника = ',s); r:=(a*b*c)/(2*s); { находим радиус описанной окружности } s:=pi*r*r; { присваиваем переменной S площадь описанной окружности} WRITELN('Площадь описанной вокруг тр-ка окр-ти = ',s); readln;

end.В решенных здесь задачах мы придерживались различных стилей написания

программ, чтобы показать, насколько либерально ТП относится к индивидуальным особенностям программиста. В дальнейшем Вы можете выбрать один из предложенных или изобрести свой собственный стиль, но при этом, как мы советуем Вам из опыта работы, старайтесь соблюдать следующие правила:

1. Всегда делайте некоторый отступ вправо внутри составного или любого другого структурного оператора.

2. Называйте свои переменные, константы, процедуры и т.д. удобочитаемыми именами.

3. Не создавайте программные блоки размером более 50 (а лучше - 25) строк, разбивайте программу на небольшие, логически завершенные части.

Задачи для раздела "Структура программы"Задание 5. Какие из нижеперечисленных наборов символов являются комментариями?

1) {предполагаю, что (* это } комментарий *)2) (* {} это {} уж {} точно {} комментарий {}*)3) { комментарий :-) Комментарий ;-) КОММЕНТАРИЙ *) }4) { remark :-} Remark ;-} REMARK :-{}

Задание 6. Какие из нижеперечисленных наборов символов являются синтаксически верными вызовами процедур?

1) Proc1(123; 7; 32)2) x:=3*sin(3)3) Ps()4) X1(3,5,v)

Задание 7. Напишите программу, в которой будет 3 раздела объявления переменных 1 раздел объявления констант.Задание 8 [1, № 1]. Даны два числа. Найти их сумму, разность и произведение. Задание 9 [1, № 3]. Дано ребро куба. Найти объем куба и площадь его боковой поверхности.Задание 10. В электрической цепи находятся четыре резистора с сопротивлениями R1, R2, R3 и R4. Определить общее сопротивление цепи.Задание 11 [1, № 31]. Дано число a. Вычислить a64 за 6 операций.Задание 12. Даны числа r1 и R2 (r1<R2). Определить площадь кольца, внутренний радиус которого равен r1, а внешний - R2.

31

Page 32: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Выражения

1.6 ВыраженияВыражением называется вычисляемая структура, возвращающая значение

некоторого типа.Выражения в программирование пришли из математики, видоизменяясь с

учетом требований конкретного языка. Практически все языки программирования, кроме тех, которые рассчитаны на применение в алгебре или математическом анализе, предполагают, что любое выражение будет состоять из одной строки.

Пример:

Выражение x x y

sin25 z cos x

sin2 x, записанное на ТП, может выглядеть следующим образом:

x*sqrt(x+y)/sin(25*x)+sqrt(cos(x)/sqr(sin(x)))

1.6.1 Структура выраженийВ ТП выражения строятся из операций и операндов. Операнды могут быть

переменными, константами, результатами вызова функций, и также выражениями. Большинство операций в ТР являются бинарными, то есть действуют на 2 операнда, стоящих слева и справа от операции. Некоторые операции являются унарными, то есть действуют на операнд, стоящей за операцией. Выражение может содержать и только один операнд, то есть константа или переменная также являются выражением в его максимально вырожденном виде.

Пример:Рассмотрим следующее выражение:

1.6.2 Приоритет операцийДля правильного формирования выражения очень важна расстановка скобок.

В их отсутствие порядок выполнения зависит от приоритета операций.

Операции Приоритет Вид операции

32

x + y

Операнд Операция Операнд

*x

Операнд ОперацияОперанд-выражение

( )

Page 33: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Приоритет операций

@, not первый (высший) унарные операции*,/,div,mod, and,shl,shr

второй операции умножения

+,-,or,xor третий операции сложения=, <>, <, >,<=,

>=, inЧетвертый (низший)

операции отношения

1.6.3 Типы операцийВ ТП существует 6 типов операций:

Операции ::= арифметические_операции |логические_операции | строковые_операции | операции_над_множеством |операции_отношения |операция_@

1.6.3.1 Арифметические операцииАрифметические_операции::= "+" | "-" | "*" | "/" | "div" | "mod".Арифметические операции действуют только на целочисленные и

вещественные выражения. div и mod - только на целочисленные.Операция div используется для целочисленного деления, при этом дробная

часть результата отбрасывается.Пример: результатом выражения 5 div 3 будет число 1.Операция mod используется для нахождения остатка от целочисленного

деления.Пример: 5 mod 3 = 2, 1 mod 10 = 1, 11 mod 10 = 1,.32 mod 11 = 10.При воздействии арифметических операций на значения различных типов

результат приводится к более широкому из них. При воздействии на значения одинаковых типов результат получается того же типа. Исключение - арифметическая операция "/" - результат ее действия всегда вещественный.

Пример:Выражение 7/2 даст результат 3.5. Выражение 12/4 даст результат 3.0 (вещественный), а не

3 (целочисленный).Операции "+" и "–" могут быть также унарными.Пример:Если B - целочисленная или вещественная переменная, то выражения -b и +b совершенно

правомерны.

1.6.3.2 Логические операцииЛогические_операции::= "not" | "and" | "or" | "xor" | "shl" | "shr".Операция not является унарной.Логические операции могут производить действия над целочисленным

33

Page 34: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Логические операции

(побитовые операции) и логическим типом. shl и shr - только над целочисленным типом (побитовый сдвиг влево и вправо на целое количество бит). Наиболее часто первые четыре операции используются для формирования сложных логических выражений в условных и циклических операторах (см. параграф 1.8.2). Операции shl и shr используются чаще всего для быстрого деления и умножения целых чисел на степени двойки (2, 4, 8, 16, 32 и т.д.).

1.6.3.3 Строковые операцииСтроковые_операции::= "+";Данная строковая операция производит контактенцию строк. В качестве

операндов могут служить строковые, символьные и упакованные строковые значения.Пример: Для создания длинных строк можно использовать операцию "+"

...Writeln('Вначале Он сотворил Аинур, Первых Святых,'#13#10 +

'Порождение Его мысли,'#13#10 +'И они были при Нем уже тогда,'#13#10 +'Когда еще ничего другого не было.');

...{Джон Рональд Руэл Толкиен. "Сильмариллион"}

1.6.3.4 Операции над множествомОперации_над_множеством::= "+" | "-" | "*".Бинарные операторы, которые выполняют соответственно объединение,

разность и пересечение множеств.Операции над множеством мы подробно рассмотрим в параграфе -------.

1.6.3.5 Операции отношенияОперации_отношения::= "="| ">"| "<"| "<>"| ">="| "<="| "in".Операндами операций "=", ">", "<", "<>", ">=", "<=" могут быть простые и

строковые типы, для операций "=" и "<>" также типы указателя и множества, для операций "<=", ">=", "in" - множественный тип. Типы операндов должны быть совместимыми (см. параграф 1.9.6). Единственное исключение из этого правила - разрешается сравнение целочисленных и вещественных операндов.

Результат действия операций отношения - всегда логический.Операции отношений возвращают TRUE (истину) при выполнении

следующих условий:Операция Название Выполняемое условие

= Равно Левый операнд равен правому> Больше Левый операнд больше правого< Меньше Левый операнд меньше правого

<> не равно Левый операнд не равен правому>= 1)больше либо равно Левый операнд больше или равен правому. Если

34

Page 35: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операции отношения

2)надмножество операнды являются совместимыми типами множеств, то левое множество представляет собой надмножество правого

<= 1)меньше либо равно 2) подмножество

Левый операнд меньше или равен правому. Если операнды являются совместимыми типами множеств, то левое множество представляет собой подмножество правого

in Вхождение во множество

Левый операнд входит во множество, представленное правым операндом

Пример:var b:boolean; beginb:=5>2;writeln(b);

end.В результате выполнения программы на экране появится слово TRUE.

1.6.3.6 Операция @С помощью операции @ можно создать указатель на переменную, процедуру

или функцию, то есть получить адрес ее местоположения в памяти. Операция является унарной.

Более подробно эта операция будет рассмотрена в параграфе 1.9.3.

Задачи для раздела "Выражения"Задание 13. Сгруппируйте каждую операцию отношения (кроме in), с обратной для нее. Задание 14. Сократите логическое выражение: not(a>b) and not (a<c)Задание 15. Предскажите результат вычисления следующего выражения: -2+3*6-12/6. Каким образом надо расставить скобки. чтобы получить число -1?Задание 16. С помощью только одного вызова процедуры Writeln, 20 раз написать на экране фразу "Ничего на свете лучше нету, чем писать программы "на лету" ".Задание 17. Дано трехзначное натуральное десятичное число. Используя операции div и mod, выделить цифры числа и напечатать его в столбик.Задание 18. Дано натуральное число А. Не используя арифметические операции, увеличить его в 16 раз.Задание 19. Не используя арифметические операции преобразуйте число 7 в 56, 56 - в 14, а 14 - в 224.Задание 20. С помощью арифметических операций поменяйте местами содержимое двух вещественных переменных, не используя третью, промежуточную переменную.

35

Page 36: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Стандартные функции и процедуры

1.7 Стандартные функции и процедурыТурбо-Паскаль содержит множество стандартных функций и процедур,

сосредоточенных в модуле system.tpu (который по умолчанию находится в библиотеке turbo.tpl, но может быть выделен оттуда и использован отдельно).

В этом параграфе мы рассмотрим общие функции и процедуры, не имеющие привязки к какому либо разделу нашего пособия. Остальные будут проанализированы в соответствующих параграфах (например функции и процедуры работы со строками - в параграфе "Строковые типы", функции и процедуры работы с динамической памятью - в параграфе "Указатели" и т.д.)

1.7.1 Процедуры и функции модуля System

1.7.1.1 Арифметические функцииФункция или процедура Действие

Тригонометрические функцииf. ArcTan(X: Real): Real; Возвращает арктангенс аргументаf. Cos(X: Real): Real; Возвращает косинус аргументаf. Sin(X: Real): Real; Возвращает синус аргумента

f. Pi: Real; Возвращает число Пи:3.1415926535897932385

Функции для выделения целой и дробной части числаf. Frac(X: Real): Real; Возвращает десятичную часть аргументаf. Int(X: Real): Real; Возвращает целую часть аргумента.

Логарифмическая и экспоненциальная функцииf. Ln(X: Real): Real; Возвращает натуральный логарифм аргумента.f. Exp(X: Real): Real; Возвращает экспоненту аргумента

Степенные функции

f. Sqr(X: тип):тип; Возвращает квадрат аргумента. Тип результата соответствует типу аргумента.

f. Sqrt(X: Real): Real; Возвращает квадратный корень аргументаАбсолютное значение

f. Abs(X:тип):тип;Возвращает модуль аргумента. Тип результата соответствует типу аргумента.

В отличии, например, от языка программирования Бейсик, ТП содержит очень небольшой объем арифметических функций. С помощью несложных операций он может быть расширен.

ab = exp(b*ln(a)); {а в степени b}logab=ln(b)/ln(a); {логарифм по произвольному основанию}Tan(x) = sin(x)/cos(x); {тангенс x}сTan(x) = 1/tan(x); {арктангенс x}Arcsin(x)=arctg(x/sqrt(1-sqr(x))); {арксинус x}Arccos(x)=Pi/2-arcsin(x); {арккосинус x}

36

Page 37: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Арифметические функции

Arcctan(x)= Pi/2-arctan(x); {арккотангенс x}Ch(x)=(exp(x)+exp(-x))/2; {гиперболический косинус x}Sh(x)=(exp(x)-exp(-x))/2; {гиперболический синус x}

1.7.1.2 Процедуры выходаТП содержит в модуле system три процедуры выхода, позволяющие аварийно

завершит программу или блок.procedure Exit

Процедура Exit немедленно завершает работу текущего блока. Если текущий блок - программа, то происходит выход из нее.

procedure Halt [ ( Exitcode: Word ) ];Процедура Halt производит выход из программы с кодом завершения ExitCode.

procedure RunError [(Errorcode: Byte)];Процедура RunError производит выход из программы, эмулируя ошибку времени выполнения с номером Errorcode.

Процедура Exit чаще всего используется для выхода из процедур и функций.Процедура Halt - для остановки программы с целью передачи операционной

системе кода завершения, который затем может быть проанализирован, например, с помощью оператора BAT-файла :IF ErrorLevel код завершения ...

Процедура RunError применяется обычно для отладки программы. Ее использование позволяет наиболее простым методом определить место ошибки, а также проверить реакцию программы на критические ситуации.

1.7.1.3 Обработка больших объемов данных (до 64К)procedure FillChar(var X; Count: Word; value)

Процедура FillChar заполняет переменную или произвольную область памяти X значением Value любого типа (размером в 1 байт), в количестве Count байт

procedure Move(var Source, Dest; Count: Word);Процедура Move копирует область памяти Source в Dest размером в Count байт.

Процедуры FillChar и Move удобно использовать для обработки массивов и любых других объемных типов данных (записей, строк и т.д.). Например, с помощью FillChar можно обнулять или заполнять массивы предопределенным значением, с помощью Move – копировать один массив в другой, даже при несовместимых типах данных источника и приемника.

При использовании этих процедур следует быть максимально осторожным, так как ни одна из них не проверяет корректность выполняемых операций. Например – можно заполнить нулями область системных переменных, скопировать массив в область кода программы и т.д. Результатом таких действий бедет неправильная

37

Page 38: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Обработка больших объемов данных (до 64К)

работа или (чаще всего) "зависание" программы.

1.7.1.4 Манипуляция байтами одного словаfunction Hi(X): Byte;

Функция Hi возвращает старший байт аргумента. X должна быть переменной типа integer или word (см. параграф 1.9.1.1).

function Lo(X): Byte;Функция Lo возвращает младший байт аргумента. X должна быть переменной типа integer или word (см. параграф 1.9.1.1).

function Swap(X:тип): тип;Функция Swap меняет в аргументе младший и старший байт местами и возвращает полученный результат. Переменная X должна быть любого порядкового двухбайтного типа (см. параграф 1.9.1.1)

Указанные функции чаще всего используются в системном программировании, где очень часто требуется получать доступ отдельным байтам многобайтовых значений.

1.7.1.5 Генератор случайных чиселfunction Random [( Range: Word)]: тип

Функция Random возвращает:1) Случайное вещественное число из промежутка (0,1) (В случае, если

Range отсутствует. При этом тип результата – Real)2) Случайное натуральное число (или 0) из промежутка [0, Range) (В

случае, если Range передается в качестве аргумента. При этом тип результата – Word)

procedure Randomize;Процедура Randomize инициализирует генератор случайных чисел. После вызова этой процедуры Random будет возвращать другую последовательность случайных чисел.

Генератор случайных чисел будет нами использоваться при решении многих задач. Рассмотрим несколько приемов для получения случайных значений из выбранного промежутка:

Присвоить переменной X случайное целочисленное значение из промежутка [-10, 17].

Генератор случайных чисел может возвращать случайное значение только из положительной области. Поэтому алгоритм решения этой задачи будет состоять из трех шагов: 1) определить размер промежутка, 2) получить случайное значение из положительного промежутка рассчитанного размера, 3) осуществить "сдвиг" полученного значения для совмещения промежутков.

Решение: X:=random(28)-10

Присвоить переменной X случайное вещественное значение из промежутка (1.2, 3.7).

Воспользуемся предыдущим приемом:

38

Page 39: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Генератор случайных чисел

Решение: X:=random*(3.7-1.2)+1.2

Учтите, что в первом случае переменная X должна быть целочисленной, а во втором – вещественной.

1.7.1.6 Границы и размеры типов данныхfunction High(X):тип

Функция High возвращает максимальное значение аргумента. Если переданный параметр является строкой или массивом, то возвращаемый результат - максимальная длина строки или массива. Если же переданное значение имеет порядковый тип, то возвращаемое является верхней границей диапазона данного типа.

function Low(X):типФункция Low возвращает минимальное значение аргумента. Если переданный параметр является массивом, то возвращаемый результат - минимальный индекс массива. В случае передачи строки возвращаемое значение = 0. Если же переданное значение имеет порядковый тип, то возвращаемое является нижней границей диапазона данного типа.

function SizeOf(Аргумент):integer;Функция SizeOf возвращает размер аргумента в байтах. Передаваемый в функцию параметр может быть как переменной, так и типом данных

Данный набор функций применяется для универсализации разработки программ. При обработке структур данных вместо конкретных числовых размеров или границ переменных можно использовать функции low, high и sizeof, что позволит значительно сократить количество изменений в программе при изменении, размеров или типа обрабатываемых структур. Например, при заполнении в цикле массива A случайными значениями, вместо нижнего и верхнего индекса массива можно указать соответственно low(A) и high(A). Таким образом, этот участок программы останется неизменным при любых изменениях в размерах или индексации массива A.

1.7.1.7 Обработка параметров командной строкиПараметры командной строки

function ParamCount: Word;Функция ParamCount возвращает количество аргументов, переданных программе в командной строке DOS при ее запуске.

function ParamStr(Index:byte): String;Функция ParamStr возвращает параметр командной строки с порядковым номером Index. Параметр с номером 0 - это полное имя самой программы.

При разработке консольных утилит большое значение имеют возможность обработки передаваемых в программу параметров. Например, при создании программы копирования файлов (аналог команды copy), требуется получить доступ

39

Page 40: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Обработка параметров командной строки

к имени исходного и результирующего файлов, передаваемых в программу. Это можно сделать вызовами ParamStr(1) и ParamStr(2) соответственно. Имя самой программы и каталог ее запуска можно узнать вызовом ParamStr(0) и дальнейшей обработкой полученного значения.

1.7.1.8 Обзор дополнительных процедур и функций Строковые процедуры и функции будут рассмотрены в параграфе 1.9.2.2.Процедуры и функции ввода-вывода, а также процедуры для работы с

файлами будут рассмотрены в параграфе 1.9.2.5.Процедуры и функции для работы с указателями и динамической

памятью будут рассмотрены в параграфе 1.9.3.При изучении типов также будет рассмотрено несколько процедур и функций,

ассоциированных с конкретными типами данных.

1.7.2 Процедуры и функции модуля CrtМодуль Crt содержит множество процедур и функций, поддерживающих

работу с экраном и клавиатурой в обход стандартных потоков ввода-вывода. Это дает возможность получения высокоскоростного доступа в произвольную точку экрана, посимвольное чтение данных с клавиатуры с задержкой и без нее, а также многое другое. К сожалению, при использовании модуля crt программа теряет доступ к возможностям конвейеризации и перенаправления данных операционной системы.

Обработка клавиатурыfunction KeyPressed: Boolean;

Функция KeyPressed возвращает True, если произошло нажатие клавиши.function ReadKey: Char;

Функция ReadKey возвращает символ с клавиатуры, ожидая нажатия.Окна

procedure Window(X1, Y1, X2, Y2: Byte);Процедура Window устанавливает окно на экране. Весь дальнейший вывод и ввод информации происходит в его пределах. В качестве параметров передаются координаты левого верхнего и правого нижнего углов

procedure ClrScr;Процедура ClrScr очищает текущее окно.

ЦветаТП определяет в модуле Crt 15 констант для цветов текстовых режимов, плюс атрибут мигания, который для требуемого эффекта суммируется с цветом тона.Константы тона и фона:Black=0, Blue=1, Green=2, Cyan=3, Red=4, Magenta=5, Brown=6, LightGray=7;

40

Page 41: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедуры и функции модуля Crt

Константы тона:DarkGray=8, LightBlue=9, LightGreen=10, LightCyan=11, LightRed=12, LightMagenta=13, Yellow=14, White=15;Атрибут мигания: Blink=128

procedure TextBackground(Color: Byte);Процедура TextBackground устанавливает цвет фона

procedure TextColor(Color: Byte);Процедура TextColor устанавливает цвет тона

procedure NormVideo;Процедура NormVideo устанавливает стандартный цвета тона и фона.

procedure HighVideo;Процедура HighVideo устанавливает повышенную яркость символов.

procedure LowVideo;Процедура LowVideo устанавливает пониженную яркость символов.

Позиционирование курсораprocedure GotoXY(X, Y: Byte);

Процедура GotoXY устанавливает курсор в позицию X,Yfunction WhereX: Byte;

Функция WhereX возвращает текущую координату X курсора.function WhereY: Byte;

Функция WhereY возвращает текущую координату Y курсора.Экранные строки

procedure ClrEol;Процедура ClrEol очищает все символы, начиная с позиции курсора до конца строки.

procedure DelLine;Процедура DelLine удаляет строку, на которой находится курсор, все нижележащие поднимаются выше.

procedure InsLine;Процедура InsLine вставляет пустую строку по позиции курсора, все нижележащие опускаются ниже.

Звукиprocedure Sound(Hz: Word);

Процедура Sound включает внутренний динамик с частотой звука Hz герц.procedure NoSound;

Процедура NoSound выключает внутренний динамикРазличные процедуры

procedure TextMode(Mode: Integer);Процедура TextMode устанавливает текстовый режим экрана.В модуле Crt определен следующий набор констант режимов экрана: BW40=0, черно-белый режим 40x25

41

Page 42: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедуры и функции модуля Crt

CO40=1, цветной режим 40x25 BW80=2, черно-белый режим 80x25 CO80=3, цветной режим 80x25 Mono=7, монохромный режим 80x25

procedure AssignCrt(var f: Text);Процедура AssignCrt сопоставляет текстовый файл с экраном. Таким образом весь дальнейший ввод или вывод в текстовый файл будет перенаправляться на экран.

procedure Delay(MS: Word);Процедура Delay приостанавливает работу программы на MS тиков.

Задачи для раздела "Процедуры и функции модуля Crt"При решении всех задач данного модуля желательно в начале программы очищать экран. Выход из каждой программы - по нажатию на любую клавишу.Задание 21. Ввести X и Y координаты курсора. Перевести курсор в позицию X и Y и вывести на экран желтым цветом (Yellow) слово "ЗДЕСЬ!".Задание 22. Всеми цветами вывести на экран фразу "Паскаль - ЧЕМПИОН!".Задание 23. Вывести на экран ваше любимое четверостишие. С промежутком примерно в секунду, стереть его построчно с экрана, начиная с первой строки.Задание 24. В центре экрана создать окно размером 6 строк на 50 столбцов. Затем решить предыдущую задачу.Задание 25. Вывести на экран фразу "Жизнь - это движение!". Передвинуть ее на 10 строк вниз с задержкой в 0.25 секунды на каждой строке. Затем аналогичным образом привести ее в первоначальное положение.Задание 26. Попытайтесь сыграть музыкальную гамму. Время звучания каждой ноты - полсекунды.

42

Page 43: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы

1.8 ОператорыОператоры, как было уже сказано в параграфе 1.1, представляют собой

действия, выполняемые программой. ТП определяет набор операторов, которого вполне достаточно для реализации любых конструкций языков программирования.

Оператор::=[метка ":"] [(простой_оператор | структурный_оператор )]Перед каждым оператором может находится метка, используемая для

перехода в эту точку программы из другой точки с использование оператора перехода.

1.8.1 Простые операторыПростой_оператор::=оператор_присваивания |

оператор процедуры | оператор перехода.

Оператор присваивания и оператор вызова процедуры были подробно разобраны в параграфе 1.5.

Оператор перехода позволяет передать управление оператору, которому предшествует метка. Любая метка, используемая в блоке, должна быть в этом блоке и объявлена. Для этого требуется воспользоваться разделом объявления меток (см. параграф 1.5).

Раздел_объявления_меток:= "LABEL" Метка {"," Метка}";".Оператор_перехода::= "goto" метка.

Например:label xxx1,12;var x:integer;begin

…xxx1: x:=7;

…goto 12;…

12:x:=x+1;goto xxx1;…

end.Не допускаются переходы из одного блока в другой, вне зависимости от его

уровня вложенности.Оператор goto позволяет легко перемещаться по программе, однако

злоупотребление им приводит к нежелательным результатам. Применение goto ухудшает читабельность программы, создает значительные трудности при попытках анализа ее структуры, затрудняет отладку и тестирование, является источником трудноуловимых ошибок. В разделах математики, посвященных программированию, доказывается, что ЛЮБАЯ программа может быть создана без использования оператора goto. Применяйте goto только в тех случаях, когда с его

43

Page 44: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Простые операторы

помощью можно значительно сократить размер программы.

1.8.2 Структурные операторыСтруктурные операторы отличаются от простых тем, что содержат обычно в

своем теле один или более других операторов.Структурный_оператор::= составной_оператор |

условный_оператор | оператор_цикла | оператор_With.

В этом параграфе мы рассмотрим только условные операторы и операторы цикла. Составной оператор был введен ранее при анализе общей структуры программы (см. параграф 1.5), а оператор With, используемый для ускорения доступа к переменным типа запись, мы разберем позднее, при описании этого типа в параграфе 1.9.2.3.

1.8.2.1 Условные операторыУсловные операторы позволяют выбирать для выполнения один или не

одного оператора из двух или из списка.Условный оператор ::= "оператор_if"| "оператор_case"

Оператор IF

Оператор_if::= "if" логическое_выражение "then" оператор1 ["else" оператор2]

Если логическое выражение принимает значение True, то выполняется оператор1, иначе - оператор2.

Например:Задача 4 . Дано 2 числа. Найти наибольшее из них.

Решение:var a,b:integer;begin readln(a,b); {вводим 2 числа с клавиатуры }

{находим максимальное и выводим его на экран} if a>b then writeln(a) else writeln(b); readln;end.

Задача 5 . Найти максимальное из трех чисел.Решение:var a,b,c,z:integer;begin readln(a,b,c); if a>b then z:=a else z:=b; {переменной z присваиваем максимальное

из двух первых чисел}{сравниваем z с третьим числом и выводим максимальное на экран} if z<c then z:=c;

44

Page 45: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Условные операторы

writeln(z); readln;end.

Задача 6 . Определить, поместится ли открытка со сторонами a и b в конверте со сторонами x и y.

Решение:var a,b,x,y:integer;begin write('Введите через пробел стороны открытки '); readln(a,b); write('Введите через пробел стороны конверта '); readln(x,y);{ Воспользуемся при формировании логического выражения в условном операторе операциями AND и OR} if ((a<x)and(b<y))or((b<x)and(a<y)) then

writeln('Открытка помещается в конверт')else

writeln('Открытка в конверт не входит');readln;end.

Задача 7 . Решить квадратное уравнение ax2+bx+c=0Var a,b,c:real; {коэффициенты уравнения}

d:real; {дискриминант}x1,x2:real; {корни уравнения}

BeginReadln(a,b,c); {вводим коэффициенты}If a=0 then

writeln('Уравнение не является квадратным')Else begin

{находим дискриминант}D:=sqr(b)-4*a*c;{проводим анализ дискриминанта и требуемые вычисления во вложенных операторах IF}If d<0 then

writeln('Уравнение не имеет действительных корней')else if d=0 then begin

x1:=-b/(2*a);writeln('Уравнение имеет 1 корень: X=',x1:7:3);

endelse begin

x1:=(-b+sqrt(d))/(2*a);x2:=(-b-sqrt(d))/(2*a);writeln('Уравнение имеет 2 корня:');writeln(' X1=',x1:7:3);writeln(' X2=',x2:7:3);

end;end;readln;

end.

45

Page 46: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Условные операторы

Оператор CASE

В программировании очень часто возникают ситуации, когда требуется провести выбор из достаточно большого количества вариантов. В ТП для этих целей служит оператор case.

Оператор case состоит из выражения (селектора) и списка операторов, каждому из которых предшествует одна или более констант (они называются константами выбора) или ключевое слово else.

Оператор_case::= "case" выражение_селектор "of" выбор {";"выбор}["else" оператор [";"]]

"end"выбор::=константа [".." константа]

{"," константа [".." константа]} ":" операторСелектор должен иметь порядковый тип размера байт или слово (о

порядковых типах будет рассказано в параграфе 1.9.1.1, а сейчас момент нам достаточно знать, что тип Integer подходит под данное правило). Все константы выбора должны быть уникальными и иметь порядковый тип, совместимый с типом селектора.

Оператор case приводит к выполнению оператора, которому предшествует константа выбора, равная значению селектора или диапазону выбора, в котором находится значение селектора.

Если такой константы выбора или такого диапазона выбора не существует, то выполняется оператор, следующий за ключевым словом else. Если ветвь else отсутствует, то не выполняется никакого оператора.

Например: По введенному часу определить время суток.Var hour:integer;Begin

Readln(hour);Case hour of

0,24:writeln('Полночь');12: writeln('Полдень');1..3: writeln(Ночь');4..10: writeln('Утро');11,13..16: writeln('День');17..11: writeln('Вечер')else writeln('Ошибка при вводе числа');

end;readln;

end.

Задачи для раздела "Условные операторы"Задание 27. Даны три целых числа. Возвести в куб те из них, значения которых кратны 3.Задание 28. Дано целое число N. Если N[-10,-5], то увеличить его в 2 раза. Получить его модуль, если N[-6,-1]. Присвоить ему единицу, если N[0,15] и обнулить N в любом другом случае.

46

Page 47: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Условные операторы

Задание 29[1, № 47]. Даны три числа a, b и с. Выяснить, существует ли треугольник со сторонами a, b и с, и если существует, то определить, является ли он остроугольным.Задание 30. Даны три числа. Вывести их на экран в порядке возрастания.Задание 31[1, № 41]. Даны три действительных числа. Вывести на экран только те из них, которые принадлежат промежутку (1,3).Задание 32[1, № 42]. Даны действительные числа x, y (x<>y). Меньшее из этих двух чисел заменить их полусуммой, а большее - их удвоенным произведением.Задание 33. Даны три целых числа a, b и с. Определить, лежит ли a в промежутке [b,c], b в промежутке [a,c], c в промежутке [a,b].Задание 34[1, № 53]. Даны действительные числа X1, Y1, X2, Y2, X3, Y3. Определить, принадлежит ли начало координат треугольнику со сторонами (X1, Y1), (X2, Y2), (X3, Y3). Для решения задачи можете воспользоваться следующими фактами: Две точки (a,b) и (c,d), не лежащие на прямой, уравнение которой sx+ty+u=0, принадлежат одной полуплоскости, если sa+tb+u и sc+td+u - числа одного знака. Уравнение прямой, проходящей через 2 точки с координатами (e,f) и (g,h) выглядит следующим образом: (x-e)(h-f)-(y-f)(g-e)=0.

47

Page 48: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

1.8.2.2 Операторы циклаОператоры цикла используются для повторения (итераций) одного или

нескольких операторов определенное количество раз.Оператор_цикла::= оператор_for | оператор_while | оператор_repeat

Цикл For

Цикл For используется для повторения оператора фиксированное количество раз.оператор_for::=

"for" управляющая_переменная ":=" начальное_значение ("to" | "downto") конечное_значение "do" оператор.Где управляющая переменная - идентификатор порядковой переменной,

начальное и конечное значения - выражения порядкового типа (см. параграф 1.9.1.1).

Управляющая переменная должна быть объявлена в том же блоке, где используется оператор цикла (например, если цикл используется внутри процедуры, управляющая переменная также должна быть определена внутри этой процедуры).

При входе в цикл начальное и конечное значения фиксируются и остаются постоянными во время выполнения цикла. Управляющая переменная инициализируется начальным значением. После окончания выполнения оператора в теле цикла производится сравнение управляющей переменной с конечным значением. Если они оказываются равны, то происходит выход из цикла, иначе – либо увеличение("to"), либо уменьшение ("downto") управляющей переменной на 1 и переход на новую итерацию цикла.

Если при входе в цикл начальное значение больше ("to"), либо меньше ("downto") конечного значения, то происходит немедленный выход из цикла без выполнения его тела.

Примеры использования цикла FOR:Задача 8 . Вывести на экран первые N натуральных чисел.

Решение:var n,i:integer;begin

readln(n);for i:=1 to n do writeln(i);readln;

end.Задача 9 . Вывести на экран первые N положительных четных чисел в обратном порядке.

Решение:var n,i:integer;begin

readln(n);for i:=n downto 1 do writeln(i*2);readln;

end.Задача 10 . Подсчитать сумму и произведение последовательности натуральных чисел из

48

Page 49: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

промежутка [N,M].Рассмотрим подробно решение задачи :var n,m,i:integer;s,p:real;

beginreadln(n,m);s:=0; p:=1; {присваиваем первоначальное значение переменным,

отвечающим за сумму и произведение }for i:=n to m do begin { открываем цикл для перебора всех

натуральных значений от N до М } s:=s+i; p:=p*i; {увеличиваем текущее значение суммы на I,

а текущее значение произведения в I раз}end; { Завершаем тело цикла. При этом значение переменной I

увеличивается на единицу и сравнивается с М. Если I>M, то происходит выход из цикла, иначе выполнениепрограммы переходит на начало тела цикла }

writeln('Сумма = ',s);writeln('Произведение = ',p);readln;

end.Задача 11 . Вычислить сумму из N слагаемых:

112

13

14

15 . . .

1N

Решение:

Для решения задачи целесообразно вывести общую формулу: ∑i=1

N1i

var i,n:integer;s:real;

beginreadln(n);s:=0;for i:=1 to n do s:=s+1/i;writeln(s);readln;

end.Задача 12 . Вывести на экран таблицу умножения.

Решение:Для решения данной задачи нам потребуется воспользоваться понятием "вложенного

цикла", которое подразумевает использование одного цикла внутри другого.var i,k:integer;begin

for i:=1 to 10 do begin {открываем внешний цикл, с помощью которого осуществляем перебор всех десяти строк}

for k:=1 to 10 do write(i*k:4); {во внутреннем цикле для каждой строки осуществляем перебор всех столбцов и выводим на экран произведение номера столбца и строки. Для выравнивания используем специальный синтаксис оператора write (см. описание вывода числовых выражений в параграфе 1.1)}

writeln; {после завершения внутреннего цикла производим переход на следующую

49

Page 50: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

строку }end;readln;

end.При использовании цикла FOR следует придерживаться следующих правил:1) Не присваивать какое-либо значение управляющей переменной внутри

цикла. В результате такого действия могут возникнуть следующие ситуации:а) Незапланированный выход из цикла (что гораздо проще организовать с помощью

процедуры break)б) "Зацикливание" - бесконечное выполнение тела цикла, и как результат -

"зависание" программы.в) Неверное количество итераций цикла.

Ниже приводится пример, иллюстрирующий типичную ошибку, связанную с непониманием функционирования цикла FOR.Задача 13 . Вывести на экран первые N нечетных чисел.

Решение:Var i,n:intеger;Begin Readln(n); For i:=1 to n do begin Writeln(i); i:=i+2; {НЕВЕРНО! Нельзя рассчитывать получить из единицы тройку, из тройки -

пятерку и т.д. таким методом внутри цикла FOR. Управляющая переменная I сама увеличивается на единицу при каждой итерации, что учетом ее изменения в данном операторе даст приращение на 3}

End; Readln;End.Результат работы этой программы зависит от введенного числа N. Если конечное значение

не кратно 3, то произойдет "зависание", так как увеличивающееся значение управляющей переменной никогда не станет равно конечному значению (естественно, рассматривая идеальный случай, когда множество натуральных чисел бесконечно, что для типа integer не так. На самом деле, выполнение цикла закончится, сделав 2-3 круга по всему типу integer, что займет значительный объем времени и бессмысленных вычислений). Если введенное значение окажется кратным 3, то выход из цикла произойдет вовремя, оставив на экране, к сожалению, отнюдь не последовательность нечетных чисел.

С помощью элементарных арифметических действий легко получить более короткое и, что самое главное, верное решение задачи:

var n,i:integer;begin

readln(n);for i:=1 to n do writeln(i*2-1);Readln;

end.2) Не изменять начальных и конечных значений управляющей переменной,

рассчитывая при этом на изменение количества итераций цикла (данное ограничение имеет смысл только при использовании переменных в качестве конечных или начальных значений).

50

Page 51: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

Задача 14 . Дано натуральное число N. Вывести на экран все натуральные числа из промежутка [1,N+X], где X - количество таких чисел из промежутка [1,N], которые кратны 3 и не кратны 5.

Типичный подход в решении такой задачи с использованием только цикла FOR состоит в подсчете в первом цикле количества чисел по правилу, определенному в условии задачи, и выводе требуемого количества чисел на экран во втором цикле. Попытки сократить программу могут привести к следующему, в корне неверному с точки зрения семантики языка, решению:

Var i,n:intеger;Begin Readln(n); For i:=1 to n do begin Writeln(i); If (i mod 3=0)and(i mod 5<>0) then n:=n+1; {НЕВЕРНО!} End; Readln;End.Увеличение значения переменной N внутри цикла не каким образом не повлияет на

количество итераций.Для решения данной задачи только с помощью цикла FOR нам потребуется несколько

увеличить объем программы:Var i,n:intеger;Begin Readln(n); For i:=1 to n do begin If (i mod 3=0)and(i mod 5<>0) then n:=n+1; End; {воспользовавшись спецификой цикла FOR, нашли требуемую верхнюю границу

промежутка, не вводя при этом дополнительных переменных}for i:=1 to n do writeln(i); {вывели на экран все натуральные числа из определенного в

условии промежутка} Readln;End.

Цикл While

Цикл While или, как его еще называют, цикл с предусловием, используется для условного повторения оператора, который называют телом цикла.

оператор_While::= "while" логическое_выражение "do" оператор.

При входе в цикл проверяется логическое выражение. Пока его значение равно True, оператора тела цикла повторяются.

Задача 15 . Вычислить бесконечную сумму ∑i=1

∞1

i3с точностью до одной сотой:

Решение:Для решения задачи нет возможности воспользоваться циклом for, так как заранее

неизвестно количество членов последовательности, сумма которых вычисляется. Поэтому используем в программе цикл while:

var i,n:integer;s,p:real;

Const Tochnost=0.01;begin

51

Page 52: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

s:=0; i:=1;p:=1/(i*i*i); {Переменной p требуется присвоить первоначальное значение перед входом в

цикл. Иначе при первом входе логическое выражение может быть рассчитано неверно }

while p>= Tochnost do begin s:=s+p; i:=i+1; p:= 1/(i*i*i);end;writeln(s);readln;

end.Задача 16 . Попробуем увеличить скорость получения последовательности натуральных чисел при решении задачи №14. Напоминаем ее условие:

Дано натуральное число N. Вывести на экран все натуральные числа из промежутка [1,N+X], где X - количество таких чисел из промежутка [1,N], которые кратны 3 и не кратны 5.

Как было показано выше, используя цикл FOR, мы не можем обойтись только одним циклом, так как во время выполнения его тела ТП не допускает изменения конечного количества итераций. Цикл WHILE более либерален в этом отношении.

Var i,n:integer;Begin Readln(n); i:=1; While i<=n do begin If (i mod 3=0)and(i mod 5<>0) then n:=n+1; Writeln(i); i:=i+1; End; Readln;End;

Цикл Repeat

Цикл Repeat или, как его еще называют, цикл с постусловием, также, как и цикл while, используется для условного выполнения операторов, находящихся в теле цикла. Его отличительной особенностью является то, что проверка условия выхода из цикла происходит после выполнения тела цикла.

оператор_Repeat::= "repeat" оператор {";" оператор } [";"] "until" логическое_выражение.

Повторение оператора заканчивается (то есть происходит выход из цикла), когда логическое выражение принимает значение True.Задача 17 . Рассмотрим задачу №15, приведенную для иллюстрации возможностей цикла while.

Напомним ее условие: Вычислить бесконечную сумму ∑i=1

∞1

i3с точностью до одной сотой:

var i,n:integer;s,p:real;

Const Tochnost=0.01;

52

Page 53: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

begins:=0; i:=1;{ в отличие от цикла while первоначальное значение промежуточного произведения не требуется рассчитывать до тела цикла,так как проверка условия производится нев начале, а в конце цикла.}repeat p:= 1/(i*i*i); s:=s+p; i:=i+1;until p<Tochnost;{ Выход из цикла произошел, когда в искомой сумме уже было учтено последнее слагаемое, значение которого меньше, чем требуемая погрешность. }writeln(s-p); { Поэтому исключаем данный член последовательности из суммы}readln;

end.Задача 18 . Решая задачу №10 при демонстрации возможностей цикла for (Подсчитать сумму и произведение последовательности натуральных чисел из промежутка [N,M]), мы рассчитывали, что, как сказано в условии задачи, введенные значения N и M будут положительны, так и что N<M. Однако при вводе значений во время выполнения программы могут быть введены как отрицательные числа и 0, так и N>M. Поэтому в самом начале программы требуется поставить фильтр ввода данных, что очень удобно сделать с помощью цикла Repeat.

...repeat write('Введите натуральные числа N и М, причем N<M'); readln(n,m);until (n>0)and(m>0)and(n<m);...Таким образом, при вводе неверных данных произойдет переход на начало цикла и

пользователю будет предложено снова организовать ввод. К сожалению, данный фильтр не защищает полностью от ошибок ввода. Например, вместо

целого числа может быть введено вещественное, числа вместо пробела могут быть разделены запятой, может быть набран просто произвольный набор символов и т.д. Такие ошибки скорее всего вызовут аварийный останов программы и для их предупреждения требуется более серьезный фильтр.

Вложенные циклы

Вложенным называется цикл, организованный внутри другого цикла. Под уровнем (или глубиной) вложенности цикла понимают количество внешних, по отношению к рассматриваемому, циклов. Виды внешнего и внутренних циклов могут не совпадать.

Например:

53

Page 54: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

Вложенные циклы используются в основном для обработки многомерных массивов (см. параграф 1.9.2.1). В то же время существует несколько достаточно больших классов задач, не связанных с массивами, но требующих для своего решения вложенных циклов.Задача 19 [1, № 330]. Дано натуральное число N. Найти все совершенные числа, меньшие чем N. Натуральное число называется совершенным, если оно равно сумме всех своих делителей, за исключением самого себя (число 6 - совершенное, так как 6=1+2+3; число 8 - не совершенное, так как 8<>1+2+4).

var n,k,i,s:integer;begin readln(n); for k:=2 to n do begin {перебираем все натуральные числа от 2 до N} s:=1; {первоначальное значение искомой суммы делителей = 1, так как 1 - делитель

любого натурального числа} for i:= 2 to k div 2 do begin {для каждого анализируемого числа K открываем цикл,

перебирающий первую половину меньших его натуральных чисел, чтобы найти и суммировать все его делители (вторую половину перебирать не имеет смысла, так как делители K там отсутствуют) }

if k mod i = 0 then s:=s+i; {суммируем делители} end; if s = k then writeln(k); {если число совершенное, выводим его на экран} end;end.При запуске этой программы и вводе, например 10000, мы получим 4 совершенных числа:

54

...for i:=1 to d*2 do begin ... for k:= i to i+5 do begin ... repeat ... while x<5 do begin ... end; ... until z<>x; ... end; ...end;...

Цикл третьего уровня

вложенности

Цикл второго уровня

вложенности

Цикл первого уровня

вложенности

Внешний цикл

Page 55: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

6284968128Примечание: Решение задачи можно оптимизировать, если учесть, что находя один

делитель числа, мы тем самым находим и второй. С учетом этого факта количество итераций внутреннего цикла снижается до K .

При работе с вложенными циклами следует иметь в виду, что наиболее ресурсоемким для ЭВМ является цикл с максимальным уровнем вложенности. Действительно, если, допустим, внешний цикл имеет 10 итераций, цикл первого уровня - 15, а цикл второго уровня - 4, то общее количество итераций тела цикла первого уровня будет 10*15=150, а второго - 10*15*4=600. Поэтому, для повышения эффективности выполнения программы следует максимально "облегчать" содержимое внутренних циклов, выносить всевозможные расчеты за их пределы.

Изменение скорости выполнения программы в зависимости от сложности внешнего и внутреннего циклов (для простоты рассмотрим только первый уровень вложенности) можно проанализировать на следующем примере:

Задача 20 . Вычислить ∑k=1

300

∑j=k

300sin ( k )sin1cos ( j )cos 1

Решение:var k,j:integer; s,sin1,sink,cos1:real; begin s:=0; for k:=1 to 300 do begin for j:=1 to 300 do begin sin1:=sin(1); cos1:=cos(1); sinK:=sin(k); s:=s+(sink+sin1)/(cos(j)+cos1); end; end; writeln(s); readln; end.Время выполнения данной программы на компьютере IBM PC с процессором Pentium-120

составляет примерно 10 секунд.Попытаемся несколько ускорить программу, вынося за пределы циклов подсчет синуса и

косинуса единицы.var k,j:integer; s,sin1,sink,cos1:real; begin s:=0; sin1:=sin(1); cos1:=cos(1); for k:=1 to 300 do begin for j:=1 to 300 do begin sinK:=sin(k); s:=s+(sink+sin1)/(cos(j)+cos1); end; end; writeln(s);

55

Page 56: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

readln; end.Время выполнения программы составит примерно 6 секунд.Покажем теперь, что при "облегчении" внутреннего цикла скорость выполнения

программы возрастет значительнее, чем при эквивалентном (и даже в несколько раз большем) "облегчении" внешнего.

Для этого во внешний цикл мы внесем извне вычисления синуса и косинуса единицы, а из внутреннего вынесем туда же в два раза более простой расчет синуса K.

var k,j:integer; s,sin1,sink,cos1:real; begin s:=0; for k:=1 to 300 do begin sin1:=sin(1); cos1:=cos(1); sinK:=sin(k); for j:=1 to 300 do begin s:=s+(sink+sin1)/(cos(j)+cos1); end; end; writeln(s); readln; end.В результате такого эксперимента скорость выполнения программы возрастет до 4 секунд.

Выбор вида цикла при решении задач

Для выбора вида цикла при решения той или иной задачи следует руководствоваться следующими правилами:

1) Если количество итераций (повторений) цикла заранее известно, выбирайте цикл FOR.

2) Если требуется, чтобы цикл сработал обязательно хотя бы один раз или проверка условия должна идти после выполнения тела цикла, выбирайте цикл REPEAT.

3) В остальных случаях выбирайте цикл WHILE.

Процедуры break и continue

Для операторов цикла существует две процедуры - break и continue. Процедура break выполняет досрочный выход из цикла. Процедура continue производит переход на следующую итерацию цикла.

В ТП версии 7.0 процедуры break и continue во многих случаях заменяют оператор goto, который в раннее часто использовали для тех же целей.Задача 21 .Определить, является ли число N простым (простым называется такое натуральное число, которое делится без остатка только на себя и на единицу)

Задачу можно решить, используя определение, то есть подсчитывая количество чисел, на которые делится N без остатка:

Var i,n,s:integer; Begin Readln(n);

56

Page 57: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

S:=0; For i:=2 to n div 2 do begin If n mod i=0 then s:=s+1; End; If s=0 then writeln('Число простое') else writeln('Число составное');end.

Искомый результат можно получить значительно быстрее, если "перевернуть" определение и рассматривать его следующим образом: "Натуральное число называется составным, если оно делится без остатка на любое другое натуральное число, кроме себя и единицы".

Var i,n:integer;Simply:boolean;

{ значение переменной Simply по завершении алгоритма равно TRUE, если введенной число является простым и FALSE в противном случае }

Begin Readln(n); Simply:=true; For i:=2 to n div 2 do begin If n mod i=0 then begin Simply:=false; Break; {определили, что число N - составное, досрочно выходим из цикла} End; End; If simply then writeln('Число простое') else writeln('Число составное');end.В общем случае время работы программы значительно уменьшается по сравнению с

первым методом решения, так как для определения, является ли N составным, достаточно найти хотя бы одно натуральное число, на которое N делится без остатка.

Задача 22 . Найти первые N простых чисел.Расширяем решение предыдущей задачи.Var i,n:integer;Simply:boolean;Num:integer; { проверяемое число }

Begin Readln(n); Num:=0; repeat Num:=Num+1; {начинаем проверку с увеличения Num.

При первом входе в цикл значение Переменной Num станет равно единице}

Simply:=true; For i:=2 to Num div 2 do begin If Num mod i=0 then begin Simply:=false; Break; End; End; If not simply then continue; {если анализируемое число не является простым, то

57

Page 58: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Операторы цикла

переходим к следующему числу, на новую итерацию цикла (к строке "Until n=0;")}

Writeln(Num); {число оказалось простым, напечатали его ...} N:=N-1; { ... и уменьшили значение счетчика}Until n=0;Readln;end.Решение трех последних задач можно серьезно оптимизировать (см. примечание к

задаче 19)

Задачи для раздела "Операторы цикла"Задание 35. Дано натуральное число N. Вычислить sin(0.1)+sin(0.2)+sin(0.3)...+sin nЗадание 36. Найти произведение цифр натурального числа.

Задание 37[1, № 77]. Дано натуральное N. Вычислить N корней

Задание 38[1, № 78]. Дано действительное число a, натуральное n. Вычислить: a(a+1)...(a+n-1)Задание 39[1, № 89]. Даны натуральные числа N и M. Используя алгоритм Евклида, найти наибольший общий делитель и наименьшее общее кратное N и M. алгоритм Евклида основан на следующих свойствах неотрицательных целых чисел: Пусть M>=N. Если N=0, то НОД(M,N)=M, иначе НОД(M,N)= НОД(N,R), где R - остаток от деления M на N. Например, НОД(15,6)= НОД(6,3)=НОД(3,0)=3.Задание 40[1, № 322]. Найти натуральное число от 1 до 10000 с максимальной суммой делителей.Задание 41[1, № 329]. Даны натуральные числа N и M. Получить все меньшие N натуральные числа, квадрат суммы цифр которых равен M.Задание 42[1, № 332]. Дано натуральное N. Указать такие неотрицательные целые X, Y, Z и T, что N=X2+Y2+Z2+T2.

58

22. . . 2

Page 59: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Типы

1.9 ТипыКаждая переменная в ТП имеет тип. От типа зависит допустимые операции

над переменной и размер памяти, ею занимаемый.Тип::= ИД_типа | простой_тип | структурный_тип | тип_указателя |

процедурный_тип.ТП позволяет программисту определять свой собственный тип, основанный

на встроенных или ранее определенных типах. Для этого используется раздел объявления типов в разделе объявлений, как было показано в параграфе 1.5.Раздел_объявления_типов:=

"TYPE" 1{ объявление_типа }.Объявление_типа::= ИД_типа "=" тип ";".

После объявления идентификатора типа его можно использовать в программе как любой встроенный тип.

Типы в программе применяются при:1. Объявлении переменных2. Объявлении типированных констант3. Объявлении формальных параметров процедур и функций 4. Приведении типов (т.е. преобразовании одного типа в другой).

1.9.1 Простой типПростые типы определяют упорядоченные множества значений и

подразделяются на два больших класса - порядковые и вещественные типы. Простой_тип::=порядковый_тип | вещественный_тип

1.9.1.1 Порядковый типТаблица порядковых типов

59

Page 60: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

Порядковые типы

Перечислимый тип

Тип поддиапазона

Встроенный порядковый тип

Целочисленный тип

INTEGER

SHORTINT

LONGINT

WORD

BYTE

Логический тип

BOOLEAN

Символьный тип

CHAR

Встроенный порядковый тип

Встроенный порядковый тип определяет все порядковые типы, свойства которых (диапазон значений, определение и т.д.) четко зафиксированы и не могут быть изменены программистом.

Целочисленный тип

Под целочисленными понимаются собственно целочисленные, а также неотрицательные типы, отличающиеся друг от друга диапазоном значением и объемом занимаемой памяти.

Таблица свойств целочисленных типов данных:Целочисленн

ый тип Диапазон возможных

значенийОбъем занимаемой

памятиЦелочисленные типы

Shortint -128 .. 127 1 байтInteger -32768 .. 32767 2 байтаLongint -2147483648 .. 2147483647 4 байта

60

Page 61: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

Неотрицательные типыByte 0 .. 255 1 байтWord 0 .. 65535 2 байта

С помощью функции ODD можно определить, является ли целочисленное значение четным или нет. Функция возвращает True, если значение, переданное ей, нечетно.

function Odd(X: Longint): Boolean;.Например:Begin Writeln(odd(10)); Writeln(odd(15));End.В результате работы этой программы на экране появится:FALSETRUE

Логический тип

Логический тип определяется зарезервированным словом boolean и имеет только 2 значения - TRUE(истина) и FALSE(ложь). Переменные логического типа - основа булевой алгебры, и все законы преобразований на основе логических операций (см. приложение и параграф 1.6.3.2) верны и в Турбо-Паскале. С их помощью можно легко, например, заменить цикл с предусловием на цикл с постусловием (если конечно предусловие не является определяющей причиной использования цикла While) и наоборот, сократить логическое выражение и т.д.

Например:1) Используя правило де Моргана (одно из правил преобразования в булевой алгебре), цикл

while not(d>5)or not (x<d) do …; можно заменить на цикл repeat … until (d>5)and (x<d);

2) Значение логического выражения (x>5)or(x=5) and (not (x>=5)) равно false вне зависимости от значения x.

Переменным логического типа можно присваивать произвольные логические выражения.

Например:var a, b: boolean;

x, y: integer; begin … a:=(x>7)or not(y<x) and (y<>0); b:=a or (x=y); a:=b and a; … end.При переводе логического значения в целочисленное, для false мы получим

число 0, для true - 1. При обратном переводе значение 0 преобразуется в false,

61

Page 62: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

любое другое значение - в true. Для значений логического типа всегда верно условие: TRUE>FALSE.

Например: процедура writeln(true<=false) выведет на экран слово FALSE.

Символьный тип

Любая переменная символьного типа может содержать в себе один из 256 символов набора ASCII. Объем памяти, занимаемый переменными этого типа, составляет 1 байт. Правила построения констант символьного типа соответствуют правилу построения строковых констант (см. параграф 1.4.7) с одним символом. Все операции, допустимые для строк, могут быть использованы и для типа Char.

Специально для символьного типа существует функция Chr, которая осуществляет перевод однобайтового значения в тип Char.

function Chr(X: Byte): Char;Таким образом можно легко получить символьное представление любого

числа.Пример: Var a:byte;begin repeat readln(A); writeln(chr(A)); until a=0;end.С помощью этой программы можно определить символ по его коду. Однако следует учесть,

что многие символы обладают специальными функциями и не имеют поэтому визуального отображения. Например, попытка вывести на экран символ с кодом 7 закончится гудком встроенного динамика компьютера, символ с кодом 13 означает переход на следующую строку, а с кодом 10 - в начало строки и т.д.

С помощью функции Ord можно создать программу, которая будет выводить на экран код введенного символа. При этом вместо процедуры Readln удобно воспользоваться функцией ReadKey (см. параграф 1.7.2).

Uses crt; {подключение модуля, который содержит функцию readkey}

Var c:char;begin repeat c:=readkey; writeln(ord(c)); until c=#27;end.Выполнение программы закончится, когда пользователь нажмет на клавишу ESC (код 27).

Запустив и немного поэкспериментировав с программой, можно заметить, что некоторые клавиши (например - клавиши курсора) имеют двухбайтовый код. Этот нюанс следует учитывать, разрабатывая программы, которые основаны на анализе вводимой с клавиатуры информации.

Перечислимый тип

Перечислимый тип и тип поддиапазона, в отличии от встроенных

62

Page 63: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

порядковых типов, не задаются каким либо зарезервированным словом. Диапазон значений этих типов и размер памяти, выделяемый для них, изменяется в зависимости от конкретного определения.

Перечислимый тип используется в случаях, когда диапазон значений некоторой переменной заранее известен, немногочисленнен и может быть символически описан.

Перечислимый_тип::= "(" ИД {"," ИД} ")"Например: тип week (неделя) может быть описан с помощью семи значений: monday,

tuesday, wednesday, thursday, friday, saturday, sunday.Определяем тип Week:type Week=(monday, tuesday, wednesday, thursday, friday, saturday, sunday);Идентификаторы, с помощью которых определяется перечислимый тип,

понимаются как константы внутри блока, в котором они определены. Согласно этому правилу monday является константой типа Week.Размер памяти, отводимый для перечислимого типа, зависит от количества

констант, определяющих данный тип, и может быть 1, 2 или (что совершенно невероятно!) 4 байта.

Создавая, например, на ТП компилятор или интерпретатор какого-либо алгоритмического языка, часто определяют перечислимый тип, в качестве имен констант которого служат аббревиатуры зарезервированных слов языка. Естественно, что таких слов может быть более 256, и тогда под переменную данного типа будет выделяться 2 байта оперативной памяти. Однако ситуация, когда количество констант начнет превышать число 65536 (то есть под переменную будет отведено не 2, а 4 байта) практически невозможна.

Тип поддиапазона

Тип поддиапазона используется, когда программисту для решения задачи требуется не весь диапазон значений какого-либо порядкового типа, а только его часть. Таким образом, тип поддиапазона определяется как диапазон значений некоторого порядкового типа (главного типа), причем определение поддиапазона включает наименьшее и наибольшее значения из этого типа.

Тип_поддиапазона::=константа .. константа.Например: 0 .. 100-139 .. 340 .. 24Tuesday .. SaturdayОбъем памяти, выделяемый для типа поддиапазона может быть 1, 2 или 4

байта в зависимости размера диапазона.Чаще всего тип поддиапазона применяется при объявлении массивов (см.

параграф 1.9.2.1).

Свойства порядковых типов

Порядковый тип обладает некоторыми специфическими свойствами, которые реализуются с помощью следующего набора процедур и функций.

Преобразования

63

Page 64: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

function Ord(X): Longint;Значение порядкового типа характеризуется порядковым номером. Первое значение любого порядкового типа, кроме целочисленных, имеет порядковый номер 0, следующее - 1, и т.д. Порядковый номер значения целочисленного типа равен самому этому значению. Функция Ord осуществляет перевод значения любого порядкового типа в его порядковый номер.

function Chr(X: Byte): Char;Функция chr возвращает символ по его коду. Для обратного преобразования можно использовать, например, функцию Ord.

Получение предыдущего и последующего значений порядкового типаfunction Pred(X: порядковый_тип): тот_же_тип;

Функция Pred возвращает предыдущее значение аргумента. Если X - первое значение порядкового типа (нижняя граница), то выдается сообщение об ошибке.

function Succ(X: порядковый_тип): тот_же_тип;Функция Succ возвращает последующее значение аргумента. Если X - последнее значение порядкового типа (верхняя граница), то выдается сообщение об ошибке.

Увеличение и уменьшение значений переменных порядкового типаprocedure Inc(var X [ ; N: Longint ]);

Процедура Inc увеличивает переданное ей значение X на N. Если N отсутствует, то X увеличивается на 1 (т.о. Inc(x,n) эквивалентно x:=x+n, а Inc(x) эквивалентно x:=x+1).

procedure Dec(var X [ ; N: Longint ]);Процедура Dec уменьшает переданное ей значение X на N. Если N отсутствует, то X уменьшается на 1 (т.о. Dec(x,n) эквивалентно x:=x-n, а Dec(x) эквивалентно x:=x-1).

Четностьfunction Odd(X: Longint): Boolean;.

Функция возвращает True, если значение, переданное ей, нечетно. В противном случае возвращается False

Пример использования функции Ord:1) begin Writeln(ord(true),' ',ord(false)); End.

В результате выполнения программы на экране появятся числа 1 и 0.2) При рассмотрении перечислимого типа мы определили тип Week:

type Week=(monday, tuesday, wednesday, thursday, friday, saturday, sunday);Функция ord(monday) возвратит 0, ord(tuesday) - 1 и т.д.

Пример использования функций Pred и Succ:При выполнении программы:var a:boolean;begin

64

Page 65: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Порядковый тип

a:=false; writeln(pred(7)); writeln(Succ(a));end.на экране появятся число 6 и слово TRUE.

Примеры использования процедур Inc и Dec:Задача 23 . Определить сумму цифр натурального числа.

var N,i,s:integer;begin readln(n);{вводим натуральное число} s:=0; {первоначальное значение суммы} while n<>0 do begin {пока число не обратилось в 0} i:=n mod 10; {находим последнюю цифру числа} inc(s,i);{увеличиваем сумму на эту цифру} n:=n div 10; {уменьшаем число в 10 раз, чтобы добраться до следующей цифры} end; writeln(s); readln;end.

Задача 24 . Дано натуральное число N. Вывести на экран убывающую последовательность чисел от N до X, где X - последнее натуральное число в промежутке [1,N], кратное 11. Если такого числа не существует, вывод последовательности завершить на единице.

Решение:var N:word;begin write('Введите значение N>0: '); readln(n); inc(n); {увеличим N для корректировки первого входа в цикл} repeat dec(n); {уменьшаем N на 1 …} writeln(n); { … и выводим его на экран} until (n mod 11 = 0)or (n=1); {выходим из цикла, если N кратно 11 или равно 1} readln;end.

1.9.1.2 Вещественный типМножество действительных чисел в ТП представлено вещественными

типами. За одним исключением, все они обладают определенной погрешностью при проведении арифметических операций.

Таблица свойств вещественных типов данных:Вещественный

тип Диапазон возможных

значенийЗначащие

цифрыРазмер в байтах

Real 2.9⋅10−39 .. 1.7⋅1038 11-12 6Single 1.5⋅10−45 .. 3.4⋅1038 7-8 4Double 5.0⋅10−324 .. 1.7⋅10308 15-16 8Extended 3.4⋅10−4932 .. 1.1⋅104932 19-20 10Comp −263 . . 263 19-20 8

65

Page 66: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вещественный тип

Для типов Real, Single, Double и Extended в диапазон значений включается и отрицательная область.

Если компьютер не имеет встроенного математического сопроцессора, то удобнее всего использовать тип Real, так как разработчики ТП специально для него оптимизировали по скорости все операции. Остальные 4 типа являются специфичными для математического сопроцессора и должны использоваться с директивой компилятора {$N+}, которая указывает на его присутствии в системе, где будет исполняться программа. При отсутствии сопроцессора, с помощью директивы {$N+,E+} можно произвести его эмуляцию и применять в программе все вещественные типы.

Директива {$N+} замедляет скорость вычислений с типом Real, который является специфическим для ТП и не поддерживается сопроцессором. Таким образом, арифметические операции с типом Real предваряются переводом Real в Extended и завершаются обратным переводом.

При эмуляции математического сопроцессора по аналогичной причине замедляется обработка всех вещественных типов, кроме Real.

Все современные микропроцессоры Intel-архитектуры имеют встроенный сопроцессор. Поэтому для использования вещественных типов достаточно использовать в начале программы директиву {$N+}.

Тип Comp на самом деле не является вещественным. Это целочисленный тип с очень большим диапазоном значений (примерно от -1018 до 1018). Его удобно использовать в бухгалтерских расчетах, когда производятся операции над гигантскими суммами и требуется вести учет до последней копейки. Математический сопроцессор обрабатывает тип Comp методами, аналогичными для других вещественных типов.

Следующий пример отвечает на вопрос о точности вычислений для различных вещественных типов:

Задача 25 . Вычислить выражение 1−12

13−. . .

19999

−1

10000 двумя способами:

1) последовательно слева направо

2) последовательно слева направо вычисляются 113 . . .

19999

, затем

12

14. . .

110000

, после чего второе значение вычитается из первого.

Определить, насколько будут отличаться результаты, полученные при первом и втором методах расчета.

Решение:var s,s1,s2,s3:real;

i,sign:integer;begin {----- ПЕРВЫЙ способ -----} s:=0; sign:=1; {значение, с помощью которого меняется знак перед слагаемым} for i:=1 to 100 do begin s:=s+sign/i; {вычисляем сумму}

66

Page 67: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вещественный тип

sign:=-sign; {меняем знак} end; {----- ВТОРОЙ способ -----} s1:=0; for i:=1 to 50 do s1:=s1+1/(i*2-1);{вычисляем сумму с нечетным знаменателем} s2:=0; for i:=1 to 50 do s2:=s2+1/(i*2);{вычисляем сумму с четным знаменателем} s3:=s1-s2;{вычисляем разность между полученными значениями } writeln(s); writeln(s3); writeln(s-s3); readln;end.В результате выполнения программы на экране появятся 3 числа: 6.8817217931E-01 6.8817217931E-01-9.0949470177E-12Точность вычисления в данном случае составляет примерно 10-11.Применим директиву компилятора {$N+, E+}, чтобы проанализировать работу программы

при использовании математического сопроцессора. ($N - для подключения сопроцессора, $E - для эмуляции в случае его отсутствия):

{$N+, E+}var s,s1,s2,s3:real;

i,sign:integer;begin...Результат: 6.88172179303365E-0001 6.88172179314279E-0001-1.09139364212751E-0011Последовательно заменяя тип Real в программе на типы Single, Double и Extended

получим следующие значения:Для типа Single: 6.88171803951263E-0001 6.88172578811646E-0001-7.74860382080078E-0007Для типа Double: 6.88172179310196E-0001 6.88172179310195E-0001 3.33066907387547E-0016Для типа Extended: 6.88172179310195E-0001 6.88172179310195E-0001 6.50521303491303E-0019Как можно заметить, во всех случаях погрешность вычислений примерно соответствует

заявленной в таблице. В то же время, результаты выполнения данной программы могут несколько различаться на компьютерах с различными видами сопроцессоров.

Вещественный тип можно преобразовать в порядковый (а конкретно - в целочисленный) с помощью двух функций:

67

Page 68: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вещественный тип

function Round(X: Real): Longint;function Trunc(X: Real): Longint;Функция Round производит округление переданного ей вещественного

значения до ближайшего целого.Например: Begin Write(round(1.3),' ', round(2.7),' ', round(-7.3),' ', round(-15.5));End.В результате выполнения этой программы на экране появится строка, состоящая из 4 чисел:

1 3 -7 -16Функция Trunc производит отбрасывание дробной части у переданного ей

вещественного значения.Например: Begin Write(trunc(1.3),' ', trunc(2.7),' ', trunc(-7.3),' ', trunc(-15.5));End.В результате выполнения этой программы на экране появится строка, состоящая из 4 чисел:

1 2 -7 -15Отвечая на вопрос, какие вещественные типы целесообразнее использовать в

различных ситуациях, мы можем посоветовать следующее:Для простых, с небольшим объемом вещественных расчетов используйте тип

Real.Если у Вас в программе выполняются сложные математические расчеты, при

этом очень важна точность, и достаточно как оперативной памяти, так и времени, используйте тип Extended.

Если объем памяти ограничен или требуется обработка больших вещественных массивов, и при этом точность вычислений не играет особой роли, используйте тип Single.

В ситуации, промежуточной между первыми двумя, используйте тип Double.Если Вы выполняете расчеты с очень большими целыми числами, используете

тип Comp.Если у Вас отсутствует математический сопроцессор, а скорость выполнения

программы играет решающую роль, используйте тип Real.

Задачи для раздела "Простой тип"Задание 43. Дано натуральное число N. Не используя арифметические операции, вывести на экран все натуральные числа от 1 до N.Задание 44. Вывести на экран всю таблицу символов, начиная с пробела.Задание 45. "Поговори с компьютером". Создать программу, которая будет отвечать на нажатие клавиши выводом произвольного количества (до 80) произвольных символов (можете воспользоваться, например, тем, что коды заглавных латинских букв находятся в промежутке [65,90]). Выход из программы - по нажатию клавиши ESC.Задание 46. Ежемесячный доход от торговли нефтью некой арабской страны составляет 250 миллионов условных единиц. 7.564325 процентов от этой суммы она тратит на поддержку мирового терроризма, 3.71232 процента - на подрывную деятельность, направленную против Израиля. 49.99999 процентов помещается в самые надежные банки, а остальное идет на

68

Page 69: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Задачи для раздела "Простой тип"

повседневные нужды правителя. Какие суммы по каждой статье расходов истратит великий шейх за 25 лет своего безупречного правления? Примечание: погрешности в вычислениях не приемлимы для великого шейха.

69

Page 70: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Структурные типы

1.9.2 Структурные типыОсновное отличие структурных типов от простых заключается в том, что они

состоят из нескольких компонент, которые, в некоторых случаях, также могут иметь структуру.

Структурный_тип::=[packed] (тип_массив | строковый_тип | тип_запись | множественный_тип | файловый_тип | объектный_тип)

Слово packed должно указывать компилятору, что данные этого типа следует уплотнять. Однако компилятор ТП сам производит все возможные уплотнения и не нуждается в подобном указании. Упакованные типы оставлены для совместимости со стандартным Паскалем.

1.9.2.1 МассивыПод массивом понимается упорядоченный набор однотипных элементов

(компонент), число которых фиксировано (ТП не поддерживает массивов с переменными границами). Доступ к каждому элементу массива осуществляется с помощью набора индексов, количество которых называется размерностью массива. Индексами могут служить значения любого порядкового типа.

Тип_массив::= "array" "[" тип_индекса {"," тип_индекса"} "]" "of" тип_компонент.

тип_индекса::= порядковый тип.тип_компонент::=типМассивы содержат фиксированное количество компонент одного типа. На

каждый тип индекса приходится по одной размерности массива. Например:Рассмотрим тип двумерного массива с компонентами целого типа.

Следующий тип полностью идентичен первому. Type MyArray2=array[boolean] of array[1..10] of integer;

Чаще всего для типа индекса используют тип поддиапазона, однако нет никаких ограничений на применение любого другого порядкового типа. Основная причина использования типа поддиапазона состоит в том, что объем занимаемой массивом памяти рассчитывается как произведение мощности индексов друг на друга и на размер памяти одного элемента массива. Мощность (диапазон значений) любого порядкового типа, кроме типа поддиапазона и перечислимого типа, фиксирована и не может быть изменена. Т.о., если весь диапазон значений не используется, происходит бессмысленный расход оперативной памяти компьютера.

Например:

70

type MyArray1=array[ boolean , 1..10 ] of integer;

Тип индекса-логический

Индекс типа поддиапазона

Page 71: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Массивы

Определение типа массива:Type FirstArray=array[shortint] of byte;

по объему занимаемой памяти и обращению к элементам массива эквивалентно:Type SecondArray=array[-128..127] of byte;

Для получения значения элемента массива требуется указать переменную массива со следующим за ней индексом.

Индекс::= "[" выражение {"," выражение"} "]"Например:type MyArray1=array[boolean,1..10] of integer;var A:MyArray1;

B:array[-1..3] of boolean;begin...writeln(A[true,3], A[false,1], B[2])…end.ТП имеет 3 предопределенных одномерных массива для прямого доступа к

памяти: Mem - для доступа к байтам, MemW - для доступа к словам, MemL - для доступа к значениям типа longint. Индексация массивов памяти производится стандартным методом построения адреса памяти с помощью значений сегмента и смещения, разделенных двоеточием (см. параграф 1.9.3).

Например:var a:longint absolute $40:$6C; {абсолютная переменная, которая соответствует области

оперативной памяти с адресом $40:$6C (дневной счетчик времени)}b: longint;

begin b:=a; {присваиваем переменной b текущее время} … b:=memL[$40:$6C]; {делаем то же самое с помощью прямого обращения к памяти}…end.Для прямого доступа к портам ввода-вывода ТП имеет 2 предопределенных

одномерных массива: Port - для доступа к байтам, PortW - для доступа к словам.

Заполнение и обработка массивов

В программировании массивы используются для обработки больших объемов однотипных данных. Перед использованием любого массива его следует заполнить, что производится обычно с помощью цикла, или, для многомерных массивов, с помощью вложенных циклов. Обработка массива также ведется с помощью циклов.Задача 26 . Дано натуральное число N. Получить N случайных чисел и вывести их на экран сначала в прямом, а потом - в обратном порядке.

var a:array[1..100] of word; {т.к. ТП не позволяет определять массивы переменной длины, мы рассчитываем, что количество получаемых чисел будет не более 100}

i,N:integer; begin readln(n);

71

Page 72: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Массивы

randomize; {инициализируем счетчик случайных чисел} for i:=1 to N do begin {заполняем и одновременно выводим массив на экран} a[i]:=random(23); write(a[i]:3); end; writeln; for i:=N downto 1 do begin {выводим на экран массив в обратном порядке} write(a[i]:3); end; writeln; readln; end.

Задача 27 [1, № 377]. Дана натуральная квадратная матрица M*M. Заменить нулями все ее элементы, лежащие на главной диагонали и выше ее.

var i,j,m:integer; a:array[1..10,1..10]of integer; {двумерный массив для хранения матрицы} begin repeat {простейший фильтр ввода} readln(m); until (m>0)and(m<=10);

{с помощью двух вложенных циклов заполняем матрицу случайными числами и выводим ее на экран}

randomize; for i:=1 to m do begin for j:=1 to m do begin a[i,j]:=random(100); write(a[i,j]:3); end; writeln; {производим перевод строки для разделения строк матрицы} end; writeln; {производим перевод строки для разделения исходной и результирующей

матриц}{с помощью двух вложенных циклов преобразуем матрицу в соответствии с условием задачи и выводим ее на экран}

for i:=1 to m do begin for j:=1 to m do begin if i<=j then a[i,j]:=0; {если номер строки меньше или равен номеру столбца (условие для

главной диагонали и всех вышележащих ее элементов), то обнуляем данный элемент массива}

write(a[i,j]:3); end; writeln; end; readln end.Если в результате запроса после запуска программы ввести число 5, то на экране можем

получить примерно следующее: 0 3 86 20 27 67 31 16 37 42 8 47 7 84 5

72

Page 73: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Массивы

29 91 36 77 32 69 84 71 30 16

0 0 0 0 0 67 0 0 0 0 8 47 0 0 0 29 91 36 0 0 69 84 71 30 0Благодаря применению процедуры randomize следующий запуск программы построит

новую последовательность случайных чисел.Задача 28 . Найти максимальный элемент одномерного массива.

var a:array[1..10] of byte;i,max:byte;

begin randomize; for i:= 1 to 10 do begin {заполняем и выводим на экран массив} a[i]:=random(100); write(a[i]:4) end; writeln; max:=a[1]; {предполагаем, что максимальным является первый элемент массива } for i:=2 to 10 do {перебираем все остальные элементы массива}

if max<a[i] then max:=a[i]; {если предположение оказалось неверным, то будем считать, что максимальным является текущий элемент массива}

writeln(max);{выводим на экран максимальный элемент} readln;end.

Определение содержимого массива в разделе типированных констант

Объявление константы с типом массив содержит значения элементов массива, разделенных запятыми и заключенными в скобки.

Константа-массив::="(" типированная_константа{"," типированная_константа} ")".

Например:Const A: array[1..3] of integer=(-4,5,21);

B: array[1..3,1..2] of char=( ('A','f'),('1','2'),('x','y'));

Задачи для раздела "Массивы"Задание 47. Найти индекс и значение последнего минимального элемента одномерного массива длиной N.Задание 48. Заполнить массив A длиной N и преобразовать его следующим образом: увеличить каждый элемент массива на max(A1..AN).Задание 49. Заменить нулями все минимальные элементы одномерного массива длиной N.Задание 50. Найти сумму, разность, произведение и среднее арифметическое элементов одномерного массива длиной N.Задание 51. Найти максимальный и минимальный элементы двумерного массива размером M на

73

Page 74: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Массивы

N.Задание 52. Найти максимальные элементы строк двумерного массива размером M на N.Задание 53. Перенести содержимое двумерного массива в одномерный.Задание 54. Отразить двумерный массив размером M на N относительно побочной диагонали (левый верхний угол становится правым нижним, а правый нижний - левым верхним).

74

Page 75: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

1.9.2.2 Строковый типСтроковые типы используются для определения произвольных наборов

символов. Строку можно определить как одномерный массив с переменными границами, каждый элемент которого является символом типа Char.

Строковый_тип::= Стандартный_строковый_тип | ASCIIZ_типИзначально в Паскале, а затем и в ТП существовал только один строковый

тип, максимальная длина которого не могла превышать 255 байт. Одной из особенностей данного типа было то, что первый байт строки означал ее актуальную длину (отсюда и ограничение на 255 символов). При этом во многих других языках, и прежде всего в языке Си для организации строк используется совершенно другая структура, основанная на последовательности символов, заканчивающейся нулем. Длина такой последовательности может быть до 64 килобайт, что вполне достаточно для хранения небольших текстов. Поэтому для совместимости с другими языками в седьмую версию ТП был введен ASCIIZ тип (ASCII - американский стандарт набора символов, Z (zero-нуль) - заканчивающегося нулем).

Справедливости ради следует сказать, что несмотря на широкое распространение в программировании ASCIIZ строк, манипулировать стандартными паскалевскими строками значительно проще и надежнее. Поэтому в современных версиях языка Паскаль (Object Pascal, Free Pascal и др.) введено понятие длинной строки, которая совмещает в себе все достоинства стандартных и ASCIIZ строк и простейшим преобразованием типов (а для стандартных строк даже и этого не требуется) может быть приведена к любому из них.

Стандартный строковый тип

Стандартный_строковый_тип ::= "string" [ "[" "целое_без_знака" "]"]Число в скобках означает максимальную длину строки. Если оно отсутствует,

то максимальная длина строки =255 символам. Объем памяти, занимаемый строкой, равен ее максимальной длине, вне зависимости от актуальной длины, значение которой находится в промежутке от 0 до максимальной длины.

Аналогично элементу массива можно проиндексировать строковую переменную, причем значение индекса должно принадлежать промежутку от 0 до максимального размера строки. Таким образом можно получить доступ к каждому символу строки типа Char. Нулевой символ строки представляет собой после перевода в целочисленное выражение актуальную длину строки.Задача 29 . Ввести с клавиатуры строку и вывести ее задом наперед.

var s:string;i:byte;

begin readln(s); for i:=ord(s[0]) downto 1 do write(s[i]); {открываем цикл от актуальной длины строки до 1.

В теле цикла выводим все символы строки} writeln; readln; end.Для стандартных строк можно использовать операции отношения. При

75

Page 76: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

сравнении строк сравниваются последовательно все символы с одинаковыми индексами в соответствии с таблицей ASCII. Операция сравнения завершает свою работу, как только значение символа одной строки станет больше, чем значение символа с таким же порядковым номером из другой строки. Если одна строка длиннее другой, то она считается большей в операциях сравнения, только если ее начало равно более короткой строке.

Например:Процедура writeln('AA'>'BB') выведет на экран FALSE;Процедура writeln('AA'='aa') выведет на экран FALSE;Процедура writeln('Привет'<'Привет, друг!') выведет на экран TRUE;Модуль System содержит большой набор функций и процедур,

предназначенных для работы со стандартными строками.Function Concat(s1 [, s2,..., sn]: String): String;

Функция Concat объединяет переданные ей строки, присоединяя каждую последующую к концу предыдущей и возвращает полученный результат. Функция эквивалентна строковой операции контактенции "+"

Function Copy(S: String; Index: Integer; Count: Integer): String;Функция Copy возвращает вырезку из строки S, начиная с символа, номером которого Index в количестве Count символов

Procedure Delete(var S: String; Index: Integer; Count:Integer);Процедура Delete удаляет из строки S подстроку, начиная с символа, номер которого Index в количестве Count символов.

Procedure Insert(Source: String; var S: String; Index: Integer);Процедура Insert вставляет строку Source в строку S, начиная с позиции Index строки S.

Function Length(S: String): Integer;Функция Length возвращает длину переданной ей строки (эквивалентно ord(s[0]))

Function Pos(Substr: String; S: String): Byte;Функция Pos возвращает номер позиции первого вхождения подстроки Substr в строку S. Если подстрока Substr в строке S отсутствует, то функция возвращает 0.

procedure Str(X [: Width [: Decimals ]]; var S:string);Процедура Str переводит число X в строку S с возможностью форматирования (также как для форматированного вывода с помощью процедур Write и Writeln)

Procedure Val(S:string; var V; var Code: Integer);Процедура Val переводит строку S в число V. Если перевод невозможен (например из-за недопустимых символов в строке, или из-за несоответствия типов - попытка перевода строкового представления вещественного числа в целочисленную

76

Page 77: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

переменную V), то в переменной Code возвращается код ошибки. Если перевод прошел нормально, в переменной Code возвращается 0.

Задача 30 . Ввести с клавиатуры и объединить три строки.var s1,s2,s3,s:string; begin readln(s1); readln(s2); readln(s3); s:=concat(s1,s2,s3); {объединяем введенные строки с использованием функции concat} writeln(s); s:=s1+s2+s3; {объединяем введенные строки с использованием операции контактенции } writeln(s); readln; end.С помощью данной программы можно сравнить результаты действия функции Concat и

операции контактенции.Задача 31 . Заменить в строке все знаки присваивания (':=') на знаки равенства ('=').

При решении данной задачи воспользуемся небольшой хитростью. Вместо того, чтобы заменять знаки ':=' на '=', просто удалим из каждого знака присваивания двоеточие.

var s:string;i:integer;

begin readln(s); i:=pos(':=',s); {находим позицию первого знака присваивания} while i<>0 do begin {открываем цикл для перебора всех знаков присваивания в строке} Delete(s,i,1); {удаляем из знака присваивания двоеточие} i:=pos(':=',s); {снова находим позицию знака присваивания. Так как предыдущий знак

был изменен, то этим оператором мы найдем следующий знак присваивания}

end; writeln(s); readln;end.

Задача 32 . Дана строка символов и число N. Произвести ротацию строки на N символов (например: если исходная строка равна '1x2y3z4a', а N=3, то результирующая строка будет равна ' z4a1x2y3').

var s:string;N:integer;

begin readln(s); readln(N); n:=n mod length(s); {учитываем, что число N может быть больше, чем длина строки} if n<>0 then begin {с помощью вырезки составляем результирующую строку из двух частей исходной} s:=copy(s,length(s)-n+1,n)+copy(s,1,length(s)-n); end; writeln(s); readln;

77

Page 78: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

end.Задача 33 . Вставить пробел после каждой запятой в строке. Использование дополнительных строк не допускается.

var s:string; i:integer; begin readln(s); i:=1; while i<=length(s) do begin {цикл For использовать нельзя, так как в процессе итераций

происходит увеличение длины строки} if s[i]=',' then begin {если нашли запятую, то вставляем пробел и увеличиваем счетчик на

единицу, чтобы на следующей итерации не анализировать этот пробел}

insert(' ',s,i+1); inc(i); end; inc(i); {переходим к следующему символу} end; writeln(s); readln; end.

Задача 34 . Создать универсальный фильтр для ввода натурального числа.Создание универсального фильтра подразумевает, что никакой введенный набор символов

не сможет вызвать аварийный останов программы или неправильную интерпретацию такого набора.

var s:string; {введенная строка}N:Longint; {полученное путем преобразования число}ErrorCode:integer; {код ошибки}

begin repeat {открываем цикл для организации фильтра} readln(s); val(s,N,ErrorCode); {переводим введенную строку в число} until ErrorCode=0; {выходим из цикла, если не произошло ошибки} writeln(n); readln;end.

Задача 35 . Дано натуральное число N. Вывести на экран значение его квадрата в прямом и обратном порядке.

var N:Longint; i:byte; s:string;begin readln(N); n:=sqr(n); writeln(n); {выводим квадрат числа} str(n,s); {преобразуем его в строку} for i:=length(s) downto 1 do write(s[i]);{выводим полученную строку в обратном порядке} writeln; readln;end.

78

Page 79: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

ASCIIZ строковый тип

ASCIIZ (тип PCHAR) представляет собой указатель (см. параграф 1.9.3) на символ типа Char, его адрес в оперативной памяти. Однако при использовании расширенного синтаксиса (что достигается с помощью директивы компилятора {$X+}) к типу PChar можно обращаться как к одномерному массиву символов, индекс которого начинается с нуля.

Например:{$X+}var A:PChar;B:array[0..100] of char;

К переменной А можно обращаться с помощью тех же методов, что и к переменной B.В отличии от стандартных строк, память для переменных типа PСhar не

выделяется автоматически в начале программы, что накладывает определенные ограничения на использование данного типа. Например, попытка обратиться к такой переменной как к массиву до присваивания ей некоторого значения обречена на провал. Значение любой переменной PChar до присваивания ей некоторого значения всегда равно nil (см. параграф 1.9.3).

Например:{$X+}var s1,s2:PChar; begin s1:='Номер 1'; writeln(s1); s1[6]:='2'; {здесь мы совершенно правомерно обращаемся к седьмому символу строки s1,

так как ей заранее было присвоено константное значение, в результате чего s1 указывает на некоторую область памяти}

writeln(s1); s2[0]:='A'; s2[1]:='B'; s2[2]:='C'; {НЕВЕРНО! Переменной s2 ничего заранее присвоено

не было...} writeln(s2); {... и поэтому на экране ничего не появится} readln;end.Не следует забывать, что ASCIIZ строки всегда должны заканчиваться нулем.

При присваивании им строковых констант или определении типированных констант это происходит автоматически. Если же потребуется принудительно сократить длину строки, достаточно в требуемое место вставить символ с кодом 0.

Например:const s:pchar='Казнить нельзя, помиловать'; begin s[7]:=#0; {всего один символ недвусмысленно решает судьбу осужденного} writeln(s); readln; end.Так как строки PChar являются на самом деле указателями, то присваивание

одной строки другой не создает копии значения строки. На самом деле, после такого присваивания обе строки будут указывать на одну и ту же область памяти, и

79

Page 80: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

все изменения в одной из них автоматически будут отражены в другой.Например:var s1,s2:pchar;begin s1:='Cтрока номер 1'; s2:=s1; s2[13]:='2'; writeln(s1); writeln(s2); readln;end.В результате выполнения программы на экране появится:Cтрока номер 2Cтрока номер 2Модуль Strings содержит большой набор функций, предназначенных для

работы с ASCIIZ строками. Каждая из них может работать как с типом PChar, так и с массивом символов. К сожалению, функции, изменяющие или зависящие от регистра символов, не поддерживают русский алфавит.

Функции распределения динамической памятиFunction StrNew(Str: PChar): PChar;Function StrDispose(Str: PChar);

Функция StrNew выделяет блок динамической памяти и копирует туда переданную ей строку Str. Адрес выделенного блока возвращается в качестве результата. Функция StrDispose освобождает блок памяти, выделенный ранее функцией StrNew.

Функции преобразованияFunction StrPCopy(Dest: PChar; Source: String): PChar;Function StrPas(Str: PChar): String;

Функция StrPCopy копирует стандартную паскалевскую строку Source в ASCIIZ строку Dest и возвращает ее в качестве результата. Строка Dest должна иметь достаточный объем для сохранения строки Source.Функция StrPas совершает обратную операцию.

Функция определения длиныFunction StrLen(Str: PChar): Word;

Функция StrLen возвращает длину переданной ей строкиФункции поиска

Function StrPos(Str1, Str2: PChar): PChar;Function StrScan(Str: PChar; Chr: Char): PChar;Function StrRScan(Str: PChar; Chr: Char): PChar;

Функция StrPos возвращает указатель на первое вхождение строки Str2 в строку Str1. Если такое вхождение отсутствует,

80

Page 81: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

функция возвращает nil.Функция StrScan возвращает указатель на первое, а StrRScan - на последнее вхождение символа Chr в строку Str.

Функции контактенцииFunction StrCat(Dest, Source: PChar): PChar;Function StrLCat(Dest, Source: PChar; MaxLen: Word): PChar;

Функция StrCat присоединяет к строке Dest строку Source и возвращает Dest. Строка Dest должна иметь достаточный объем для сохранения строки Source.Функция StrLCat присоединяет к строке Dest строку Source и возвращает Dest. Полученный результат будет иметь длину не более чем MaxLen символов.

Функции сравненияFunction StrComp(Str1, Str2 : PChar): Integer;Function StrIComp(Str1, Str2:PChar): Integer;Function StrLComp(Str1, Str2: PChar; MaxLen: Word): Integer;Function StrLIComp(Str1, Str2: PChar; MaxLen: Word): Integer;

Функция StrComp сравнивает две строки и возвращает значение <0, если Str1 < Str2 =0, если Str1 = Str2 >0, если Str1 > Str2

Функция StrIComp сравнивает две строки без учета регистра.Следующие две функции сравнивают только MaxLen символов строк.

Функции копированияFunction StrCopy(Dest, Source: PChar): PChar;Function StrECopy(Dest, Source: Pchar): PChar;Function StrMove(Dest, Source: PChar; Count: Word): PChar;Function StrLCopy(Dest, Source: Pchar; MaxLen: Word): PChar;

Функция StrCopy копирует строку Source в строку Dest и возвращает Dest. Функция StrECopy копирует строку Source в строку Dest и возвращает указатель на конец объединенной строки. Функция StrMove копирует Count символов из строки Source в строку Dest и возвращает Dest. Для всех трех функций строка Dest должна иметь достаточный объем для сохранения Source.Функция StrLCopy копирует максимум MaxLen символов строки Source в строку Dest и возвращает Dest.

Функции изменения регистраFunction StrLower(Str: PChar): PChar;Function StrUpper(Str: PChar): PChar;

Функция StrLower переводит строку в строчные буквы.

81

Page 82: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Строковый тип

Функция StrUpper переводит строку в прописные буквы.Функция перехода

Function StrEnd(Str: PChar): Pchar;Функция StrEnd возвращает указатель на конец строки.

Задачи для раздела "Строковый тип"

Во всех последующих задачах подразумевается, что строка вводится с клавиатуры, а измененная строка(строки) выводится на экран. Использование дополнительных строк, о которых не сказано в условии задачи, не допускается.Задание 55. Обрезать строку за последним пробелом.Задание 56. Удалить из строки все восклицательные знакиЗадание 57. Удвоить каждый символ строки (строка 'ABC' превращается в 'AABBCC').Задание 58. Зашифровать строку следующим образом: увеличить код каждого символа строки на единицу.Задание 59. "Перевернуть" строку.Задание 60. Заменить в строке все точки троеточием.Задание 61. Определить, имеются ли в строке два рядом стоящих символа.Задание 62. Разделить строку на две части по следующему правилу: все цифры остаются в первой строке, все остальные символы переносятся во вторую (строка '1sd1025ds' превратится в две - '11025' и 'sdds').Задание 63. Все пробелы переместить в начало строки. Решите задачу с использованием и без использования дополнительных строковых переменных.

82

Page 83: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Записи

1.9.2.3 ЗаписиЗапись в ТР является одним из самых общих и структурированных типов.

Запись состоит из фиксированного числа компонент (полей), которые могут быть различных типов.

тип_запись::= "record" [ список_полей ] "end"список_полей ::= ( фиксированная_часть [";" вариантная_часть] [";"]) |

(вариантная_часть [";"])фиксированная_часть::= список_ИД ":" тип { ";" список_ИД ":" тип }

Примеры определения типа запись с фиксированной частью:

type Book=record {определяем тип записи - "Книга"} Title:string[40]; {название книги} Autor:string[50]; {автор} Publ:string; {издательство} Date:integer; {год издания}end;Date=record {определяем тип записи - "Дата"} Year: integer; {год} Month: 1..12; {месяц} Day: 1..31; {день}end;Заметьте, что одно из полей записи Book имеет то же имя, что и запись Date. ТП не считает

это ошибкой, так как одинаковые идентификаторы находятся в разных блоках.Для обращения к определенному полю переменной типа запись требуется

указать имя переменной, точку и имя поля.Например:…var A:Book;begin ... a.title:=’Кризис империи’; a.Autor:=’Дэвид Дрейк’; a.Publ:=’Армада’; a.Date:=1997; ...end.В вариантной части ТП позволяет распределить одну и ту же область памяти

компьютера между несколькими полями записи. Т.о. изменение одного поля сказывается на содержимом других. Объем распределенной памяти равен объему наибольшего поля.

вариантная_часть ::= "case" [ИД_поля_признака ":"]тип_поля_признака "of" вариант {";" вариант}

тип_поля_признака::= порядковый_тип.

83

Page 84: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Записи

Вариант::= константа {"," константа} ":" "(" [список_полей] ")"

Например:…type Person=record {определяем тип записи - "Человек"}

Name:string[40]; {Имя (фамилия, отчество)}BirthDate: Date; {дата рождения}case Citizen:Boolean of {гражданство в нашей стране}

true: (BirthPlace: string[40]); {если гражданин, то определяем место рождения }false: (Country:string[20]; {иначе определяем страну, из которой прибыл …}

EntryDate,ExitDate:Date); {… даты въезда и выезда}end;Т.о. в зависимости от гражданства определено либо место рождения, либо

страна, дата въезда и дата выезда.К полям, указанным в вариантной части обращение производится точно так

же, как и для фиксированной части. Для каждого варианта должен быть указан индивидуальный набор констант. Доступ к каждому варианту всегда разрешен вне зависимости от значения поля признака. Программа может использовать значение поля признака для определения, какой из вариантов является активным в данный момент. Если поле признака отсутствует, то определение должно происходить по другому критерию.

Для сокращения процесса обращения к полям записи служит оператор работы над записями.

Оператор_работы_над_записями::= "with" ссылка {"," ссылка} "do" оператор

Ссылка::=ИД переменной типа запись или объект.Внутри оператора позволяется манипулировать полями записи, ссылки на

которые имеются в заголовке, без указания имени переменной типа запись.Например: var I: Date;...with I do begin writeln("Год", Year); writeln("Месяц", Month); writeln("День", Day);end;...

Определение содержимого записи в разделе типированных констант.

Объявление константы типа запись содержит идентификатор и значение каждого поля, заключенное в скобки и разделенные точками с запятой.

Константа_запись::=

84

Page 85: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Записи

"(" ИД_поля ":" типированная_константа{ ";" ИД_поля ":" типированная_константа } [";"] ")".

Например: const Man:person=

(Name: 'Иванов Иван Иванович';BirthDate: ( Year: 1970;

Month: 2;Day: 23);

Citizen: true;BirthPlace: 'Шадринск');

Jerry:Person=(Name: 'Мышонок Джерри';BirthDate: ( Year: 1970;

Month: 2;Day: 23);

Citizen: false;Country: 'США';EntryDate: ( Year: 1990;

Month: 1;Day: 1);

ExitDate: ( Year: 2090; Month: 1;Day: 1));

Задачи для раздела "Записи"Задание 64. Создать запись с информацией об автомобиле (не менее 5 полей). Заполнить с

клавиатуры массив автомобилей. Затем ввести числовое значение и вывести на экран информацию об автомобилях с объемом двигателя, равным введенному значению.

Задание 65. Создать запись с информацией о процессоре (не менее 3 полей). Заполнить с клавиатуры массив процессоров. Затем ввести строковое значение и вывести на экран информацию о процессорах, название фирмы-производителя которых соответствует введенному значению.

Задание 66. Создать запись с информацией о студенте, включающую - ФИО, номер зачетки, номер группы. Создать программу, заполняющую с клавиатуры массив студентов и переводящую их на следующий курс. Получившийся результат вывести на экран (Например: если студент был в 181 группе, то после перевода на следующий курс номер его группы изменяется на 281. Если студент был в 504 группе, то в процессе перевода на следующий курс он исключается из массива).

Задание 67. Создать запись с вариантной частью для хранения информации о таких геометрических фигурах, как точка, линия, окружность, треугольник, прямоугольник. Включить информацию о цвете фигуры. Создать программу, заполняющую с клавиатуры и выводящую на экран массив фигур.

1.9.2.4 МножестваМножество в ТП является типом данных, диапазон значений которого

является мощностью множества для определенного порядкового (базового) типа. Каждое возможное значение типа множества является подмножеством базового типа. Переменная типа множество может принимать как все значения множества,

85

Page 86: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Множества

так и не одного. Множество не может содержит повторяющихся элементов. Размер любой переменной множественного типа составляет 32 байта. При этом для хранения каждого значения множества используется 1 бит. Если значение присутствует во множестве, соответствующий бит устанавливается в 1, в противном случае – в 0.

Тип_множество::= "set" "of" порядковый тип.Базовый тип не должен иметь более 256 значений, нижняя и верхняя границы

типа не должны выходить из промежутка от 0 до 255. Это ограничение напрямую следует из размера переменной множественного типа.

Например:type MySet = set of char;var S:set of byte;Создание множества получается путем записи выражений, заключенных в [].

Пустое множество описывается как [].Описатель_множества::= "[" [группа {"," группа}] "]"группа::= выражение [".." выражение]Значение выражения не должно выходить за пределы базового типа.Например:var x:set of byte;

c: set of char;k:byte;

begin... x:=[1,5,100..145, K div 10]; c:=[‘A’ .. ‘Z’, ‘a’ .. ’z’];...end.Над множествами можно проводить операции объединения, разности и

пересечения по алгебраическим правилам действий над множествами, а также определять, содержит ли множество некоторый элемент, или является ли одно множество подмножеством (надмножеством) другого (см. параграф 1.6.3).

Например:Объединение:

Операция [1,2,5,12]+[0,2,5,7,34] возвратит множество [0,1,2,5,7,12,34] (состоящее из первого и второго множеств)

Разность:Операция [1,2,5,12]-[0,2,5,7,34] возвратит множество [1,12] (состоящее из тех элементов

первого множества, которые отсутствуют во втором)Пересечение:

Операция [1,2,5,12]*[0,2,5,7,34] возвратит множество [2,5] (состоящее из тех элементов первого множества, которые имеются и во втором)

Вхождение во множество:Операция 1 in [0,3,5] возвратит false.Операция ‘x’ in [‘A’, ‘k’..’z’] возвратит true.

Надмножество и подмножество:Операция [1,2,5,12]>=[0,1,2,5,7,12,34] возвратит falseОперация [1,2,5,12]<=[0,1,2,5,7,12,34] возвратит true

86

Page 87: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Множества

Задача 36 . Создать фильтр ввода ответа на вопрос (типа "Да"/"Нет")Решение:uses crt;var c:char; begin writeln('Вы уверены?(Д/Н)'); repeat {начало фильтра} c:=readkey; until c in ['Д', 'д', 'Н', 'н']; {фильтр пропускает только требуемый для ответа символ} writeln; if c in ['Д','д'] then writeln(' На вопрос Вы ответили "ДА"') else writeln('На вопрос Вы ответили "НЕТ"'); readln; end.Для добавления и исключения элемента из множества в ТП предусмотрены

две процедуры:procedure Include(var S: set of T; I:T);procedure Exclude(var S: set of T; I:T);Процедура Include включает во множество S значение I.Процедура Exclude исключает из множества S значение I.

Задача 37 . Исключить из строки все повторения символов.var CharSet:set of char; {множество символов строки}

s:string;i:byte;

beginreadln(s);CharSet:=[]; i:=1;while i<=length(s) do begin {перебираем все символы строки. Цикл For использовать

нельзя, так как во время итераций происходит удаление символов и, как следствие - уменьшение длины строки}

if s[i] in CharSet then delete(s,i,1) {если текущий символ строки уже во множестве, удаляем его (переходя таким образом к следующему символу строки)...}

else begin {... иначе включаем его во множество и переходим к следующему символу} Include(CharSet,s[i]); inc(i); endend;writeln(s);readln;end.В предыдущих версиях ТП и стандартном Паскале добавить элемент во

множество можно было с помощью операции объединения, а удалить - с помощью операции разности множеств.

Например:Если S - множество натуральных чисел, то операция [3]+S и функция Include(s,3) имеют

один и тот же результат. Аналогичным образом можно оценить операцию S-[7] и функцию

87

Page 88: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Множества

Exclude(s,7). Однако функции Include и Exclude выполняются значительно быстрее.

Задачи для раздела "Множества"Задание 68. Удалить из строки все символы, входящие во множество цифр и знаков препинания.Задание 69. Оставить в строке только буквы (Подсказка: множество русских строчных букв разрывно. Поэтому вместо промежутка 'а'..'я' требуется использовать два промежутка - 'а'..'п' и 'р'..'я').Задание 70. Перевести строку в верхний регистр с учетом русского алфавита.Задание 71. Удалить из строки все символы, которые имеются в другой строке.Задание 72. Оставить в строке только те символы, которые имеются в другой строке.Задание 73. Все буквы строки, которые имеются во второй строке, заменить на символ 0, а оставшиеся - на символ 1.Задание 74[1, № 557]. Воспользовавшись решетом Эратосфена, найти все простые числа в промежутке [2,N], где N[2,255]. Решетом Эратосфена называют следующий способ. Выпишем подряд все целые числа от 2 до N. Подчеркнем его, а все большие числа, кратные 2, вычеркнем. Первое из оставшихся чисел - 3, поступим с ним так же, как и с двойкой. Первое из оставшихся - 5, так как 4 уже вычеркнуто. Поступим аналогично с числом 5 и всеми последующими числами до N. Подчеркнутые числа являются простыми.2,3,4,5,6,7,8,9,10Задание 75. Получить неповторяющуюся последовательность из 100 случайных чисел, значения которых лежат в промежутке [1,100].

88

Page 89: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

1.9.2.5 Файловые типыФайловый тип состоит из линейной последовательности компонент любого

типа, кроме файлового или структурного типа, который содержит компоненту файлового типа.

Файловый_тип::= "text" | ("file" "of" тип) | "file".Файлы TEXT являются текстовыми файлами последовательного доступа.

Их обработку можно вести только последовательно, строка, за строкой, слово за словом, символ за символом. Таким образом, если требуется считать строку из середины текстового файла, придется считывать все ей предшествующие. Однако этот недостаток с лихвой перекрывают возможности форматированного вывода и ввода информации произвольного типа из файла стандартными процедурами ввода-вывода. По сути дела, экран и клавиатура сами являются текстовыми файлами соответственно для записи и чтения. В модуле System содержатся 2 текстовые файловые переменные с именами Output и Input, первая из которых сопоставлена с экраном, а вторая - с клавиатурой.

Файлы file of тип являются типированными файлами прямого доступа. Это означает, во первых, что компоненты файла имеют один и тот же тип, а о вторых, что доступ к содержимому файла ведется произвольно, в любую позицию. Таким образом, например, если нам требуется записать в середину файла вещественных чисел новое число, мы легко можем произвести установку файловой позиции в требуемое местоположение и произвести запись.

Не следует использовать для хранения строк тип file of string. Такое определение подразумевает, что для каждой строки будет резервироваться 256 байт внутри файла. Это очень неэффективный подход с точки зрения экономии дискового пространства. Лучше в такой ситуации, хотя и в ущерб скорости, воспользоваться текстовыми файлами.

Файлы file являются нетипированными файлами прямого доступа. У нетипированных файлов отсутствует заранее определенная структура. Запись и чтение для таких файлов производится блоками, состоящими из последовательностей байтов. Размер блоков задается при открытии файла.

Типированные и нетипированные файлы отличаются от текстовых тем, что информация в них хранится в том же формате, что и в оперативной памяти компьютера. Это означает, с одной стороны, значительно меньший размер по сравнению с текстовыми, а с другой - невозможность, в большинстве случаев, редактирования содержимого таких файлов с помощью любых текстовых редакторов. К счастью, ТП имеет достаточно средств для создания специальных программ просмотра и редактирования нетекстовых файлов.

Принципы работы с файлами

Общий принцип обработки содержимого файлов состоит в следующей последовательности действий:

1. Сопоставление файловой переменной и конкретного файла на диске.2. Открытие файла.3. Чтение из файла или (и) запись в файл.

89

Page 90: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

4. Закрытие файла.Рассмотрим стандартные процедуры, позволяющие реализовать принципы

работы с файлами. Сопоставление файлов

procedure Assign(var f; name: string);Процедура Assign сопоставляет файловую переменную F конкретному файлу на диске с именем Name.

Открытие файловprocedure Reset(var f);

Процедура Reset открывает существующие текстовые файлы только для чтения, а типированные - для чтения и записи. F - файловая переменная, сопоставленная ранее с помощью процедуры Assign конкретному дисковому файлу.

procedure Reset(var f:file[; recsize: Word]);Процедура Reset открывает существующий нетипированный файл F для чтения и записи. F - файловая переменная, сопоставленная ранее с помощью процедуры Assign конкретному дисковому файлу. Recsize - размер одной записи в файле. Если Recsize отсутствует, считается, что размер одной записи равен 128 байтам

procedure Rewrite(var f);Процедура Rewrite создает текстовые файлы только для записи, а типированные - для чтения и записи. F - файловая переменная, сопоставленная ранее с помощью процедуры Assign конкретному дисковому файлу. Если файл с таким именем уже существовал на диске, он предварительно удаляется.

procedure Rewrite(var f:file[; recsize: Word]);Процедура Rewrite создает нетипированный файл F для чтения и записи. F - файловая переменная, сопоставленная ранее с помощью процедуры Assign конкретному дисковому файлу. Recsize - размер одной записи в файле. Если Recsize отсутствует, считается, что размер одной записи равен 128 байтам. Если файл с таким именем уже существовал на диске, он предварительно удаляется.

procedure Append (var f:text);Процедура Append открывает текстовый файл F для добавления в него информацией. F - файловая переменная, сопоставленная ранее с помощью процедуры Assign конкретному дисковому файлу.

Чтение и запись файловДля доступа к содержимому текстовых файлов используются процедуры Read, Readln, Write, Writeln, причем первым параметром передается имя файловой переменной. Методы обработки текстовых файлов с помощью этих процедур ничем не отличаются от методов обработки клавиатуры и экрана.Для доступа к содержимому типированных файлов используются процедуры Read и Write, причем первым параметром также передается имя файловой переменной. Тип записываемых или считываемых переменных не должен отличаться от типа сохраненной в файле информации. В качестве параметров процедуры Write запрещено использовать выражения.

90

Page 91: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

procedure BlockRead(var f: file; var Buf; Count: Word [; var Result: Word])Процедура BlockRead читает в переменную Buf Count записей из файла F (размер каждой записи определен при открытии файла). В переменной Result возвращается число действительно прочитанных записей.

procedure BlockWrite(var f: file; var Buf; Count: Word [; var Result: Word])Процедура BlockWrite Записывает в файл F Count записей из переменной Buf. В переменной Result возвращается число действительно сохраненных записей. Процедуры BlockWrite и BlockRead не могут обрабатывать более 64 килобайт информации за один раз.

Закрытие файлаprocedure Close(var f);

Процедура Close закрывает файл F. Закрытие файлов требуется для освобождения всех файловых буферов в оперативной памяти, а также ресурсов, затребованных у операционной системы при открытии файла. По завершении работы программы все незакрытые файлы автоматически закрываются.

Задача 38 . Написать две программы. С помощью первой из них создать и заполнить типированный файл десятью целыми числами. Вторую использовать для просмотра содержимого файла, сформированного первой программой.

Решение:{-----------первая программа------------}

var f:file of integer;i,v:integer;s:string;

begin write('Введите имя файла:'); readln(s); Assign(f,s); Rewrite(f); {сопоставляем файловую переменную и создаем текстовый файл} writeln('Эти значения будут сохранены в файле:'); for i:=1 to 10 do begin {заполняем файл} v:=random(101)-50; {получаем случайное значение из промежутка

[-50,50]} write(f,v); {сохраняем полученное число в файле ...} write(v:4);{... а также выводим его на экран} end; {файл заполнен} writeln; close(f);{закрываем файл} readln; end.

{-----------вторая программа------------}var f:file of integer;

i,v:integer;s:string;

begin write('Введите имя файла:'); readln(s); Assign(f,s); Reset(f); {сопоставляем файловую переменную и открываем текстовый файл

для чтения} write('Содержимое файла ',s,': ');

91

Page 92: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

for i:=1 to 10 do begin {считываем содержимое файла} Read(f,v);{считываем очередное число из файла} write(v:4);{выводим полученное значение на экран} end;{содержимое файла прочитано} writeln; close(f);{закрываем файл} readln; end.

Задача 39 . Написать две программы. С помощью первой из них создать и заполнить типированный файл (file of byte) размером в 100000 байт. С помощью второй создать аналогичного размера нетипированный файл. Сравнить скорости работы обеих программ.

Решение:{-----------первая программа------------}

var f:file of byte;i:longint;b:byte;s:string;

begin write('Введите имя файла:'); readln(s); Assign(f,s); Rewrite(f);{сопоставляем и открываем типированный файл для записи} for i:=1 to 100000 do write(f,b);{сохраняем 100000 байт в файле} close(f);{закрываем файл} writeln('Файл сохранен'); readln; end.

{-----------вторая программа------------}var f:file;

b:array [1..50000] of byte;s:string;

begin write('Введите имя файла:'); readln(s); Assign(f,s); Rewrite(f,1); {сопоставляем и открываем нетипированный файл для записи,

устанавливая размер одной записи в 1 байт} BlockWrite(f,b,50000);{сохраняем первую половину требуемого содержимого файла} BlockWrite(f,b,50000);{сохраняем вторую половину требуемого содержимого файла} close(f); writeln('Файл сохранен'); readln; end.Первая программа на компьютере с процессором Pentium-120 выполняется около 20 секунд,

вторая - практически мгновенно. Выводы сделайте сами.Задача 40 . Написать две программы. С помощью первой из них создать и заполнить типированный файл сотней чисел. С помощью второй создать аналогичный текстовый файл. Сравнить содержимое и размеры первого и второго файлов.

Решение:{-----------первая программа------------}var f:file of integer; i,v:integer; s:string;

92

Page 93: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

begin randomize; write('Введите имя файла:'); readln(s); Assign(f,s); Rewrite(f); for i:=1 to 100 do begin v:=random(300)-200; write(f,v); end; close(f); writeln('Файл сохранен'); readln; end.

{-----------вторая программа------------}var f:text;

i,v:integer;s:string;

begin randomize; write('Введите имя файла:'); readln(s); Assign(f,s); Rewrite(f); for i:=1 to 100 do writeln(f, integer(random(300)-200));

{Обратите внимание на приведение типов (см. параграф 1.9.5) в процедуре Writeln. Дело в том, что функция Random возвратит значение типа Word, который не имеет отрицательного диапазона. Без приведения типов мы получим множество значений в промежутках [0,100) и [65335,65535], а не в промежутке [-200,100), как должно бы быть, судя по программе}

close(f); writeln('Файл сохранен'); readln; end.После выполнения обеих программ вы наверняка заметите, что размер первого

(типированного) файла постоянен и равен 200 байт (100 значений типа Integer умножить на 2 байта памяти для каждого числа), в то время как размер текстового файла изменяется от запуска к запуску второй программы и превышает размер первого файла по крайней мере в полтора раза.

Файловая позиция

Чтение или запись любого файла происходит последовательно, блок за блоком. Местоположение в файле, откуда при последующем обращении к файлу произойдет чтение или куда будет произведена запись, называется файловой позицией.

Для всех файлов, кроме текстовых, существует возможность принудительного перемещения файловой позиции в любую точку файла, а также чтение текущей файловой позиции.

Файловая позиция отсчитывается от 0.Получение файловой позиции

function FilePos(var f): Longint;

93

Page 94: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

Функция FilePos возвращает файловую позицию в файле F.function FileSize(var f): Longint;

Функция FileSize возвращает последнюю возможную файловую позицию (ее можно рассчитать по формуле: размер файла в байтах/размер одной записи). Для файлов, размер одной записи которых составляет 1 байт, FileSize возвращает размер файла. В общем случае, FileSize возвращает количество компонентов файла.

Установка файловой позицииprocedure Seek(var F; N: Longint);

Процедура Seek устанавливает файловую позицию файла F в N.Операции над файлом, зависящие от текущей файловой позиции

function Eof(var F): Boolean;Возвращает True, если файловая позиция находится за концом типированного или нетипированного файла.

function Eof [ (var F: Text) ]: Boolean;Возвращает True, если файловая позиция находится за концом текстового файла. Если файловая переменная отсутствует, то используется переменная Input (клавиатура).

function Eoln [(var F: Text) ]: Boolean;Возвращает True, если файловая позиция находится за концом строки текстового файла. Если файловая переменная отсутствует, то используется переменная Input (клавиатура).

procedure Truncate(var F);Отсекает конец файла, начиная с текущей файловой позиции.

Задача 41 . Ввести набор из N чисел, сохранить его в файле. Организовать цикл, в котором по введенному индексу определяется и выводится на экран числовое значение из файла. Предусмотреть выход их цикла.

var f:file of real;v:real;i,n:integer;

begin write('Введите количество чисел: '); readln(n); assign(f,'Real.fil'); Rewrite(f); for i:=1 to n do begin {заполняем файл вещественными числами} v:=random*1000-500; write(f,v); end; close(f);{файл заполнен, закрываем его} reset(f);{снова открываем файл (закрытие и повторное открытие файла использовано здесь

только для того, чтобы показать возможность повторного открытия файла без повторного использования процедуры Assign)}

write('Введите номер: '); readln(N); {ввели индекс} while (n>=0) and (n<=FileSize(f)-1) do begin {пока введенный индекс не вышел за пределы

файла}

94

Page 95: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

seek(f,n);{устанавливаем файловую позицию} Read(f,v);{читаем число из файла} writeln(v);{выводим его на экран} write('Введите номер: '); readln(N); {снова вводим индекс} end;

{вышли из цикла, так как введен недопустимый индекс} Close(f);{закрываем файл} readln; end.

Задача 42 . Создать программу, которая выводит на экран саму себя.В общем случае такая задача является достаточно сложной для решения, практически

олимпиадного уровня. Однако решение становится тривиальным, если воспользоваться файлом текста программы.

var f:text; s:string; i:byte; begin s:=paramstr(0); {получаем имя исполняемого файла} s:=copy(s,1,length(s)-3)+'pas'; {заменяем расширение "exe" исполняемого файла на

расширение "pas"} assign(f,s); Reset(f); while not eof(f) do begin {пока не конец файла ...} readln(f,s);{считываем строку} writeln(s);{выводим ее на экран} end; close(f); {обработка завершена, закрываем файл} readln; end.

Задача 43 . Каждая строка (до 1000) текстового файла содержит в себе набор целых чисел (до 100), разделенных пробелами. Вывести на экран содержимое файла с использованием форматирования, а так же подсчитать среднее арифметическое каждой строки файла.

Решение:var f:text;{текстовый файл}

Ac: array[1..100] of integer; {массив чисел текущей строки}Ar: array[1..1000] of real;{массив средних арифметических строк}Row, Col : integer;{количество строк в файле и количество чисел в текущей строке}i:integer;

begin assign(f,'numbers.txt');{сопоставление} reset(f);{открытие для чтения} writeln('Содержимое файла NUMBERS.TXT:'); Row:=0; while not eof(f) do begin {пока не конец файла ...} Col:=0; while not eoln(f) do begin {пока не конец строки файла ...} inc(Col); {переходим к следующему числу строки} read(f, ac[Col]); {считываем очередное числовое значение из файла в массив AC} write(ac[Col]:6); {производим форматированный вывод} end;

{информация из строки считана} readln(f);{считываем маркер конца строки из файла}

95

Page 96: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

writeln;{разделяем выводимые на экран строки}

inc(Row);{переходим к следующей строке массива AR для подсчета среднего арифметического}

ar[row]:=0; for i:=1 to Col do ar[row]:=ar[row]+ac[i]; {подсчитываем сумму элементов строк} ar[row]:=ar[row] / col; {рассчитываем среднее арифметическое} end;

{обработка файла закончена}Close(f); writeln('Средние арифметические строк:'); for i:=1 to Row do write(ar[i]:7:2); {выводим на экран средние арифметические строк

файла} writeln; readln;end.Если, например, файл number.txt имеет следующее содержимое:1 34 -2 35 43 1 2 -2 -2 7 -823 3 45 -3 22 12 -21 2 43 -43 5 6 72 37 89 7то в результате работы программы на экране появится:Содержимое файла NUMBERS.TXT: 1 34 -2 35 43 1 2 -2 -2 7 -8 23 3 45 -3 2 2 12 -21 2 43 -43 5 6 7 2 3 7 89 7Средние арифметические строк: 9.91 14.00 1.44 2.50 34.33

Дополнительные процедуры и функции для работы с файлами

Обработка ошибокfunction IOResult: Integer;

Во время работы с файлами могут возникать различные ошибки. Если установлена директива компилятора {$I+}, то работа программы при этом аварийно завершается. Если установлена директива компилятора {$I-}, то с помощью функции IOResult можно определить номер последней ошибки ввода-вывода. IOResult возвращает 0, если ошибки не произошло. Если произошла ошибка, то до вызова IOResult все операции с файлами будут заблокированы

Обработка файлов, не связанная с их содержимымprocedure Rename(var F; Newname:string);

Переименовывает файл, сопоставленный с файловой переменной F в Newname. Файл не должен быть открыт.

procedure Erase(var F);

96

Page 97: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

Удаляет файл, сопоставленный с файловой переменной F. Файл не должен быть открыт.

Обработка каталоговprocedure ChDir(S: String);

Переходит в каталог с именем S.procedure MkDir(S: String);

Создает каталог с именем S.procedure RmDir(S: String);

Удаляет каталог с именем S.Задача 44 . Дано имя файла. Проверить, существует ли файл с таким именем он на диске.

var f:file;s:string;

begin write('Введите имя файла:'); readln(s); {$I-}{отключаем проверку ошибок ввода-вывода} assign(f,s); Reset(f);{пытаемся открыть файл} {$I+}{включаем проверку ошибок ввода-вывода} if ioresult<>0 then {попытка открытия файла окончилась неудачно}

writeln ('Такого файла на диске нет') else begin {файл открыт успешно ...} writeln('Файл существует'); close(f);{... не забудем его закрыть} end; readlnend.

Задачи для раздела "Файловые типы"

В задачах данного раздела подразумевается, что результат работы программ оценивается, по возможности, с экрана.Задание 76. Создать программу, в которой вводятся с клавиатуры произвольные числа, пока не будет введен 0, и сохраняются в текстовом файле только те из них, которые кратны 7.Задание 77. Дан текстовый файл, заполненный целыми числами (создать в любом текстовом редакторе). Вывести на экран только те из них, порядковый номер которых равен значению числа.Задание 78. Дан текстовый файл, заполненный целыми числами и одномерный массив из 5 целых чисел. Вывести на экран в только те числа из файла, которые равны одному из чисел массива.Задание 79. Дан текстовый файл, заполненный целыми числами (создать в любом текстовом редакторе). Вывести их на экран в обратном порядке.Задание 80. Создать и заполнить одними и теми же строками 2 файла. Первый - текстовый файл, второй - типированный файл строк. В операционной системе сравнить размеры и содержимое обоих файлов. Сделать выводы. Задание 81. Дан файл, компоненты которого являются целыми числами. Найти сумму всех компонент файла.Задание 82. Создать две программы. Первая из них заполняет файл геометрическими фигурами (см. Задание 67). Вторая программа по введенному номеру считывает из файла запись и выводит ее содержимое на экран.

97

Page 98: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Файловые типы

Задание 83. Создать программу копирования одного файла в другой. Оптимизировать по скорости выполнения.

1.9.2.6 Объектные типы (обзор)Объектный тип является наиболее абстрактным и мощным из структурных

типов. Он содержит в себе не только данные (поля объекта), но и средства их обработки (методы объекта), то есть, если рассматривать его с алгебраических позиций, представляет собой множество с определенными на нем операциями. Это свойство объектов называется инкапсуляцией. Объекты могут наследовать поля и методы друг друга, добавляя при этом свои собственные. Данное свойство называется наследованием. И, наконец, объекты-потомки могут переопределять методы предков, полностью или частично изменяя тем самым реакцию объектов-предков на различные события. Такое поведение называется полиморфизмом.

Объектный тип ::= "object" ["("объект_предок")"]

{["private" | "public"]}поля_объектазаголовки_методов_объектов

"end".Методы объектов могут быть статическими и виртуальными процедурами и

функциями. Виртуальная процедура или функция может быть переопределена внутри объекта-потомка в рамках полиморфизма (допускается также переопределение статической процедуры или функции, однако свойства объекта-предка при этом не изменяются).

Объектный тип ТП поддерживает также специальные методы-процедуры, которые называются констракторами и дестракторами. Констракторы используются для инициализации переменных типа объект, и вызываются перед началом работы с объектом. Дестракторы завершают работу с объектом.

Пример:type

Point=object{поля объекта}

x, y : integer;{заголовки методов объекта}constructor Init(new, NewY:integer);destructor Done; virtual;procedure SetXY(new, NewY:integer);{скрытые поля и заголовки методов объекта}

private OldX,OldY:integer;

Procedure ClearXY;end;

TCircle= object(point) {наследование от point}{поля объекта}

98

Page 99: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Объектные типы (обзор)

R : integer;{заголовки методов объекта}

constructor Init(new, NewY, NewR:integer);procedure SetRadius(NewR:integer);{скрытые поля и заголовки методов объекта}

private OldR: integer;

Procedure ClearR;end;В разделе объявления процедур и функций все методы объекта должны быть

определены.Например:…constructor TCircle.Init(new, NewY, NewR:integer); begin

inherited Nit(new, NewY); {вызов метода предка}R:=NewR;

end;…Определение переменных объектного типа и обращение к ним происходит

аналогично записям (то есть с помощью символа "." или оператора With).Пример:…var S:Tpoint;begin … s.Init(10,20); …with s do begin SetXY(x*10,y*10);end; … s.done;…end.Подробно данный тип, его свойства и область применения мы рассмотрим во

второй главе нашего пособия.

1.9.3 УказателиТип указатель определяет адрес памяти для переменной базового типа.

Указатели является одним из наиболее важных и часто применяемых типов в разработке серьезных программных продуктов. Указатели позволяют создавать сложные, динамически изменяющиеся во время работы программы типы данных, такие как графы, деревья, списки (очереди, стеки) и т.д.

Тип_указатель::= ("^" базовый_тип) | "Pointer"Базовый_тип::= ИД типа.

99

Page 100: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Указатели

Указатель может быть типированным, то есть указывать на переменную некоторого типа, и может быть нетипированным (pointer), то есть указывать на переменную произвольного типа. Если указатель имеет нулевое значение, его значение равно nil. В независимости от типа указателя, его размер в памяти компьютера постоянен и равен 4 байтам. Для обращения к переменной, адрес которой хранится в указателе, требуется после имени указателя ставить знак "^".

В ТП существует специальная операция @ (см. параграф 1.6.3.6), с помощью которой можно получить указатель на любую переменную, процедуру или функцию

Пример:var a:integer;

pa1,pa2:^integer;begin pa1:=@a; {получаем адрес переменной a и присваиваем его

указателю Pa1} pa2:=pa1; {присвоили указателю Pa2 значение указателя Pa1. Теперь Pa1 и Pa2 указывают

на одну и ту же область памяти} pa1^:=7; pa2^:=6; writeln(a,' ',pa1^,' ',pa2^);end.В результате работы программы на экране появятся три числа 6.Оперативная память компьютера, выделенная операционной системой для

программы, делится на несколько частей:1) Область кода, где хранится исполняемая часть программы (максимум 64К

на модуль).2) Область стека, где хранятся вызовы и локальные переменные процедур и

функций (максимум 64К).3) Область статических данных, где хранятся все глобальные переменные и

размер которой равен 64К.4) Область динамических данных или куча (вся оставшаяся память,

запрошенная программой у операционной системы и объем которой в реальном режиме может в 8-10 раз превышать объем области статических данных, а в защищенном - достигать 16 мегабайт). ТП позволяет произвольно выделять память из кучи блоками любого размера до 64К, а после использования - возвращать обратно.

Динамическая переменная - это переменная-указатель, оперативная память для которой выделяется из области динамических данных во время выполнения программы. По окончании использования переменной память должна быть освобождена, чтобы в дальнейшем ее можно было выделить для другой динамической переменной.

Процедуры для работы с динамической памятьюВыделение памяти для динамических переменных

procedure New(var P: Pointer);Процедура New выделяет память для динамической переменной P. Объем

100

Page 101: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Указатели

выделяемой памяти рассчитывается на основе типа переменной. Таким образом, требуется, чтобы переменная P была типированным указателем.

procedure GetMem(var P: Pointer; Size: Word);Процедура GetMem выделяет память объемом в Size байт для динамической переменной P, которая может быть указателем любого типа.Процедуры New и GetMem могут стать причиной аварийной остановки программы, если размер затребованной памяти превышает размер максимального свободного блока.

Освобождение памяти, выделенной ранее для динамических переменных

procedure Dispose(var P: Pointer);Процедура Dispose освобождает динамическую переменную P. Используется в паре с процедурой New.

procedure FreeMem (var P: Pointer; Size: Word);Процедура FreeMem освобождает динамическую переменную P объемом в Size байт. Используется в паре с процедурой GetMem.По завершении работы программы вся память, выделенная из кучи, автоматически освобождается.

Альтернативный метод освобождения динамической памятиprocedure Mark (var p: pointer);

Процедура Mark сохраняет состояние кучи в указателе P. Используется совместно с процедурами New и GetMem.

procedure Release(var p: pointer);Процедура Release освобождает все динамические переменные, память для которых была выделена после использования Mark с указателем P.Процедуры Mark и Release не должны использоваться совместно с Dispose и FreeMem. Мы вообще не советуем пользоваться этими процедурами, как устаревшими и включенными в язык только для совместимости с предыдущими версиями.

Состояние динамической памятиfunction MemAvail: Longint;

Процедура Memavail возвращает объем свободной памяти в куче.function MaxAvail: Longint;

Процедура MaxAvail возвращает объем максимального свободного блока памяти в куче. В идеальном случае значения, возвращаемые процедурами MemAvail и MaxAvail, равны. Однако при частом выделении и освобождении блоков возможна дефрагментация кучи. В самом худшем случае может оказаться. что нет возможности выделить память для указателя, несмотря на то, что общий объем кучи превышает затребованный в несколько десятков раз.

Адресация памятиТП позволяет напрямую взаимодействовать с адресами памяти компьютера.

101

Page 102: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Указатели

Каждый байт памяти IBM PC адресуется в реальном режиме с помощью двух значений - сегмента и смещения. Следующие функции преобразовывают адреса переменных в сегмент и смещение, а сегмент и смещение - в указатели. Получение сегмента и смещения любого объекта ТП может оказаться полезным при прямом обращении к памяти с помощью предопределенных массивов Mem, MemW и MemL (см. параграф 1.9.2.1)

function Seg(X): Word;Функция Seg возвращает сегментную часть адреса объекта X

function Ofs(X): Word;Функция Ofs возвращает смещение объекта X

function Ptr(Seg, Ofs: Word): Pointer;Функция Ptr возвращает указатель, сформированный из сегмента и смещения

function Addr(X): pointer;Функция Addr возвращает указатель на объект X

Этапы работы с динамической переменной:1) Определение ДП.2) Выделение памяти для ДП или присваивание ей адреса некоторого

объекта (переменной, процедуры или функции, произвольной области памяти и т.д.).

3) Работа с динамической переменной.4) Освобождение памяти, выделенной для динамической переменной.Например:

type Arr=Array[1..20000] of integer; {определяем тип массива размером в 40000 байт }var a:array[1..10000]of ^arr;{определяем массив указателей на массив}

i,n:integer;begin n:=0; writeln('Исходный объем динамической памяти: ', MemAvail,

' байт'); while MaxAvail>=sizeof(arr) do begin {пока объем кучи достаточен} inc(n);{переходим к следующему элементу массива} New(a[n]);{выделяем память} end; writeln('Удалось выделить память только для ', n,

' элементов массива'); writeln('Осталось памяти ', MemAvail, ' байт'); for i:=1 to n do dispose(a[i]);{освобождаем массив динамических переменных} readln;end.

Задачи для раздела "Указатели"

В нескольких задачах данного параграфа предусматривается обработка

102

Page 103: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Указатели

многомерных массивов, не помещающихся целиком в оперативной памяти. Для разрешения данной проблемы мы предлагаем использовать массивы указателей на массив.Задание 84. Заполнить случайными числами 2 байтовых массива, каждый размером в 35000 байт. Сравнить содержимое массивов и подсчитать количество элементов первого из них, равных соответствующим элементам (с тем же индексом) второго.Задание 85. Дан текстовый файл размером не менее 1000 строк. Сохранить его в другом текстовом файле задом наперед (то есть первая строка становится последней, вторая - предпоследней и т.д.). Предусмотреть обработку ошибок в случае нехватки оперативной памяти.Задание 86. Дана действительная матрица размером 200 на 200 элементов. Заполнить ее случайными числами и подсчитать сумму элементов главной и побочной диагоналей.Задание 87. Дана целочисленная матрица размером 20 на 5000 элементов. Заполнить ее случайными числами и определить средние арифметические элементов строк.

103

Page 104: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедурные типы (обзор)

1.9.4 Процедурные типы (обзор)В ТП процедуры и функции рассматриваются как объекты, которые можно

присваивать переменным, передавать в качестве параметров и т.д. Для этого существуют процедурные типы.

Процедурный_тип ::= ("procedure" [список_формальных_параметров]) |("function" [список_формальных_параметров] ":" тип).

После его определения можно объявлять переменные процедурного типа.Пример:type Proc = procedure; SwapProc = procedure(var X, Y: Integer); StrProc = procedure(var S: String); MathFunc = function(X: Real): Real: DeviceFunc = function(var F: Text): Integer; MaxFunc = function(A, B: Real; F: MathFunc): Real;var A: SwapProc; B: StrProc; С: MaxFunc;…Этим переменным можно присваивать идентификаторы глобальных процедур

и функций, скомпилированных по дальней модели вызова (см. параграф 1.10.5.1)Более подробно процедурные типы мы рассмотрим в параграфе 1.10.4.

1.9.5 Приведение типовПриведение типов используется для преобразования выражения одного типа в

другой. Порядковые типы преобразуются друг в друга безо всяких ограничений. В остальных случаях приведение типов запрещено, только если различны объемы памяти, занимаемые переменными этих типов.

Например, нельзя преобразовать один в другой два типа записи, если первый содержит 3 поля типа Char, а второй - 2 поля типа Word. В то же время можно преобразовать запись с двумя байтовыми полями к типу Integer и тип Longint к типу Boolean.

Синтаксис приведения типа аналогичен вызову функции с одним параметром.Приведение_типа::=

тип_результата "(" выражение_исходного_типа ")"Например:

Вместо функции Ord можно использовать преобразование типа:var a:word;begin

a:=word('0');writeln(a);

end.Для доступа к младшему и старшему байтам значения типа Word можно воспользоваться

следующим методом:type

ByteRec = record {тип записи для получения доступа к байтам слова}

104

Page 105: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Приведение типов

Lo,Hi : Byte;end;

varW: Word;

beginW := $709;writeln(ByteRec(W).Lo);writeln(ByteRec(W).Hi);readln;

end.После запуска на экране появятся числа 9 (младший байт) и 7(старший байт). Аналогичного

результата можно добиться следующей программой:var W: Word;

p:^byte; {объявляем переменную - указатель на байт}begin

p:=@w; {присваиваем указателю адрес слова}W := $709;writeln(p^); {выводим младший байт}inc(longint(p)); {увеличиваем указатель, прибегая к преобразованию его в тип longint, так

как процедура Inc ожидает передачи ей значения порядкового типа}writeln(p^); {выводим старший байт}readln;

end.

1.9.6 Совместимость типовВ любом выражении ТП требуется совместимость типов. Совместимость

типов имеет место, если выполняется хотя бы одно из следующих условий:1) оба типа являются одинаковыми2) оба типа являются вещественными типами3) оба типа являются целочисленными4) один тип является поддиапазоном другого5) оба типа являются поддиапазоном одного и того же основного типа6) оба типа являются типами множеств с совместимыми базовыми типами7) оба типа являются упакованными строковыми типами с одинаковым

числом компонент8) один тип является строковым, а другой - либо строковым, либо

упакованным строковым типом, либо типом Char9) Один тип - Pointer, а другой - любой тип указателя10) Оба типа являются процедурными типами с тождественными типами

результата, с тождественным числом параметров, с тождественными (один в один) типами параметров.

Совместимость по присваиванию необходима с случае использования оператора присваивания или при передаче значений параметров процедурам или функциям.

Значение типа Т2 является совместимым по присваиванию с типом Т1 (т.е. допустимо Т1:=Т2), если выполняется одно из следующих условий:

105

Page 106: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Совместимость типов

1. - Т1 и Т2 являются тождественными типами, и ни один из них не является файловым типом или структурным типом, содержащим компоненту с файловым типом на одном из своих уровней.

2. - Т1 и Т2 являются совместимыми порядковыми типами и значения типа Т2 попадают в диапазон возможных значений Т1.

3. - Т1 и Т2 являются вещественными типами и значения типа Т2 попадают в диапазон возможных значений Т1.

4. - Т1 является вещественным типом, а Т2 является целочисленным типом.5. - Т1 и Т2 являются строковыми типами.6. - Т1 является строковым типом, а Т2 является типом Char.7. - Т1 является строковым типом, а Т2 является упакованным строковым типом.8. - Т1 и Т2 являются совместимыми упакованными строковыми типами.9. - Т1 и Т2 являются совместимыми типами множеств, и все значения типа Т2

попадают в диапазон возможных значений Т1.10.- Т1 и Т2 являются совместимыми типами указателей.11.- Т1 и Т2 являются совместимыми процедурными типами.12.- Т1 является процедурным типом, а Т2 является процедурой или функцией с

тождественным типом результата, с идентичным числом параметров и тождественностью один-в-один между типами параметров.

13.- Объект типа Т1 совместим по присваиванию с объектом типа Т2, если Т2 находится в области определения Т1.

14.- Указатель типа Р2, указывающий на тип объекта Т2, совместим по присваиванию с указателем типа Р1, указывающим на тип объекта Т1, если Т2 лежит в области определения Т1.

На этапе компиляции выдается сообщение об ошибке, если совместимость по присваиванию необходима, а ни одно из условий предыдущего списка не выполнено.

106

Page 107: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедуры и функции

1.10 Процедуры и функцииПроцедуры и функции в ТП используются для сокращения записи

повторяющихся частей программы. Каждое объявление процедуры включает в себя заголовок и тело процедуры. Процедура вызывается с помощью оператора процедуры. Функции в ТП отличаются от процедур тем, что возвращают значение любого типа размером в 1, 2, 4 байта или типа String и вызываются внутри выражений.

1.10.1 Объявление процедур и функцийКаждая процедура или функция в ТП должна быть объявлена в разделе

объявлений процедур и функций перед ее вызовом, как было показано в параграфе 1.5.Обявление_процедуры ::= заг_проц тело_проц ";".

В заголовке процедуры описывается имя процедуры и список формальных параметров:Заг_проц ::= "procedure" ИД

["(" объявление_параметра {";" объявление_параметра }")"] ";".объявление_параметра::=["var" | "const"] список_ИД [":" тип_параметра].тип_параметра::= ИД_типа | "string" | "file" | ("array" "of" ИД_типа).Тело_проц ::= ([("near" | "far" | "interrupt") ";"]

(БЛОК | "forward"| "external" | блок_asm)) | директива_inline.Тело процедуры содержит в себе либо блок объявлений и операторов (блок,

см. параграф 1.5), либо блок программы на ассемблере (блок_asm), либо процедурные директивы, указывающие, что блок будет определен в другом месте программы (forward, external). Дополнительно могут использоваться директивы, определяющие некоторые внутренние свойства и область применения процедуры (near, far, interrupt).

Примеры объявления процедур:procedure Exec(Path, CmdLine: string);

begin ... end;procedure FindFirst(Path: PChar; Attr: Word; var F: TSearchRec);

{ TSearchRec - ранее определенный тип}begin ... end;

procedure S(var T:real; const x: array of real);begin ... end;

{$L my.obj}procedure X(a:byte);external; {X - процедура на ассемблере в файле my.obj}procedure Y(b:integer);forward; {предопределение процедуры Y}procedure Z(c:longint);far;

begin ... end;procedure Y(b:integer); {фактическое определение тела процедуры Y}

begin ... end;Тело процедуры также может состоять только из директивы inline, которая

является макроопределением на машинном коде.

107

Page 108: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Объявление процедур и функций

Объявление функции отличается от объявления процедуры заголовком и невозможностью применения к телу функции директивы interrupt:Заголовок_функции::= "function" ИД

["(" объявление_параметра {";" объявление_параметра }")"] ":" ИД_типа ";".

Идентификатор типа, идущий за двоеточием, определяет тип значения, возвращаемого функцией.

Примеры объявления функций:function Max(x,y:real):real; begin ... end;function N(x,y:longint):string; asm ... end;function D(a:byte):string; near; begin ... end;function E(var S:string):byte; inline ( ... );Функции в ТП отличаются от процедур тем, что возвращают некоторый

результат и могут быть использованы в выражениях. В составном операторе тела функции должен быть хотя бы один оператор присваивания, слева от которого стоит ИД функции (см. параграф 1.5.2). Присваивание значения функции может производиться произвольное количество раз.

Пример:function Max(x,y:real):real; {определение максимального из двух чисел}

begin if x>y then

max:=x {присваивание результата функции}else

max:=y; {присваивание результата функции}end;

Функции не могут быть функциями обработки прерываний.

1.10.2 Формальные и фактические параметры.Каждый параметр, объявленный в списке формальных параметров, является

локальным по отношению к данному блоку, т.е. не видим за его пределами. Это означает, в частности, что в списке формальных параметров можно использовать переменные с такими же именами, как в основной программе или других процедурах и функциях. Данное правило верно и для локальных, т.е. объявленных внутри процедуры или функции, переменных.

Например:var a: byte; {определяем глобальную переменную с именем A}procedure One(a:byte); {определяем процедуру One с аргументом A}

var b:byte; {определяем локальную переменную B процедуры One} procedure Two; var a:byte; {определяем локальную переменную A процедуры Two} begin

…a:=89;{значение присваивается локальной переменной A процедуры Two}b:=a; {значение локальной переменной A процедуры Two присваивается локальной

переменной B процедуры One }…

108

Page 109: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Формальные и фактические параметры.

end; {процедура Two завершена …} begin {… начинается процедура One }

…a:=98;{значение присваивается переменной A из процедуры One}

… end; {процедура One завершена …}begin {… начинается основная программа }

…a:=0; {значение присваивается глобальной переменной A}

…end.Существует 3 вида формальных параметров: Параметр-значение, Параметр-

переменная, Параметр-нетипированная переменная.1) Параметр-значение - без "var" или "const", но с типом параметра.Параметр-значение является полностью локальным, за исключением того,

что принимает начальное значение от фактического параметра, переданного в процедуру или функцию. Любое изменение параметра-значения внутри составного оператора процедуры или функции не влияет на значение фактического параметра. С помощью параметра-значения можно передавать информацию в процедуру или функцию, но не обратно.

Фактический параметр, соответствующий параметру-значению в операторе процедуре или вызове функции может быть выражением любого типа, совместимого по присваиванию с типом формального параметра.

Например:

procedure X(A:integer); begin a:=7; end; var d:integer;begin {основная программа} d:=8; x(d); writeln(d);

end.

A - формальный параметр

D - фактический параметр

В результате работы программы на экране появится число 8.2) Параметр-переменная - с "var" или "const", и с типом параметра.

Компилятор запрещает изменять параметр, предваряемый зарезервированным словом const.

Параметр-переменная используется как для передачи информации в процедуру или функцию, так и обратно. Любое изменение формального параметра-переменной сказывается и на фактическом параметре.

Фактический параметр, соответствующий формальному параметру-переменной, должен быть переменной с типом, тождественным формальному параметру.

Например:Если заголовок процедуры определен следующим образом:

109

Page 110: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Формальные и фактические параметры.

procedure A(var b:byte); то компилятор выдаст ошибку при попытке ее вызова с константным значением или

выражением в качестве аргумента.procedure A(var b:byte);

begin…

end;var x:integer; y:byte;begin

…a(7); a(4+y); a(x); {неверные вызовы!!!}a(y); {правильный вызов}…

end.Файловые типы могут передаваться только как параметры-переменные.Параметры-переменные отличаются от параметров-значений методом

передачи данных. Если параметр-значение - это копия фактического параметра, то параметр-переменная - это ссылка на фактический параметр, его адрес в памяти компьютера. Из этого вытекает еще одна особенность параметров-переменных: объем памяти, выделяемый для них, неизменен и равен 4 байтам. Таким образом, если в процедуру или функцию требуется передать, например, массив большого размера, то для ускорения работы программы и экономии памяти желательно осуществить его передачу как параметра-переменной. В то же время, если требуется запретить изменение переданного массива, можно вместо зарезервированного слова var воспользоваться словом const.

Например:procedure X(var A:integer); begin a:=7; end;var d:integer;

begin {основная программа}d:=8;x(d);writeln(d);

end.В результате работы программы на экране появится число 7.3) Параметр-нетипированная переменная - с "var" или "const", и без типа

параметра.Если параметр является нетипированным, то соответствующий фактический

параметр может быть переменной любого типа. В этом случае внутри процедуры или функции может потребоваться преобразование типа или использование абсолютных переменных для параметра. Задача 45 .

1) Создать функцию - аналог стандартной процедуры Val, которая будет возвращать целочисленный эквивалент переданной ей строки. Проверку на ошибки в тело функции не включать.

2) Создать функцию - аналог стандартной процедуры Val, которая будет возвращать как параметр-переменную целочисленный эквивалент переданной ей строки. В качестве результата функции возвращать логическое значение, показывающее, удачно произошел перевод, или нет.

110

Page 111: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Формальные и фактические параметры.

3) Создать функцию перевода из целого числа в строку. Проверить результат действия всех трех функций.Решение:{-------- функция StrToInt ---------}function StrToInt(S:string):longint;{функция перевода из строки в число} var V:longint; Code:integer; begin val(s,v,code); StrToInt:=v; {результат перевода присвоили значению функции} end;{-------- функция StrToIntB ---------}function StrToIntB(S:string; Var V: longint):boolean;{функция перевода из строки в число с проверкой} var Code:integer; begin val(s,v,code); StrToIntB:=code=0;{При отсутствии ошибок перевода функция возвращает True } end;{-------- функция IntToStr ---------}function IntToStr(v:longint):string; {функция перевода из числа в строку} var S:string; begin str(v,s); IntToStr:=s; {результат перевода присвоили значению функции} end;

{---------------начинается основная программа-----------------------} var s:string; v:longint; begin {Начало основной программы, проверка действий разработанных функций} write('Введите целое число '); readln(v); writeln('Вот его перевод в строку - ',IntToStr(v)); writeln('А вот обратный перевод - ',StrToInt(IntToStr(v))); write('Введите строку '); readln(s); if not StrToIntB(s,v) then writeln('Строка не может быть переведена в целое число') else writeln('Результат перевода - ',v); readln; end.

Задача 46 *. Дано натуральное число N<10000. Вычислить и вывести на экран 2N.Решение:Основная проблема, возникающая при решении задачи, состоит в невозможности

произвести расчет с достаточной степенью точности. Для типа longint, с максимальным диапазоном значений среди целочисленных, возможно возведение в степень до 230. Для типа extended, рекордсмена по диапазону значений и точности среди вещественных типов, невозможно без потерь возвести двойку в более чем 59 степень.

Поэтому, вместо того, чтобы воспользоваться одним из встроенных типов и операцией умножения, мы произведем эмуляцию целочисленного типа с помощью массива и создадим процедуру умножения двойки (вернее, любой цифры) на массив. Постараемся сделать эту процедуру максимально универсальной для дальнейшего использования, например, для расчета в

111

Page 112: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Формальные и фактические параметры.

других системах счисления.При таких больших числах возникает еще одна проблема. Если мы желаем манипулировать

при выводе рассчитанным значением (например, ограничить кавычками, предварить фразой, увидеть результат в требуемой системе счисления и т.д.), то желательно преобразовать его в строку. На первый взгляд, никакой проблемы не существует. Можно преобразовывать каждую цифру в символ и добавлять к концу получаемой строки. Однако, например, число 2848 занимает 256 символов, что превышает максимальный размер стандартной паскалевской строки. Единственный выход из такой ситуации - использовать тип PChar, что и сделано в следующей программе:

{$X+}uses strings;{----------------процедура умножения массива на цифру--------------------}procedure Mul(var Massiv; Var Count:integer;

N:byte; NumSystem:byte);{Massiv - нетипированная параметр-переменная. Должна представлять собой исходный

массив байт (цифр) для перемножения. Count - количество цифр в массиве N - цифра - множитель. NumSystem - система счисления, в которой производится расчет}

var i,v,p:integer;A:array[1..32767]of byte absolute Massiv; {абсолютная переменная для адресации

массива} begin p:=0; {перенос, начальное значение равно 0} for i:=1 to count do begin {перебираем все цифры массива, эмулируя перемножение в

столбик} v:=a[i]*n; {получаем произведение очередной цифры массива и множителя} inc(v,p); {увеличиваем полученный предыдущим действием результат на старый перенос} a[i]:=v mod NumSystem; {заменяем текущий элемент массива младшей цифрой

рассчитанного выражения} p:=v div NumSystem; {получаем новый перенос} end; if p>0 then begin {если при выходе из цикла перенос не равен нулю, ...} inc(count); a[count]:=p; {... то увеличиваем количество элементов массива и заносим в

последний из них перенос} end; end;

{------------функция получения строки символов из массива---------------}function OutString(var Massiv; Count:integer; Dest:PChar):PChar;{Massiv - нетипированная параметр-переменная. Должна являться исходным массивом

байт (цифр) для перемножения. Count - количество цифр в массиве Dest - результирующая строка, должна иметь достаточный объем для сохранения

результата.}{-------универсальная функция перевода числа в символ---------}function IntToChar(v:byte):Char;

begin if v>9 then IntToChar:=chr(v-10+ord('A')) {если цифра находится в системе счисления,

основание которой больше 10, то преобразуем ее в символ-букву, начиная с

112

Page 113: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Формальные и фактические параметры.

латинской "A"}else IntToChar:=chr(v+ord('0')); {если цифра - в десятичной системе счисления, то преобразуем ее в символ-цифру, начиная с "0"}

end; {------------------функция IntToChar завершена---------------------}{------------------начинается функция OutString---------------------}

var i:integer; A: array[1..32767]of byte absolute Massiv; {абсолютная переменная для адресации

массива}begin

for i:=Count downto 1 do {заполняем строку преобразованными в символы цифрами из массива (с учетом того, что цифры в массиве расположены в обратном порядке, т.е. самая младшая цифра - слева, самая старшая- справа )}

Dest[Count-i]:=IntToChar(a[i]);Dest[Count]:=#0; {добавляем признак конца строки}OutString:=Dest; {возвращаем полученную строку как результат функции}

end;{------------------функция OutString завершена---------------------}{----------------начинается основная программа---------------------}

var a:array[1..10000] of byte;{массив цифр}S:array[0..10000] of char;{массив символов, эквивалент типа PChar}i:integer;

const Count:integer=1;{первоначальное количество цифр - 1}begin fillchar(a,sizeof(a),0); {заполняем нулями исходный массив цифр} a[1]:=1; {первый элемент массива - 1} Readln(n); for i:=1 to N do begin {возводим двойку в N-ю степень} mul(a,count,2,10); {умножаем двойку на массив А длинною в Count цифр, ведя расчеты в

десятичной системе счисления} end; Writeln(OutString(a,count,s)); {выводим на экран полученный результат} readln;end.Мы предлагаем читателю самому поэкспериментировать с данной программой,

различными системами счисления, различными цифрами и т.д. Попробуйте расширить набор процедур и функций для получения, например, произведения двух больших натуральных чисел.

1.10.3 Открытые массивы и строкиВ ТП версии 7.0 было введено понятие открытого массива. Открытый массив - это формальный параметр процедуры или функции,

который является одномерным массивом переменной длины, индексируемым с 0.Открытые массивы описываются как array of ИД_типа, без использования

диапазона значений. Фактическим параметром, сопоставленным открытому массиву, может быть любой одномерный массив с элементами типа ИД_типа. Аналогично открытым массивам ведется обработка строк PChar, когда последние являются формальными параметрами процедур и функций.

Для получения верхней границы открытого массива можно воспользоваться

113

Page 114: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Открытые массивы и строки

функцией High (см. параграф 1.7.1.6). Например:procedure HighA(f:array of integer);{процедура для констатации верхней границы

массива}begin

writeln('Верхняя граница массива - ',high(f)); end;

{---------основная программа------------}var x:array[1..100]of integer;{массив на 100 элементов}

y:array[-100..300] of integer; {массив на 401 элемент}begin HighA(x); HighA(y); readln;end.В результате выполнения данной программы на экране появится:Верхняя граница массива - 99Верхняя граница массива - 400Так как индексация открытых массивов ведется от 0, то значение верхней границы на

единицу меньше количества элементов массива.Задача 47 . Создать две процедуры. Первая из них заполняет случайными числами переданный ей одномерный вещественный массив. Вторая выводит на экран содержимое переданного ей вещественного массива.

procedure Fill(var f:array of real); {процедура заполнения} var i:word;begin for i:=low(f) to High(f) do f[i]:=random;end;procedure Out(var f:array of real); {процедура вывода на экран} var i:word;begin for i:=low(f) to High(f) do write(f[i]:5:2); writeln;end;{---------основная программа------------}var x:array[1..5]of real; {массив на 5 элементов}

y:array[1..10] of real; {массив на 10 элементов}begin randomize; Fill(x); Fill(y); {заполняем оба массива} Out(x); Out(y); {выводим их на экран} readln;end.В результате выполнения программы на экране появится две строки, первая из которых

содержит 5 чисел, вторая - 10.Например:0.62 0.98 0.74 0.98 0.870.63 0.97 0.03 0.68 0.31 0.94 0.72 0.13 0.18 0.04Благодаря randomize, при следующем запуске выводимые значения будут уже другими.

114

Page 115: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Открытые массивы и строки

Открытыми строками в ТП называются строковые параметры-переменные типа string. Открытые строки обладают свойством менять свою максимальную длину в соответствии максимальной длиной фактически переданной строки. При использовании директивы компилятора {$P+} строковые параметры-переменные превращаются в открытые строки.

Например{$P+}procedure MaxLen(var f:string);begin writeln('Максимальная длина строки = ',high(f));end;{---------основная программа------------}var x:string[70]; {строковая переменная на 70 символов}

y:string[50]; {строковая переменная на 50 символов}begin MaxLen(x); MaxLen(y); readln;end.В результате выполнения данной программы на экране появится:Максимальная длина строки = 70Максимальная длина строки = 50Если отказаться от поддержки открытых строк с помощью директивы {$P-}, и не забыть

установить директиву {$V-}, которая позволяет отключить проверку компилятором совпадения максимальных длин строк для формальных и фактических параметров ({$P-,V-}), то результат выполнения данной программы будет другим:

Максимальная длина строки = 255Максимальная длина строки = 255

1.10.4 Процедурные типыКак было показано в параграфе 1.9.4, процедурные типы можно использовать

в разделе объявления типов, переменных, а также типированных констант. Значения процедурного типа также могут передаваться в качестве параметров процедурам и функциям.Задача 48 . Вывести на экран таблицы сложения, вычитания, умножения, деления и возведения в степень.

Решение задачи не представляет особой сложности. Однако без использования процедур и процедурных типов оно будет громоздким и лишенным универсальности:

uses crt;type MathFunc= Function (a,b:real):real; {определяем процедурный тип} MathRecord=record {определяем запись для хранения информации о соответствующей

математической функции} Name:string[20];{имя функции} Func:MathFunc;{сама функция} end;{$F+}{устанавливаем дальнюю модель вызова} Function Add(a,b:real):real; {функция сложения} begin Add:=a+b; end;

115

Page 116: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедурные типы

function Sub(a,b:real):real; {функция вычитания} begin Sub:=a-b; end; Function Mul(a,b:real):real; {функция умножения} begin Mul:=a*b; end; function Division(a,b:real):real; {функция деления} begin Division:=a/b; end; function Power(a,b:real):real; {функция возведения в степень} begin Power:=exp(b*ln(a)); end;const Funcs:array[1..5] of MathRecord={константный массив для хранения информации о

математических функциях} ((Name:'сложение';func:Add), (Name:'вычитание';func:Sub), (Name:'умножение';func:Mul), (Name:'деление';func:Division), (Name:'возведение в степень';func:Power));procedure PrintTable(dx,dy:integer; Func:MathFunc); {--------------процедура для вывода на экран таблицы--------------}{ dx, dy - размеры таблицы (не советуем выводить таблицы с количеством столбцов более семи, не хватает ширины экрана для универсального форматирования) func - соответствующая математическая функция}

var i,j:integer; begin for i:=1 to dy do begin for j:=1 to dx do write(' ',func(i,j):9:2); writeln; end; end;{------основная программа--------}var a,b:integer;

i:byte;begin clrscr; write('Введите размеры таблицы (2 числа): '); readln(a,b); for i:=1 to 5 do begin with funcs[i] do begin {ведем обработку очередной записи информации о математической

функции} writeln('Вывод таблицы, операция - ',Name); PrintTable(b,a,func); readkey; {после вывода каждой таблицы ожидаем нажатия клавиши} end; end;end.Например, при выводе таблицы размером в 3 строки и 7 столбцов мы получим следующий

результат:Введите размеры таблицы (2 числа): 3 7Вывод таблицы, операция - сложение 2.00 3.00 4.00 5.00 6.00 7.00 8.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00Вывод таблицы, операция - вычитание

116

Page 117: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Процедурные типы

0.00 –1.00 –2.00 –3.00 –4.00 –5.00 –6.00 1.00 0.00 –1.00 –2.00 –3.00 –4.00 –5.00 2.00 1.00 0.00 –1.00 –2.00 –3.00 –4.00Вывод таблицы, операция - умножение 1.00 2.00 3.00 4.00 5.00 6.00 7.00 2.00 4.00 6.00 8.00 10.00 12.00 14.00 3.00 6.00 9.00 12.00 15.00 18.00 21.00Вывод таблицы, операция - деление 1.00 0.50 0.33 0.25 0.20 0.17 0.14 2.00 1.00 0.67 0.50 0.40 0.33 0.29 3.00 1.50 1.00 0.75 0.60 0.50 0.43Вывод таблицы, операция - возведение в степень 1.00 1.00 1.00 1.00 1.00 1.00 1.00 2.00 4.00 8.00 16.00 32.00 64.00 128.00 3.00 9.00 27.00 81.00 243.00 729.00 2187.00К сожалению, ТП не поддерживает присваивание процедурным переменным

локальных процедур и функций, а также методов объектов, что тормозит применение процедурных типов в объектно-ориентированном программировании. К счастью в Delphi данная проблема решена.

1.10.5 Процедурные директивы

1.10.5.1 Директивы Near и FarТП поддерживает две модели вызова процедур и функций - ближнюю и

дальнюю. Ближняя более эффективна, но может использоваться только внутри одного модуля. Дальние процедуры и функции могут вызываться из любого модуля, но их код менее эффективен. В тех случаях, когда требуется принудительно объявить процедуру или функцию как дальнюю или ближнюю, используют near и far объявления.

Для тех же целей служит специальная директива компилятора. После того, как в программе встретится директива {$F+}, все объявляемые процедуры и функции (не содержащие директивы near) будут определены по дальней модели вызова. Аналогично, после директивы {$F-}, все объявляемые процедуры и функции (не содержащие директивы far) будут определены по ближней модели вызова.

1.10.5.2 Опережающие объявленияДиректива forward позволяют описать процедуру или функцию до описания

операторов, составляющих ее тело. Это требуется, когда из одной процедуры происходит вызов другой, еще не определенной. Однако forward-процедура должна быть обязательно полностью определена в этом же блоке.

Невозможно обойтись без директивы forward при решении следующей задачи:Задача 49 . Дано множество поочередно вложенных друг в друга окружностей и равносторонних треугольников, начиная с окружности. Радиус первой окружности равен R, общее количество фигур - N. Вывести на экран площади каждой из N фигур.

117

Page 118: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Опережающие объявления

Решение.Попытаемся сконструировать наиболее общую информационную модель, которую легко в

дальнейшем впишутся изменения условия задачи, не касающиеся основной геометрической структуры (например, можно предположить, что треугольник не равносторонний, а равнобедренный, или со сторонами, рассчитываемыми по определенной формуле). Создадим две процедуры. Первая из них будет рассчитывать и выводить на экран площадь окружности, радиус которой передан ей в качестве аргумента, а затем, если количество фигур не исчерпано, рассчитывать сторону вписанного треугольника и вызывать вторую процедуру. Вторая будет рассчитывать и выводить на экран площадь треугольника, сторона которого передана ей в качестве аргумента, а затем, если количество фигур не исчерпано, рассчитывать радиус вписанной окружности и вызывать первую процедуру. Как видно из метода решения, каждая из процедур должна быть определена до другой процедуры, что без применения директивы forward невозможно.

Площадь окружности вычисляется по формуле Sокр=π Rокр2 . Сторона вписанного в

окружность равностороннего треугольника зависит от радиуса окружности по формуле a вп .тр .=3Rокр .

Площадь равностороннего треугольника вычисляется по формуле S тр=34

aтр .2 . Радиус

вписанной в равносторонний треугольник окружности Rвп .окр .=a тр

23.

{-------опережающее объявление-------}procedure AreaOfTriangle(a:real; Number:word);forward;

{-------процедура нахождения площади окружности---------}procedure AreaOfCircle(R:real; Number:word);

{R - радиус окружности, Number - количество оставшихся фигур} begin writeln('Площадь окружности с радиусом ',R:5:2,

' равна ',pi*sqr(R):5:2); if Number<>0 then {если количество фигур не исчерпано, то рассчитываем площадь

треугольника, уменьшая при этом количество фигур}AreaOfTriangle(sqrt(3)*R,Number-1);

end;{-------процедура нахождения площади треугольника---------}

procedure AreaOfTriangle(a:real; Number:word);{ a - сторона треугольника,

Number - количество оставшихся фигур} begin writeln('Площадь равностороннего треугольника со стороной ',

a:5:2,' равна ',sqrt(3)*sqr(a)/4:5:2); if Number<>0 then {если количество фигур не исчерпано, то рассчитываем площадь

окружности, уменьшая при этом количество фигур} AreaOfCircle(a/(2*sqrt(3)),Number-1);

end;{---------------основная программа-----------------}

var FirstR:real;Number:word;

begin write('Введите радиус первой окружности '); readln(FirstR); write('Введите количество фигур '); readln(Number);

118

Page 119: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Опережающие объявления

AreaOfCircle(FirstR,Number); readln; end.Выполнение данной программы покажет то, что можно было рассчитать при чуть более

глубоком анализе математической модели: Сторона каждого последующего треугольника в 2 раза меньше стороны предыдущего. Аналогично, радиус каждой последующей окружности в 2 раза меньше радиуса предыдущей. Таким образом, решение данной конкретной задачи можно значительно упростить, что мы предлагаем читателю сделать самостоятельно.

1.10.5.3 Interrupt объявленияInterrupt объявления используются, когда процедура применяется в качестве

замены одного из векторов прерываний DOS или BIOS. Такие процедуры нельзя вызывать с помощью оператора вызова процедуры, количество параметров и их тип строго определены и не могут быть изменены.

1.10.5.4 Внешние объявления (external)Если процедура или функция описана как external, это означает, что ее тело

находится в подключаемом модуле, написанном на языке ассемблера (файл с расширением OBJ). Затем, с помощью директивы компилятора {$L имя_модуля_на_ассемблере}, модуль должен быть подключен.

1.10.5.5 Блок asmБлок asm используется для описания процедуры или функции, написанной на

встроенном ассемблере.блок_asm::=

"assembler" ";" раздел_объявления asm_оператор.asm_оператор::=

"asm" операторы_встроенного_ассемб "end".С помощью ассемблерных процедур, а также asm-операторов можно

создавать скоростные и экономичные программы на языке ассемблера, не пользуясь никакими дополнительными средствами. Более подробно о программировании на ассемблере в Турбо-Паскале Вы можете узнать, обратившись к приложению.

1.10.5.6 Объявление inlineДиректива inline используется для того, чтобы описать процедуру или

функцию прямо в машинных кодах. При попытке вызова процедуры или функции, описанной с помощью директивы inline, на самом деле производится не вызов, а вставка тела процедуры или функции прямо в программу. Таким образом директива inline - это единственный способ создать макроопределение в ТП.

Директива_inline::="inline" "(" набор_чисел_разделяемых_слешем ")"

Директива inline может использоваться и как оператор.

119

Page 120: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Задачи для раздела "Процедуры и функции"

Задачи для раздела "Процедуры и функции"Во всех задачах данного параграфа обязательна проверка создаваемых процедур и функций. Использование глобальных переменных внутри процедур и функций не допускается.Задание 88. Создать функцию, которая возвращает true, если переданное ей число является простым. На ее основе создать процедуру, которая выводит на экран все простые числа от 1 до N, где N - переданное процедуре число.Задание 89. Создать процедуру, которая по переданному двумерному массиву целых чисел и числам M и N, представляющим собой количество столбцов и строк массива, возвращает одномерный массив, заполненный элементами первого столбца переданного массива.Задание 90. Создать функцию, которая возвращает true, если в текстовом файле, имя которого передано функции, хотя бы одна из строк является числом.Задание 91. Создать процедуру, которая в переданной строке заменяет все точки восклицательными знаками, а все восклицательные знаки точками.Задание 92. Создать функцию, которая возвращает true, если произведение элементов главной диагонали переданной квадратной матрицы равно последнему элементу первого столбца. Задание 93. Создать функцию, которая возвращает true, если в переданном одномерном массиве длиной N все числа равны.Задание 94. Создать процедуру, которая обнуляет диагонали переданного двумерного массива, если 4 угловых элемента данного массива равны друг другу.Задание 95. Создать процедуру, которая дополняет переданную ей строку таким количеством пробелов, чтобы ее длина была равна числу N, которое также передается в качестве параметра (такая процедура полезна, например, для выравнивания при выводе на экран или в файл столбцов таблицы).Задание 96[1, № 443]. Даны действительные числа a, b, c, d. Определить площадь пятиугольника, изображенного на рисунке.

a b

c

d

1.0

2.0

1.5

Задание 97[1, № 444]. Даны натуральное число n, действительные числа X1,Y1, X2,Y2, ..., Xn,Yn. Найти площадь n-угольника, вершины которого при некотором последовательном обходе имеют координаты (X1,Y1), (X2,Y2), ..., (Xn,Yn) (определить процедуру вычисления площади треугольника по координатам его вершин).

120

Page 121: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модули

1.11 МодулиМногомодульное программирование - это разбиение общей задачи на

небольшие части, каждая из которых может быть решена единым блоком и сосредоточена (в общем случае) в одном файле, называемом модулем. В настоящее время из всех принципов разбиения программы на модули, основным является принцип сокрытия информации. На его основе разрабатывается и распространяются библиотеки программного обеспечения, защищенные авторским правом.

В каждом модуле для внешнего общения имеются процедуры и функции, переменные, константы и типы, к которым можно обращаться как из основной программы, так и из других модулей. При этом не обязательно знать содержимое каждой из процедур, то-есть каким образом она производит некоторые действия. Достаточно знать только входные и выходные параметры и сущность этих действий. Дополнительно, в каждом модуле имеется своя, локальная сфера действий, внутренние процедуры и функции, переменные, константы и типы, которые вне этого модуля невидимы.

Каждый модуль состоит из 3 частей - интерфейсной секции, а также секций реализации и инициализации, которые могут быть пустыми или отсутствовать.

Если модуль содержит в интерфейсной части только переменные, типы и константы, и не содержит процедур и функций, то секция реализации может быть пуста.

Если модуль не требует никаких инициирующих действий, то секция инициализации может отсутствовать.

ИД_модуля (идентификатор, или имя модуля) всегда должен совпадать с именем файла, в котором хранится модуль.

Модуль::="Unit" ИД_модуля ";"

"Interface"[подключение_модулей]{раздел_объявления_переменных|раздел_объявления_констант|раздел_объявления_типов|раздел_объявления_заголовков_проц_и_функц}

"Implementation"[подключение_модулей][раздел_объявлений]

["begin" оператор {";" оператор } [";"]] "end" ".".

Интерфейсная секция

Секция реализации

Секция инициализации

121

Page 122: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модули

Для подключения в основной программе или модуле других модулей используется следующий синтаксис (см. также параграф 1.5.3):

Подключение_модулей::= "uses" список_модулей ";". Под списком модулей понимаются имена модулей, перечисленных через

запятую.

1.11.1 Интерфейсная секцияВ интерфейсной секции модуля находятся: подключение требуемых

модулей (то есть тех, на содержимое которых имеются ссылки в данной секции), разделы объявления переменных, типов, констант, а также заголовков процедур и функций, доступных для других модулей и главной программы. Так как метки могут использоваться только внутри того блока, в котором они определены, то их объявление в интерфейсной секции лишено смысла и запрещено синтаксисом ТП.

Объявление заголовков процедур и функций в интерфейсной секции эквивалентно forward и far объявлениям.

Например:UNIT MyUnit; {заголовок модуля} interface {начало интерфейсной секции}

uses Graph; {подключение модуля Graph } Const DefaultColor=White;{определение константы, значение которой является, в свою

очередь, константой из модуля Graph}Type Point3D=record x,y,z:real end; {определение типа} var Point1,Point2: Point3D;{объявление переменных}

VarR:Real; procedure Proc1(x,y:byte);{объявление заголовков процедур и функций} function Func:boolean;

implementation {завершение интерфейсной секции, начало секции реализации}...

1.11.2 Секция реализацииПосле интерфейсной секции следует секция реализации, предваряемая

ключевым словом Implementation.Секция реализации может содержать подключение дополнительных модулей,

внутренние переменные, типы, константы, метки, процедуры и функции, невидимые вне данного модуля, а также обязана содержать определения функций и процедур, заголовки которых описаны в интерфейсной секции. Все функции и процедуры, определенные только в секции реализации, являются функциями и процедурами ближнего вызова (near)

Продолжаем предыдущий пример:…

Implementation {начало секции реализации}uses dos; {подключение модулей, требуемых для данной секции}

var Var2:integer; { объявление внутренних переменных}Procedure Proc2; { определение внутренних процедур и функций}

begin ... end;

122

Page 123: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Секция реализации

procedure Proc1(x,y:byte);{определение процедур и функций, заголовки которых находятся в интерфейсной секции}

begin ... end;function Func:boolean;

begin ... end;... {секция реализации завершена}Как показано в данном примере, процедура Proc2 является внутренней для модуля и может

использоваться только в его пределах. Аналогично переменная Var2 невидима вне модуля MyUnit.

1.11.3 Секция инициализацииСекция реализации заканчивается либо ключевым словом end, либо секцией

инициализации в виде составного оператора. В конце модуля, как и в конце программы, ставится точка.

Секция инициализации используется, чтобы присвоить первоначальные значения переменным модуля, вызвать инициирующие процедуры и т.д. Операторы в секции инициализации выполняются до запуска основной программы.Продолжаем предыдущий пример:Если секция инициализации отсутствует, то модуль закончится так: ... end.Если секция инициализации присутствует, то модуль может быть завершен следующим образом: ... begin

Var2:=122;VarR:=28.456;proc2;

end.Одним из недостатков секции инициализации является невозможность

использовать в ней выделение памяти для динамических переменных.

1.11.4 Косвенные ссылки на модулиКосвенные ссылки на модули возникают, когда программа или модуль A

подключает модуль B, который, в свою очередь, использует модуль C. В этом случае считается, что A имеет косвенную ссылку на модуль С. Хотя содержимое модуля C не будет доступно A, компилятору для создания исполняемой программы потребуются не только A и B, но и модуль C.

Например:Основная программа A:

program A; uses B; {подключаем модуль В}begin writeln(StringFromB); {выводим на экран строку из модуля В}end.

Модуль B:unit B;

123

Page 124: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Косвенные ссылки на модули

interfacevar StringFromB : string; {строка модуля В}implementation

uses C; { подключаем модуль С }begin

{формируем строку для модуля В с использованием строковой константы из модуля С} StringFromB:= StringFromC+' и модуля B'end.

Модуль C:unit C;interfaceconst StringFromC='Это строка из модуля С'; { строковая константа модуля С }implementationend.

В результате выполнения данной программы на экране появится фраза:

Это строка из модуля С и модуля B.

Таким образом, не смотря на то, что основная программа использует только модуль В, модуль С также обязан присутствовать на диске.

1.11.5 Циклические ссылки модулейЦиклические ссылки модулей - это ситуация, которая возникает при

одновременном подключении двумя или несколькими модулями друг друга. В случае взаимных ссылок между двумя модулей возникают прямые циклические ссылки. Если же три или более модуля ссылаются друг на друга (см. рисунок ниже) то возникают косвенные циклические ссылки.

Например:

124

Прямые циклические ссылки между модулями 1 и 2

Модуль 1 Модуль 2

Косвенные циклические ссылки между модулями 1 и 3

Модуль 1 Модуль 2 Модуль 3

Page 125: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Циклические ссылки модулей

Пусть нам требуется автоматизировать вывод сообщений и информацию об ошибках. Создадим для этого два модуля.

Процедуры модуля Display позволяют выводить на экран информацию об ошибках и сообщения, содержимое которых находится в модуле MSConst.

Модуль MSConst содержит два константных строковых массива с информацией об ошибках и сообщениями, а также процедуру, объединяющую в себе возможности процедур модуля Display с проверкой на корректность передаваемого аргумента.

Таким образом, оба модуля ссылаются друг на друга.

Модуль Display:unit Display;interface procedure DisplayError(Num:integer); procedure DisplayMessage(Num:integer);implementation uses msconst; { циклическая ссылка на модуль msconst } procedure DisplayError(Num:integer);

{Процедура DisplayError выводит на экран информацию об ошибке по ее номеру, предваряя словом 'Ошибка!'}

begin writeln('Ошибка! ',Errors[Num]); end; procedure DisplayMessage(Num:integer);

{Процедура DisplayMessage выводит на экран сообщение по его номеру, предваряя словом 'Сообщение:'}

begin writeln('Сообщение: ',Messages[Num]); end;end.

Модуль MSConst:unit MSConst; interface const Errors:array[1..3]of string= ('Неправильное выражение', 'Неверный вызов функции', 'Неверный номер сообщения'); const Messages:array[4..6]of string= ('Программа работает нормально', 'Программа начала работу', 'Программа закончила работу'); procedure ShowInfo(Num:integer); implementation uses display; { циклическая ссылка на модуль display } procedure ShowInfo(Num:integer);

{Процедура ShowInfo вызывает процедуры DisplayError и DisplayMessage из модуля Display, которые, в свою очередь, используют содержимое массивов из модуля MSConst.}

begin if Num in [low(Errors)..high(Errors)] then DisplayError(Num) else if Num in [low(Messages)..high(Messages)] then DisplayMessage(Num) else DisplayError(high(Errors));end; end.

125

Page 126: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Циклические ссылки модулей

Основная программа, используемая для проверки возможностей созданных процедур:uses msConst;begin ShowInfo(1); ShowInfo(4); ShowInfo(8); readln;end.

В результате выполнения программы на экране появятся 3 строки:

Ошибка! Неправильное выражениеСообщение: Программа работает нормальноОшибка! Неверный номер сообщенияОсновная проблема, возникающая при использовании циклических ссылок

состоит в том, что компилятор не может транслировать модули, если циклические ссылки находятся в интерфейсной части. Дело в том, что ТП при подготовке программы загружает и обрабатывает один за другим все интерфейсные секции модулей программы. Если при этом в одном из модулей встречается циклическая ссылка на другой, возникает ошибка. В секции реализации никаких ограничений на использование циклических ссылок нет.

Если бы при реализации модулей MSConst и Display мы воспользовались циклическими ссылками в интерфейсной секции, откомпилировать бы программу нам не удалось.

1.11.6 Пример разработки модуляЗадача 50 . Для проверки эффективности программ часто требуется определять и сравнивать время их работы. Создать модуль для поддержки таймера, включая процедуры задержки и определения времени, прошедшего с некоторого установленного момента.

Постараемся сделать решение независимым от особенностей операционной системы (т.е. воспользуемся процедурой получения текущего времени, а не счетчиком времени из области данных BIOS по адресу $40:$6C).

unit UTimeOut; {модуль поддержки таймера} interface Procedure SetTimeOut(TMilli:longint); {Установка счетчика таймера, TMilli - количество

миллисекунд ("завели будильник")} Function GetTimeOut:boolean; {Возвращает True, если с момента установки таймера

прошло не менее чем TMilli миллисекунд ("будильник звенит")}

procedure SetTimer; {фиксирует счетчик таймера ("запустили секундомер")} function GetTimer:longint; {возвращает количество миллисекунд, прошедших с момента

фиксации счетчика } procedure Wait(M:longint); {задержка на M миллисекунд}

Implementationuses dos; {подключаем модуль Dos для доступа к процедуре получения текущего времени }

var Timer:longint;{момент фиксации таймера}TTmilli:longint;{счетчик таймера}

{------------функция ConvertTime -------------}

126

Page 127: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример разработки модуля

function ConvertTime(H,M,S,Milli:integer):longint; begin {функция переводит часы, минуты, секунды и миллисекунды в миллисекунды} ConvertTime:= longint(h)*0360000+longint(M)*0006000+

longint(s)*0000100+longint(Milli); end;{------------функция GetCurrentTime -------------}function GetCurrentTime:longint;{возвращает текущее время в миллисекундах} var h,m,s,milli:word; begin GetTime(h,m,s,milli);{вызов процедуры из модуля Dos для получения текущего времени} GetCurrentTime:=ConvertTime(h,m,s,milli); end;{------------процедура Wait -------------}procedure Wait(M:longint); begin SetTimeOut(M);{устанавливаем счетчик} while not GetTimeOut do;{ожидаем "звонка"} end;{------------процедура SetTimer -------------}Procedure SetTimer; begin Timer:=GetCurrentTime; end;{------------функция GetTimer -------------}function GetTimer:longint; var NewTime:longint; begin NewTime:=GetCurrentTime;{получаем текущее время}{Рассчитываем количество прошедших миллисекунд с момента фиксации таймера. Учитываем возможность перехода за полночь.} if newTime>=Timer then Gettimer:=Newtime-Timer else Gettimer:=Newtime-Timer+8640000; end;{------------процедура SetTimeOut -------------} Procedure SetTimeOut(TMilli:longint); begin TTMilli:=TMilli; SetTimer end;{------------функция GetTimeOut -------------}Function GetTimeOut:boolean; begin

{возвращаем True, если количество времени, прошедшего с момента фиксации таймера, превышает значение счетчика}

if TTMilli<GetTimer then GetTimeOut:=true else GetTimeOut:=false; end;end. {модуль завершен}Для проверки действия процедур и функций модуля создадим несколько программ.

Задача 51 . Сравнить скорость работы циклов For, While и Repeat.Решение:uses crt,uTimeOut;var i:longint; begin clrscr;

127

Page 128: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример разработки модуля

write('Время работы цикла For '); Settimer; for i:=1 to 100000000 do; writeln(getTimer,' миллисекунд'); write('Время работы цикла While '); Settimer; i:=1; while i<=100000000 do inc(i); writeln(getTimer,' миллисекунд'); write('Время работы цикла Repeat '); Settimer; i:=1; repeat inc(i) until i>100000000; writeln(getTimer,' миллисекунд'); readln; end.В результате выполнения данной программы (компьютер с процессором Pentium-120) на

экране появятся три строки:Время работы цикла For 769 миллисекундВремя работы цикла While 852 миллисекундВремя работы цикла Repeat 856 миллисекундНа самом деле, при каждом запуске программы мы получим чуть отличные результаты,

однако общая тенденция достаточно ясна.Задача 52 . Создайте программу, с помощью которой покажите, насколько сильно замерз главный герой одного из стихотворений Некрасова.

Решение проанализируйте сами:uses crt,uTimeOut;const TOut:real=1;

s:string='Однажды в студ-д-д-д-еную зимнюю пору '+'я из-з-з лес-с-су в-в-в-вышел ...';

var i:integer; begin clrscr; for i:=1 to length(s) do begin write(s[i]); wait(round(TOut)); TOut:=TOut*1.05; end; readln; end.

1.11.7 Стандартные модули (обзор)Турбо-Паскаль имеет 5 основных модулей: System.tpu, Crt.tpu, Overlay.tpu,

Dos.tpu и Printer.tpu.Данные модули объединены в библиотеку Turbo.tpl, которая для ускорения

обращения обычно загружается в память компьютера при запуске среды ТП. В то же время любой из них может быть выделен из библиотеки и использован отдельно.

Модуль System является основным и неявно подключаемым к любой программе модулем. Это ядро ТП, которое включает в себя средства для поддержки файлов, арифметические функции, процедуры для работы с кучей, и многое другое.

128

Page 129: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Стандартные модули (обзор)

Модуль Crt поддерживает работу с экраном и клавиатурой в обход стандартных потоков ввода-вывода. Дополнительно, модуль Crt поддерживает работу со встроенным динамиком. Процедуры и функции модуля Crt реализуют текстовые окна, цветной ввод-вывод, произвольное позиционирование курсора, очистку экрана, вставку и удаление строк и т.д.

Модуль Overlay используется для разработки больших программ, исполняемый код которых не умещается в оперативной памяти компьютера.

Модуль Dos, как и следует из его имени, поддерживает работу с операционной системой, включая расширенную работу с файлами и дисками, получение и установку системных даты и времени, обработку системного окружения, исполнение программ, вызов программных и аппаратных прерываний, создание резидентных программ и тому подобное.

Очень маленький модуль Printer делает, тем не менее, большую работу. Он обеспечивает взаимодействие с принтером, как с обычным текстовым файлом.

ТП имеет еще несколько модулей, представляющих значительный интерес для программиста. Это, модуль Graph, содержащий все необходимое для создания графических программ, модуль Graph3, реализующий "черепашью" графику, модуль WinDos, поддерживающий и расширяющий набор функций модуля Dos c заменой всех стандартных строковых параметров на строки PChar, модуль Strings, содержимое которого раскрыто в параграфе 1.9.2.2, при анализе длинных строк, модуль Objects, в котором сосредоточены процедуры, функции, типы, переменные и константы, предназначенные для поддержки объектно-ориентированного программирования.

Хотелось бы упомянуть еще библиотеку Turbo Vision, в состав которой входит и модуль Objects. Благодаря ей можно создавать событийно-ориентированные программы с многооконным текстовым интерфейсом.

1.11.8 Задачи для раздела "Модули"Задание 98. Создать 3 модуля и основную программу. Первый модуль содержит 3 переменных в интерфейсной части, инициализируемых в его секции инициализации. Второй модуль содержит функцию, возвращающую сумму трех переменных из первого модуля. Третий модуль содержит функцию, возвращающую произведение трех переменных из первого модуля и результата, возвращаемого функцией из второго модуля. Основная программа выводит на экран значение функции из третьего модуля.Задание 99. Создать 2 модуля и основную программу. Первый модуль содержит массив из пяти элементов в интерфейсной части, инициализируемых случайными числами в его секции инициализации. Второй модуль со держит функцию, возвращающую среднее арифметическое массива из первого модуля. Основная программа выводит на экран значение функции из второго модуля.Задание 100. Создать 2 модуля и основную программу. Первый модуль содержит массив из N элементов в интерфейсной части (где N - константа, определенная также в интерфейсной части), инициализируемых случайными числами в его секции инициализации. Второй модуль содержит функцию, возвращающую сумму N элементов массива из первого модуля. Основная программа выводит на экран значение функции из второго модуля.Задание 101. Создать 2 модуля и основную программу. Первый модуль содержит целочисленную

129

Page 130: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Задачи для раздела "Модули"

переменную, инициализируемую вводимым с клавиатуры числом в секции инициализации. Второй модуль содержит процедуру, выводящую на экран слово "один", если значение этой переменной = 1, слово "два", если значение этой переменной = 2 и т.д. до значения переменной = 9. Если значение переменной не входит в исследуемый диапазон, то процедура выводит на экран "переменная вне диапазона". Основная программа вызывает процедуру из второго модуля.Задание 102. Создать модуль распространенных арифметических функций, отсутствующих в ТП (см. параграф 1.7.1.1).Задание 103. Создать модуль функций перевода из числа в строку и обратно (см. параграф 1.10.2)Задание 104. Создать модуль, содержащий две функции. Первая из них переводит переданную ей строку в верхний регистр, вторая - в нижний. Обе функции должны учитывать русский алфавит.Задание 105. Создать модуль функций обработки строк. Включить функции отсечения пробелов слева от строки, отсечения пробелов справа от строки, отсечения пробелов справа и слева от строки, функцию, которая отсекает от переданной ей строки начальные символы до первого пробела и возвращает их в качестве результата.

130

Page 131: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Методы программирования на Турбо-Паскале

Глава 2. Методы программирования на Турбо-Паскале

2.1 Программный проект (фаза 0)К данному моменту предполагается, что Вам известны основы синтаксиса и семантики языка программирования Турбо-Паскаль, изложенные в первой главе. Поэтому для более серьезной иллюстрации изучаемого материала, вместо решения небольших задач мы воспользуемся методом, широко распространенным в обучении профессиональному программированию, а именно – созданием большого программного проекта (векторного графического редактора GRED).Ниже приводятся краткое описание и возможности редактора:1. Графический редактор позволяет манипулировать простейшими графическими

примитивами, как то – отрезками, окружностями, прямоугольниками, эллипсами, многоугольниками, заливками различных видов и т.д. Под манипуляциями понимаются интерактивное создание, удаление, изменение местоположения, размеров и других атрибутов графических примитивов.

2. Редактор позволяет хранить (запись и чтение) на диске полученный набор примитивов в специализированном формате, а также сохранять в текстовом файле набор вызовов графических процедур и функций. Таким образом, подготовленный в редакторе рисунок можно затем использовать в любой программе на Паскале.

3. Редактор имеет достаточный для выполнения своих функций набор элементов управления – зависимые и независимые кнопки, поля для выбора цвета и других атрибутов графических примитивов, поля ввода и вывода текста, средства скроллинга, меню и т.д.

4. Основное средство управления – манипулятор "мышь". Для ввода текстовой информации и управления с помощью "горячих клавиш" используется клавиатура.

К сожалению, объем учебного пособия не позволяет полностью реализовать все требуемые функции графического редактора, однако основные принципы будут подробно разобраны. Таким образом недостающие элементы Вы сможете запрограммировать самостоятельно. Ниже приводится примерный вид редактора:

131

Page 132: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (фаза 0)

Естественно, что в процессе модификации, улучшения и расширения возможностей редактора его вид может быть изменен.

Для работы нам понадобится несколько процедур и функций, реализующих взаимодействие с мышью, управление вводом строки в графическом режиме, вывод сообщений и т.д. Их создание является не сложной, но объемной и рутинной задачей. Поэтому данные процедуры и функции, сосредоточенные в трех модулях, будут предоставлены в готовом виде (полностью текст модулей находится на сайте http://shadrinsk.zaural.ru/~sda/teaching/programms/gred/index.html и в авторском разделе web-сервера кафедры ТМИ Шадринского государственного педагогического института).

Модуль Mouse.pas:Используемые функции и процедуры:function ChkAndReset: Boolean;

Инициализация мыши, возвращает true при нормальном завершенииprocedure ShowMouse;

Показывает курсор мышиprocedure HideMouse;

Скрывает курсор мышиprocedure GetMouseState(var X,Y:integer; var Left,Right:boolean);

Получает информацию о состоянии мыши – координаты и статус нажатия клавиш

Модуль Inter.pas:Используемые функции и процедуры:procedure NormalizedRect(var r:TRect);

Нормализует переданный прямоугольник. Класс TRect подробно рассмотрен в фазах 3 и 7

132

Page 133: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (фаза 0)

программного проекта.function LineIntersectRect(var oLine,oRect:TRect):boolean;

Возвращает ИСТИНУ, если линия пересекает прямоугольник. Подробнее см. фазу 7 программного проекта.

function Exists(Filename:string):boolean;Возвращает ИСТИНУ, если файл существует на диске

function InputString(MaxLen:byte; Caption:string; var inString:string):boolean;

Организует ввод строки в графическом режиме.MaxLen - максимальное количество отображаемых символов во вводимой строкеCaption - заголовокInString - первоначальное значение и введенная строка

procedure ShowBar(x1,y1,x2,y2:integer; Color:word; Raised:boolean);Выводит на экран выпуклый или вдавленный прямоугольник в графическом режиме. Используется обычно для прорисовки кнопокx1,y1,x2,y2 – координаты прямоугольникаColor – его цветRaised – если true, то прямоугольник является выпуклым, иначе- вдавленным

procedure Messagebox(Caption:string);Выводит в графическом режиме сообщение в центре экрана.

Модуль SimplFont.pas:Процедуры и функции данного модуля используются в функции InputString и процедуре Messagebox модуля inter.pas.

2.2 Графика.

2.2.1 Графические режимы.

2.2.1.1 Характеристики графических режимовТП позволяет использовать различные графические режимы, доступные на

данном типе видеоадаптера. Для каждого из видеоадаптеров требуется соответствующий драйвер в виде файла с расширением BGI (Borland Graphics Interface).

Например, если на компьютере установлен видеоадаптер VGA, то для поддержки графического режима требуется наличие на диске файла egavga.bgi.

Графический драйвер предоставляет самый низкоуровневый интерфейс для взаимодействия с экраном в графическом режиме. Все графические процедуры и функции ТП обращаются не напрямую к видеопамяти, а процедурам и функциям драйвера, которые скрыты от программиста. Таким образом обеспечивается унификация процесса программирования в произвольном графическом режиме.

Каждый графический режим имеет несколько характеристик:1. Разрешение. Под разрешением понимается количество точек на экране по

осям X и Y. Существует несколько стандартов разрешений графического режима - 320*200, 640*200, 640*350, 640*480, 800*600, 1024*768 и т.д. Расположение осей в

133

Page 134: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Характеристики графических режимов

ТП отличается от математического стандарта.

(0,0) (X,0)

(0,Y)

2. Набор цветов. Под набором цветов понимается максимальное количество цветов, которые могут быть отображены в одной точке. Существует несколько стандартных значений для набора цветов, кратных байту или части байта: 2 цвета (1 бит), 4 цвета (2 бита), 16 цветов (4 бита), 256 цветов (1 байт), 65536 цветов (2 байта), 16777216 цветов (3 байта) и т.д. В дальнейшем мы будем работать с 16-ти цветными режимами, хотя при наличии соответствующего драйвера ТП поддерживает любой из вышеперечисленных наборов цветов.

3. Количество страниц. Видеостраницей называется область памяти компьютера, отображаемой на экране (такую память называют видеопамятью). Т.о., обращаясь к некоторой области памяти, мы автоматически обращаемся к экрану.

На самом деле данный процесс более сложен. Например, один байт оперативной памяти в режиме 640*480 (16 цветов) адресует сразу 8 точек, хотя, казалось бы, адресовать одним байтом более двух точек в этом режиме в принципе невозможно. Установив любой SVGA режим (640*480,256 и выше), мы в один момент времени будем обращаться к одной точке, а в другой, используя тот же адрес памяти, уже к другой точке. Однако все эти нюансы не имеют значения для программиста-прикладника, так как взаимодействие с экраном ведется с помощью драйвера BGI, что позволяет полностью унифицировать программу, сделать ее независимой от типа видеоадаптера компьютера.

В зависимости от объема видеопамяти, разрешения и количества цветов можно обращаться к одной, двум, четырем и более графическим страницам. Одна из графических страниц всегда является видимой (ее содержимое видно на экране), а другая - активной (то есть на нее идет весь графический вывод). ТП позволяет использовать как видимые, так и активные страницы.

Задача 53. Объем видеопамяти некоторого видеоадаптера составляет 256 килобайт. Сколько видеостраниц может поддерживать видеоадаптер в шестнадцатицветных режимах 640*200, 640*350 и 640*480?

Рассмотрим режим 640*200. В каждом байте видеопамяти для шестнадцатицветного режима может храниться 2 точки. Количество точек на экране – 640*200=128000. Т.о. для хранения одной страницы видеопамяти требуется 128000/2=64000 байт, что составляет 64000/1024=62.5 килобайта. Получаем, что в 256 килобайтах видеопамяти можно разместить 256 div 62.5 = 4 видеостраницы.

Для режимов 640*350 и 640*480 решите задачу самостоятельно.

2.2.1.2 Видеоадаптеры EGA и VGAДля установки графического режима требуется:

1. Наличие на диске соответствующего файла драйвера.

134

Page 135: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Видеоадаптеры EGA и VGA

2. Константа драйвера, если драйвер является стандартным (т.е. входит в поставку ТП)

3. Константа режима (т.к. один видеоадаптер может поддерживать несколько графических режимов)

В нижеприведенной таблице рассмотрены наиболее распространенные графические режимы, поддерживаемые видеоадаптерами EGA и VGA.

Драйвер, константа драйвера

Типы видеоадаптеров.

Константы режимов.

Характеристика

egavga.bgiEGA EGA

EGALo EGAHI

640х200 16 цветов, 4 стр.640х350 16 цветов, 2 стр.

egavga.bgiVGA VGA

VGALo VGAMedVGAHI

640х200 16 цветов, 4 стр.640х350 16 цветов, 2 стр. 640х480 16 цветов, 1 стр.

Многие видеоадаптеры поддерживают графические режимы других видеосистем. Например, видеоадаптер VGA поддерживает все графические режимы EGA.

При изучении графики мы будем пользоваться 16-цветными режимами. Это ограничивает возможности манипуляции реалистичными и фото- изображениями, зато упрощает изучение остальных разделов графики.

2.2.1.3 Этапы работы в графическом режимеПроцесс программирования в графическом режиме содержит нескольких

этапов:1. Инициализация графического режима. Под инициализацией графического

режима подразумевается переход из текстового в графический режим или из одного графического режима - в другой.

2. Работа в графическом режиме. Программирование в графическом режиме заключается в вызове процедур и функций рисования, а также настройки свойств инструментов и области рисования.

3. Завершение работы в графическом режиме. Под этим подразумевается окончательный переход из графического режима тестовый перед завершением работы программы. В процессе программирования в графическом режиме разрешается также временный переход в текстовый режим с последующим восстановлением графического.

2.2.2 Программирование в графическом режимеГрафические процедуры, функции, переменные, константы и типы, реализующие этапы работы в графическом режиме, сосредоточены в модуле GRAPH.TPU.

135

Page 136: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы

2.2.2.1 Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы

Инициализацияprocedure InitGraph (var GraphDriver:Integer; var GraphMode: integer; PathToDriver: string);

Инициализирует графический режимprocedure SetGraphMode(Mode: Integer);

Устанавливает новый графический режим для текущего видеоадаптера

Завершениеprocedure CloseGraph;

Завершает работу с графикойprocedure RestoreCrtMode;

Временный переход в текстовый режим

Информация о графическом драйвере и видеорежимахprocedure DetectGraph(var GraphDriver, GraphMode: Integer);

Возвращает тип видеодрайвера и максимально возможный (наилучший) графический режим для установленного на компьютере видеоадаптера

function GetDriverName: string;Возвращает имя текущего видеодрайвера

function GetModeName(ModNumber: integer): string;Возвращает информацию о видеорежиме текущего видеодрайвера

function GetGraphMode: integer;Возвращает текущий видеорежиме

function GetМахMode: integer;Возвращает номер максимально возможного видеорежима для текущего видеоадаптера

procedure GetModeRange(GraphDriver:Integer; var LoMode, HiMode:Integer);Возвращает диапазон возможных значений видеорежимов для видеоадаптера

Цветаfunction GetMaxColor:word;

Возвращает максимальный номер цвета, доступного в текущем графического режима.

Координатная системаfunction GetMaxX:integer;

Возвращает максимальную X-координатуfunction GetMaxY:integer;

Возвращает максимальную Y-координату

136

Page 137: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы

Для инициализации графического режима существует процедура InitGraph:procedure InitGraph (var GraphDriver:Integer; var GraphMode: Integer; PathToDriver:

string);GraphDriver - константа драйвераGraphMode - константа режимаPathToDriver - путь для драйвера

Задача 54. Покажите все варианты инициализации графического режима 640x350 16 цветов на видеоадаптере VGA.

Решение 1:var grM,grD:integer;

begin grD:=EGA; {устанавливаем константу драйвера} grM:=EGAHi; {устанавливаем константу графического режима} InitGraph(grd,grm,''); {инициализируем графический режим} ... {здесь будет вызов графических процедур и функций} CloseGraph; end;

Решение 2:var grM,grD:integer;

begin grD:=VGA; grM:=VGAMed; InitGraph(grd,grm,''); ... CloseGraph; end;

Как видим, в обоих случаях путем для драйвера является пустая строка. Т.о. подразумевается, что файл драйвера (egavga.bgi) находится в текущем каталоге.

Если на компьютере установлен видеоадаптер EGA, то использование второго метода будет ошибочным. Если установлен адаптер VGA, то согласно схеме он поддерживает все режимы EGA, и оба метода сработают верно.

Если требуется, чтобы программа сама определяла графические драйвер и режим, можно вместо имени адаптера передать константу Detect, определенную в модуле GRAPH. Таким образом, произойдет инициализация максимально возможного графического режима для данного типа адаптера. В переменные GraphDriver и GraphMode будут помещены соответственно тип определенного адаптера и номер установленного режима. Альтернативный способ автоматического определения типа графического драйвера и лучшего (максимально возможного) видеорежима состоит в использовании процедуры DetectGraph:

procedure DetectGraph(var GraphDriver, GraphMode: Integer);Процедура сохранит в переданных переменных GraphDriver и GraphMode соответственно тип видеодрайвера и максимально возможного для него видеорежима.

После установки графического режима существует возможность как перехода

137

Page 138: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Инициализация и завершение работы с графикой, видеоадаптер и видеорежимы

в другой графический режим, поддерживаемый данным типом видеоадаптера (SetGraphMode), так и временный переход в текстовый режим (RestoreCrtMode) с последующим восстановлением графического (также SetGraphMode). И в том и другом случае не происходит перераспределения или освобождения динамической памяти, выделенной для графического драйвера при инициализации графического режима процедурой InitGraph. Обе процедуры производят очистку экрана. То есть, не следует рассчитывать, например, на то, что при временном выходе в текстовый режим содержимое графического экрана останется без изменений.

Завершение работы с графикой происходит с помощью вызова процедуры CloseGraph. При этом освобождается динамическая память, выделенная для графического драйвера и выполняется переход в текстовый режим.

При инициализации графического режима ТП выделяет определенный объем динамической памяти для загрузки файла графического драйвера. До момента завершения работы графикой данная область памяти не используется в других целях (т.е. при работе с указателями и динамическими переменными). Поэтому надо быть осторожным при использовании директивы компилятора $M, с помощью которой устанавливаются объем динамической памяти, занимаемый программой, а также размер стека. При выделении слишком малого объема динамической памяти инициализация графического режима завершится ошибкой.

Одной из характеристик любого графического режима является разрешение экрана. Левый верхний угол экрана имеет координаты (0,0), правый нижний - (GetMaxX, GetMaxY), где GetMaxX, и GetMaxY - функции получения максимальных для текущего графического режима координат X и Y.

Например в режиме 640x480 координатная сиcтема (0,0)-(639,479), то есть функция GetMaxX возвратит 639, а GetMaxY - 479.

Задания для раздела "Инициализация и завершение работы сграфикой, видеоадаптер и видеорежимы" .Задание 106. Определите и выведите на экран тип видеоадаптера и максимально для него возможный графический режим. Решите задачу с инициализацией и без инициализации графики.Задание 107. Создайте программу, последовательно (по нажатию на любую клавишу) переключающуюся между всеми возможными графическими режимами видеоадаптера, выводящую на экран при каждом переключении тип видеоадаптера, текущий графический режим и максимальное количество цветов для данного видеорежима. Задание 108. Создайте программу, аналогичную предыдущей, с тем отличием, что после вывода информации на графический экран происходит временный переход в текстовый режим, где также осуществляется вывод той же самой информации. Переключение между режимами – по нажатию на любую клавишу.Задание 109. По введенному с клавиатуры номеру видеорежима произвести переключение в данный графический режим. Если такой графический режим не поддерживается видеоадаптером, выдать соответствующее сообщение.

138

Page 139: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Анализ ошибок

2.2.2.2 Анализ ошибокПолучение информации об ошибке

function GraphResult:integer;Возвращает номер ошибки

function GraphErrorMsg(ErrCode:integer):string;Возвращает информацию об ошибке по ее номеру.

Обращение к графическим процедурам может закончиться ошибкой. Например, при попытке вызова процедуры построения окружности до инициализации

графического режима произойдет ошибка. Может не хватить оперативной памяти для закраски некоторой области, размещения графического драйвера или шрифта. Могут отсутствовать файлы шрифтов и графических драйверов и т.д.

При возникновении графических ошибок остановки программы не происходит. Программист обязан сам предусмотреть обработку ошибок, используя для этого две функции:

GraphResult возвращает одну из констант, определяющих номер ошибки (число от -1 до -14) или grOk (0), если ошибки не произошло. Результат, возвращаемый GraphResult, чаще всего проверяют на равенство grOk и выводят соответствующее сообщение, если ошибка имеет место.

GraphErrorMsg возвращает по номеру ошибки информацию о ней в строке. Данную функцию используют чаще всего в комбинации с GraphResult для формирования сообщения об ошибке.

Задания для раздела "Анализ ошибок" .Задание 110. Создайте программу, в которой при неверной инициализации графического режима будет выдано сообщение о соответствующей ошибке.Задание 111. Выведите на экран текстовую информацию о всех графических ошибках.

2.2.2.3 Графический указатель

Графический указательprocedure MoveTo(X,Y:integer);

Перемещение графического указателя.procedure MoveRel(DX,DY:integer);

Перемещение графического указателя относительно его текущего местоположения.

function GetX:integer;function GetY:integer;

Получение координат графического указателя.

В графическом режиме существует аналог курсора, который называется

139

Page 140: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графический указатель

графическим указателем (CP - current pointer) и невидим на экране. Некоторые процедуры рисования используют и изменяют его координаты. Существуют специальные процедуры перемещения графического указателя, не связанные с рисованием (MoveTo, MoveRel), а также функции для получения координат CP (GetX, GetY).

Задания для раздела "Графический указатель".В заданиях ниже для рисования разрешается пользоваться только процедурой

LineTo(x,y:integer), которая чертит прямую линию от текущего местоположения графического указателя в точку X,Y, а затем перемещает туда же указатель.Задание 112. Разработать процедуру CreateHome(x,y:integer), которая создает следующий рисунок:

Точка (x,y)

Придерживаться следующего правила – "не отрывать карандаша", т.е. начало каждой следующей линии должно совпадать с концом предыдущей, а также не рисовать одну и ту же линию два и более раз. Проверить работу процедуры, вызвав ее несколько раз с различными координатами X и Y.Задание 113. Определить тип запись, содержащий: 1) информацию о координатах точки, 2) числовое поле, отвечающее за действие над данной точкой. Значения числового поля: 0 – требуется провести линию в эту точку, 1 – требуется переместить курсор в эту точку. Определить и заполнить массив из нескольких записей данного типа. Программа должна перебрать все элементы массива, совершая требуемые действия над каждой точкой.Задание 114. Параметрическое уравнение окружности выглядит следующим образом: x=R*sin(t); y=R*cos(t), где R – радиус окружности, t-параметр, пробегающий значения от 0 до 360 градусов, x и y – координаты точки окружности. По введенному значению радиуса нарисовать окружность в центре экрана.

2.2.2.4 Графические инструменты

Свойства карандашаprocedure SetColor(Color: Word);

Установка цвета линий.function GetColor: Word;

Получение текущего цвета линий.procedure SetLineStyle (LineStyle: Word; Pattern: Word; Thickness: Word);

Установка стиля линий.procedure GetLineSettings(var LineInfo: LineSettingsType);

Получение текущего стиля линий.procedure SetWriteMode(WriteMode: Integer);

140

Page 141: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графические инструменты

Установка режима вывода линий на экран

Свойства кистиprocedure SetFillStyle(Pattern: Word; Color: Word);

Выбор встроенного стиля закраски и установка цвета.Procedure SetFillPattern(Pattern: FillPatternType; Color: Word);

Выбор пользовательского стиля закраски и установка цветаProcedure GetFillSettings(var FillInfo: FillSettingsType);

Получение текущего стиля и цвета закраски Procedure GetFillPattern(var FillPattern: FillPatternType);

Получение текущего пользовательского стиля закраски

Если рассматривать экран или некоторую область экрана как холст, то рисование в ТП осуществляется на нем двумя инструментами - карандашом и кистью. Карандашом рисуют линии, различные кривые и текст, кистью производят закраску области.

Как карандаш, так и кисть обладают целым набором свойств.Свойства карандаша Свойства кисти

1. Цвет линии2. Стиль линии (тонкая или толстая (1 или

3 пикселя), сплошная, прерывистая, состоящая из точек-тире и т.д.)

3. Режим вывода линии на экран (тип логической операции между линией и содержимым экрана)

1. Цвет закраски2. Стиль закраски (определяется

содержимым битовой матрицы 88 точек)

Свойства карандаша

Для управления цветом линий служит процедура SetColor, параметром которой является устанавливаемый цвет. Получить текущий цвет линий можно с помощью функции GetColor.

Для управления типом и толщиной линий (сплошная, точками или тип определенный пользователем) служит процедура SetLineStyle:procedure SetLineStyle (LineStyle: Word; Pattern: Word; Thickness: Word);где

LineStyle - одна из констант SolidLn=0, DottedLn=1, CenterLn=2, DashedLn=3 или UserBitLn=4 (линия, определенная пользователем).

Pattern - число, двоичное изображение которого определяет тип линии, определенной пользователем. Если LineStyle не равно UserBitLn, то значение Pattern может быть любым.

Thickness - константа NormWidth или ThickWidth, определяющая толщину линии (1 или 3 пикселя):

141

Page 142: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графические инструменты

Получить информацию о текущем установленном стиле линий можно с помощью процедуры GetLineSettings:procedure GetLineSettings(var LineInfo: LineSettingsType);где LineSettingsType - это тип записи, определенный в модуле Graph.

LineSettingsType = recordLineStyle: Word; {стиль линии}Pattern: Word; {шаблон для пользовательского стиля}Thickness: Word; {толщина}

end;

Для установки режима вывода на экран используется процедура SetWriteMode.

procedure SetWriteMode(WriteMode: Integer);где WriteMode - одна из следующих констант:

Константа ЗначениеТип

логической операции

Краткое описание

NormalPut 0 MOVВывод на экран, с игнорированием его содержимого

CopyPut 0 MOV Аналог NormalPutXORPut 1 XOR Вывод на экран с операцией XOR

OrPut 2 OR Вывод на экран с операцией ORAndPut 3 AND Вывод на экран с операцией AND

NotPut 4 NOT Инвертирование выводимых линий, содержимое экрана не учитывается

Задания для раздела "Свойства карандаша".

При решении заданий разрешается пользоваться уже известной процедурой LineTo, а также

142

Page 143: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графические инструменты

процедурой Line(x1,y1,x2,y2:integer), которая рисует линию из точки (x1,y1) в точку (x2,y2).Задание 115. Создать программу, выводящую на экран 8 линий различных стилей (см. рисунок выше).Задание 116. Нарисовать 8 концентрических окружностей различных стилей в центре экрана (см. задание 114 на стр. 140).Задание 117. Создать "бегущую" секундную стрелку в центре экрана, совершающую полный оборот за 60 секунд (см. задание 114 на стр. 140). Запрещается изменять цвет линий для затирания предыдущей стрелки, пользуйтесь установкой режима вывода на экран.Задание 118. Нарисуйте "решетку" по следующим правилам: "решетка" заполняет собой весь экран (вне зависимости от разрешения установленного графического режима) и содержит 29 линий по горизонтали и вертикали. Цвета линий распределяются следующим образом: 1, 2, … 14, 15, 14, … 2, 1.Задание 119. Выполните предыдущее задание со следующими изменениями: цвет всех линий одинаков, однако тип горизонтальных линий имеет значение 10010101, а тип вертикальных – инверсию от этого значения.

Программный проект (фаза 1)

Наш графический редактор будет состоять из нескольких модулей. Все, связанное с графическими примитивами, сосредоточим в модуле GrPrim.pas.

Каждый графический примитив, использующий для рисования карандаш, обладает набором данных, определяющих свойства карандаша. Определим такой тип:

{ модуль GrPrim.pas }…typeprLineStyle=record linestyle, pattern, thickness, color: word;end;…Префикс pr в названии типа здесь и в дальнейшем будет означать "параметр".

Свойства кисти

Для управления типом заполнения используются две процедуры:procedure SetFillStyle(Pattern: Word; Color: Word);

Color - цвет заливки.Pattern - одна из констант, определенных в модуле GRAPH: EmptyFill=0,

SolidFill=1, LineFill=2, LtSlashFill=3, SlashFill=4, BkSlashFill=5, LtBkSlashFill=6, HatchFill=7, XHatchFill=8, InterleaveFill=9, WideDotFill=10, CloseDotFill=11:

143

Page 144: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графические инструменты

Существует константа заполнения UserFill=12, определяющая пользовательский стиль. В этом случае вид заполнения определяется процедурой SetFillPattern:procedure SetFillPattern(Pattern: FillPatternType; Color: Word)

где FillPatternType предопределен в модуле GRAPH какtype FÌillPattenType = array[1..8] of byte;

Таким образом Pattern определяет битовый образ 8х8 точек (8 бит в каждом байте, 8 байт в массиве).

ТП позволяет для установки пользовательского стиля использовать только процедуру SetFillPattern. Т.о. в процедуре SetFillStyle никогда не используется константа UserFill (ее применение будет рассмотрено ниже).

Для получения текущего стиля закраски используется процедура GetFillSettings:procedure GetFillSettings(var FillInfo: FillSettingsType);

где FillInfo - это информация о стиле и цвете заполнения типа FillSettingsType:

FillSettingsType = recordPattern : Word;Color : Word;

end;Если текущий стиль заполнения является пользовательским, то значение поля

Pattern равно UserFill. В этом случае получить действительный битовый образ можно с помощью процедуры GetFillPattern:procedure GetFillPattern(var FillPattern: FillPatternType);где FillPattern - массив для сохранения битового образа (определение типа FillPatternType см. выше)

Задания для раздела "Свойства кисти".

При решении заданий разрешается пользоваться процедурой Bar(x1,y1,x2,y2:integer), которая рисует закрашенный прямоугольник с координатами (x1,y1)-(x2,y2).Задание 120. Создать программу, выводящую на экран 12 квадратов различных стилей (см. рисунок выше).

144

Page 145: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Графические инструменты

Задание 121. Создать программу, заполняющую экран прямоугольниками различных размеров, типов и цветов, причем координаты каждого прямоугольника не должны выходить за пределы экрана. Типы, цвета и размеры прямоугольников определяются случайным образом.Задание 122. Нарисовать 16 "концентрических" (от центра экрана) прямоугольников различных цветов, двух чередующихся типов – 10 и 11.Задание 123. Нарисовать "каскадом" 12 прямоугольников различных типов. Правый нижний угол каждого находится в правом нижнем углу экрана. Левый верхний угол первого прямоугольника – в левом верхнем углу экрана, левый верхний последнего – в центре экрана. Расстояния между левыми верхними углами двух последовательно стоящих прямоугольников одинаковы. Программа должна верно работать вне зависимости от разрешения экрана

Программный проект (2)

Аналогично свойствам карандаша, определим тип данных, отвечающих за свойства кисти:{ модуль GrPrim.pas }…typeprFillStyle=record Pattern: word; UserPattern: FillPatternType; Color: word; end;…Процедуры, устанавливающие стиль заливки с помощью записи данного типа, должны

использовать либо SetFillStyle, либо SetFillPattern в зависимости от значения поля Pattern записи.

2.2.2.5 ФигурыСуществует множество процедур для рисования и заполнения фигур, включая

точки, линии, окружности, дуги, эллипсы, прямоугольники, многоугольники, полосы, трехмерные полосы и сектора для построения диаграмм.

Точки, линии, многоугольники

Точкиprocedure PutPixel(X, Y: Integer; Pixel: Word);

Вывод точки.function GetPixel(X,Y: Integer): Word;

Получение точки.

Линииprocedure Line(x1, y1, x2, y2: Integer);

Рисование линии.procedure LineTo(X, Y: Integer);

Рисование линии от текущей позиции CP (в абсолютных координатах).procedure LineRel(Dx, Dy: Integer);

145

Page 146: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

Рисование линии от текущей позиции CP (в относительных координатах).

Многоугольникиprocedure Rectangle(x1, y1, x2, y2: Integer);

Рисование прямоугольника.procedure DrawPoly(NumPoints: Word; var PolyPoints);

Рисование ломаной линии.

Для работы с точками в графическом режиме используются 2 процедуры (функции).procedure PutPixel(X, Y: Integer; Pixel: Word);function GetPixel(X,Y: Integer): Word;

Процедура PutPixel ставит точку цветом Pixel в координаты X, Y (текущий установленный стиль не используется). Функция GetPixel возвращает цвет точки в координатах X, Y.

Для рисования линий используются 3 процедуры (каждая использует текущий установленный цвет и стиль карандаша, см. процедуры SetColor, SetLineStyle в параграфе 2.2.2.4):procedure Line(x1, y1, x2, y2: Integer);procedure LineTo(X, Y: Integer);procedure LineRel(Dx, Dy: Integer);

Процедура Line рисует линию из точки (X1,Y1) в точку (X2,Y2). Процедура LineTo рисует линию от текущего местоположения графического

курсора в точку (X,Y). Процедура LineRel рисует линию от текущего местоположения графического

курсора в точку (GetX+DX,GetY+DY).Каждая из процедур рисования линий по окончании действия перемещает CP

в конечную точку: line - в (X2,Y2); lineTo - в (X,Y); LineRel - в (GetX+DX,GetY+DY).

Для рисования многоугольников в ТП предусмотрены 2 процедуры (каждая использует текущий установленный цвет и стиль карандаша, см. процедуры SetColor, SetLineStyle в параграфе 2.2.2.4):procedure Rectangle(x1, y1, x2, y2: Integer);procedure DrawPoly(NumPoints: Word; var PolyPoints);

Процедура Rectangle рисует прямоугольник с координатами левого верхнего угла (X1,Y1) и правого нижнего - (X2,Y2).

Процедура DrawPoly рисует ломаную линию. Количество узловых точек для ломаной определяется параметром NumPoints, PolyPoints - это массив произвольной длины, заполненный координатами точек в следующем формате:var PolyPoints: array[1.. NumPoints] of PointType;где PointType - это тип записи:

146

Page 147: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

PointType = recordX, Y : integer;

end;Если координаты первой и последней точек совпадают, то DrawPoly рисует замкнутый многоугольник, иначе - ломаную линию.

Задания для раздела "Точки, линии, многоугольники".

Задание 124. Заполнить массив точек типа PointType (не менее 4) и нарисовать многоугольник с помощью DrawPoly. Затем произвести сдвиг каждой точки многоугольника вниз на 10 пикселей и нарисовать его без использования DrawPoly.Задание 125. Создать тип записи, включающий координаты и цвет точки. Случайным образом заполнить массив из 5000 таких записей (координаты любой точки должны быть в пределах экрана, цвет – от 1 до 15). Прорисовать все точки с небольшой задержкой между каждыми двумя. Затем, таким же образом, но в обратном порядке стереть все точки с экрана (цвет прорисовки - 0).Задание 126. Выполнить предыдущее задание для произвольных линий. Не использовать цвет 0 для стирания линий (воспользуйтесь режимом вывода на экран).Задание 127. Ввести координаты прямоугольника. Нарисовать прямоугольник несколько раз разными цветами, причем каждый раз использовать для прорисовки только один вид процедур рисования. Таким образом последовательно будут нарисованы прямоугольники с помощью только PutPixel, только LineTo, только LineRel и т.д.Задание 128. Преобразовать процедуру CreateHome из задания 112 (стр. 140) следующим образом: procedure CreateHome(x,y;integer; Scale:real), где Scale – масштабный коэффициент. Масштабирование вести относительно начальной точки (x,y). Рисовать с использованием DrawPoly.

Программный проект (3)

Определим типы данных, необходимые для хранения информации о координатах точек, линий и многоугольников.

Для этого воспользуемся, во первых, двумя типами, определенными в модуле Objects: TPoint=object X,Y:integer;end;TRect=object A,B:TPoint;…end;Зарезервированное слово object означает, что данный тип является объектным типом, о

котором будет подробно рассказано в параграфе Объектно-ориентированное программирование(ООП). На текущий момент нам достаточно знать, что классы TPoint и TRect практически эквивалентны типу запись.

{ модуль GrPrim.pas }…type{точка} prPoint=TPoint;{прямоугольник, отрезок}

147

Page 148: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

prRect=TRect;{многоугольник} prPoints=array[1..1000] of prPoint; pprPoints=^pprPoints; prPoly=record number:word; ppoints:pprpoints; end;…

Дуги, окружности, эллипсы

КривыеProcedure Circle(X,Y: Integer; Radius: Word);

Рисует окружностьProcedure Arc(X,Y; Integer; StAngle, EndAngle, Radius; Word);

Рисует дугу окружностиProcedure Ellipse(X, Y: Integer; StAngle, EndAngle: Word; Xradius, YRadius: Word);

Рисует дугу эллипса

Сопутствующие процедурыProcedure GetArcCoords(var ArcCoords: ArcCoordsType);

Возвращает координаты завершения последней операции рисования дуги окружности или эллипса

Procedure GetAspectRatio(var Xasp, Yasp: Word);Возвращает два числа, по которым может быть рассчитано соотношение сторон экрана

Procedure SetAspectRatio(Xasp, Yasp: Word);Изменяет установленное при инициализации графического режима соотношение сторон экрана

Для рисования окружностей в ТП используется процедураCircle:Procedure Circle(X,Y: Integer; Radius: Word);где (X,Y) - координаты центра окружности, а Radius - радиус окружности. Процедура Circle всегда рисует правильную окружность, учитывая при этом соотношение сторон экрана (см. GetAspectRatio).

Для рисования дуги окружности используется процедура Arc:Procedure Arc(X,Y; Integer; StAngle, EndAngle, Radius; Word);где (X,Y) - координаты центра дуги окружности, а Radius - радиус дуги окружности. Параметры StAngle и EndAngle представляют собой начальный и конечный угол дуги в градусах, при этом начальный угол может оказаться больше конечного угла. Процедура Arc всегда рисует правильную дугу окружности, учитывая при этом соотношение сторон экрана (см. GetAspectRatio).

148

Page 149: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

Для рисования дуги эллипса используется процедура Ellipse:Procedure Ellipse(X, Y: Integer; StAngle, EndAngle: Word; Xradius, YRadius: Word);где (X,Y) - координаты центра дуги эллипса, Xradius, YRadius - радиусы полуосей дуги эллипса. Параметры StAngle и EndAngle представляют собой начальный и конечный угол дуги в градусах, при этом начальный угол может оказаться больше конечного угла.

Естественно, что с помощью дуг окружностей и эллипса можно нарисовать как целую окружность, так и целый эллипс. Для этого значения начального и конечного угла (StAngle, EndAngle) должны составлять соответственно 0 и 360 градусов.

В интерактивной помощи ТП указано, что процедуры рисования кривых не используют никакие параметры карандаша, кроме цвета (SetColor). На самом деле это не так. Кривые используют такой параметр стиля линий, как толщину (другие параметры в SetLineStyle могут иметь произвольное значение). Если толщина линий установлена в 3, то кривые также используют режим вывода линий на экран (SetWriteMode). Этот факт будет использован в графическом редакторе для интерактивной прорисовки окружностей, эллипсов и дуг.

Очень часто требуется продолжить нарисованную дугу эллипса или окружности другой дугой или прямой линией. Для получения информации о последней операции рисования дуги можно воспользоваться процедурой GetArcCoords:Procedure GetArcCoords(var ArcCoords: ArcCoordsType);где ArcCoordsType является типом записи, определенным в модуле Graph:

ArcCoordsType = record X, Y, {координаты центра дуги} Xstart, Ystart, {координаты начала дуги} Xend, Yend : integer; {координаты конца дуги} end;

Попытка нарисовать окружность или дугу окружности с помощью дуги эллипса, передавая одинаковые радиусы большой и малой полуосей, закончится неудачей. Дело в том, что экран ЭВМ в графическом режиме содержит различное количество точек по горизонтали и вертикали (разрешения 640*350, 640*480, 800*600 и т.д.). Потому эллипс с одинаковыми полуосями будет выглядеть вытянутым по вертикали. Для получения соотношения сторон экрана можно воспользоваться процедурой GetAspectRatio:Procedure GetAspectRatio(var Xasp, Yasp: Word);где в переменных Xasp и Yasp возвращаются минимальные целые значения, простым делением которых друг на друга можно найти коэффициент соотношения сторон экрана.

Если нарисованные окружности выглядят эллипсами, это означает, что на компьютере используется нестандартный монитор, либо ТП неверно определил

149

Page 150: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

соотношение сторон экрана при инициализации графического режима. В этом случае может помочь процедура SetAspectRatio, которая изменяет текущее соотношение сторон экрана.

Задания для раздела "Дуги, окружности, эллипсы" (129-132).

Задание 129. В верхней части экрана нарисуйте 15 произвольных окружностей различными цветами с помощью процедуры Circle. В средней части экрана –с помощью процедуры Arc. В нижней части экрана – с помощью процедуры Ellipse. Рисунки должны быть идентичными.Задание 130. Нарисовать волнистую линию, состоящую из N полуокружностей:

Задание 131. Нарисовать N случайных дуг эллипса, причем центр каждой последующей дуги находится в точке окончания предыдущей. Случайным является центр первой дуги и радиусы всех дуг. Дуги не должны выходить за пределы экрана.Задание 132. Не пользуясь никакими процедурами рисования, кроме рисования окружности, создайте программу, результатом выполнения которой будет следующий рисунок:

Программный проект (4)

Определим типы данных, необходимые для хранения информации о координатах окружностей и эллипсов. Типы для дуг определите самостоятельно.

{ модуль GrPrim.pas }…type{ окружность } prCircle=record x,y:integer; radius:integer; end;{ эллипс } prEllipse=record x,y:integer; XRad,YRad:integer; end;…

Заполнения

Закрашенные многоугольники

150

Page 151: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

procedure Bar(x1, y1, x2, y2: Integer);Рисует закрашенный прямоугольник

procedure Bar3D(x1, y1, x2, y2: Integer; Depth: Word; Top: Boolean);Рисует закрашенный трехмерный столбец

procedure FillPoly(NumPoints: Word; var PolyPoints);Рисует закрашенный многоугольник

Закрашенные криволинейные фигурыprocedure FillEllipse(X, Y: Integer; XRadius, YRadius: Word)

Рисует закрашенный эллипсprocedure PieSlice(X, Y: Integer; StAngle, EndAngle, Radius: Word);

Рисует закрашенный круговой секторprocedure Sector(X, Y: Integer; StAngle, EndAngle, XRadius, YRadius: Word);

Рисует закрашенный эллиптический секторЗаливка

procedure FloodFill(X, Y: Integer; Border: Word);Закрашивает ограниченную область

Все процедуры заполнений используют текущий цвет и стиль кисти (см. процедуры SetFillStyle и SetFillPattern)

Для рисования закрашенных многоугольников в ТП предусмотрены 2 процедуры:procedure Bar(x1, y1, x2, y2: Integer);procedure FillPoly(NumPoints: Word; var PolyPoints);

Процедура Bar рисует закрашенный прямоугольник с координатами левого верхнего угла (X1,Y1) и правого нижнего - (X2,Y2).

Процедура FillPoly рисует закрашенный многоугольник. Количество узловых точек для ломаной определяется параметром NumPoints, PolyPoints - это массив произвольной длины, заполненный координатами точек в следующем формате:var PolyPoints: array[1.. NumPoints] of PointType;где PointType - это тип записи:

PointType = recordX, Y : integer;

end;Координаты первой и последней точек могут не совпадать, в этом случае процедура FillPoly сама формирует многоугольник, соединяя первую и последнюю точки.

Для создания столбчатых диаграмм используется процедура Bar3D:procedure Bar3D(x1, y1, x2, y2: Integer; Depth: Word; Top: Boolean);где (X1,Y1)-(X2,Y2) - координаты верхнего левого и правого нижнего углов передней грани столбца, Depth - глубина столбца (Z - координата), Top - параметр, отвечающий за прорисовку верхней грани столбца (если Top=true, то верхняя грань рисуется). Последний параметр очень полезен, когда требуется "поставить" друг на друга несколько столбцов. Bar3D - единственная процедура, которая рисует, используя одновременно как свойства кисти, так и свойства карандаша.

151

Page 152: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

Карандашом обводятся контуры столбца, кистью закрашивается передняя грань.

Для создания закрашенного эллипса используется процедура FillEllipse:procedure FillEllipse(X, Y: Integer; XRadius, YRadius: Word)где (X, Y) - координаты центра эллипса, XRadius, YRadius - радиусы полуосей. Учитывая соотношение сторон экрана (GetAspectRatio), можно легко нарисовать закрашенную окружность.

Для создания кругового и эллиптического сектора используются соответственно процедуры PieSlice и Sectorprocedure PieSlice(X, Y: Integer; StAngle, EndAngle, Radius: Word);procedure Sector(X, Y: Integer; StAngle, EndAngle, XRadius, YRadius: Word);где (X,Y) - координаты центра сектора, StAngle и EndAngle -начальный и конечный угол сектора в градусах, Radius - радиус кругового сектора, а Xradius, YRadius - радиусы полуосей эллиптического сектора.

Для закраски произвольной, ограниченной границей некоторого цвета области используется процедура FloodFill:procedure FloodFill(X, Y: Integer; Border: Word);где (X, Y) - координаты начала заливки, Border - цвет границы. К сожалению, ТП не поддерживает заливку одноцветной области (т.е. – до произвольной границы).

Задания для раздела "Заполнения" (133-137).

Задание 133. Даны 5 чисел. Построить (одну под другой) столбчатую (Bar3D) и круговую диаграммы для данного набора чисел.Задание 134. Вывести на экран N случайных треугольников зеленого цвета, окантованных синим цветом. Задание 135. Нарисовать стандартную мишень в центре экрана:

Задание 136. Нарисовать 5 концентрических колец в центре экрана:

Задание 137. Нарисовать на экране N фигур случайных размеров и местоположения, каждая из которых выглядит следующим образом (закрашенные прямоугольник и два вписанных в него

152

Page 153: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Фигуры

полуэллипса):

2.2.2.6 Вывод текстаСтиль шрифта

procedure SetTextStyle(Font, Direction: Word; CharSize: Word);Устанавливает текущий шрифт, направление вывода и размер символов.

procedure SetTextJustify(Horiz, Vert: Word);Устанавливает выравнивание выводимой строки относительно точки вывода.

procedure SetUserCharSize(MultX, DivX, MultY, DivY: Word);Устанавливает пользовательский размер символов.

procedure GetTextSettings(var TextInfo: TextSettingsType);Возвращает стиль шрифта.

function TextWidth(TextString: string): Word;Возвращает ширину переданной строки в пикселях.

function TextHeight(TextString: string): Word;Возвращает высоту переданной строки в пикселях.

Вывод текстаprocedure OutText(TextString: string);

Выводит на экран строку с позиции CP.procedure OutTextXY(X,Y: Integer; TextString: string);

Выводит на экран строку.Пользовательский шрифт

function InstallUserFont(FontFileName: string ): Integer;Регистрирует пользовательский шрифт и возвращает идентификационное значение для данного шрифта.

ТП для вывода текста использует 2 вида шрифтов - растровый и векторный. Под растровым понимается шрифт, символы которого строятся с помощью матрицы точек, в результате чего очень плохо масштабируются. Векторные шрифты имеют специальный формат и состоят из графических фигур, чаще всего - из отрезков, соединенных в определенной последовательности. Масштабирование таких шрифтов приводит только к изменению расстояния между ключевыми точками фигур, в результате чего увеличенный или уменьшенный символ выглядит также, как и нормальный.

Растровый шрифт, используемый ТП, является на самом деле шрифтом операционной системы. Т.о. только от операционной системы и установленных системных драйверов зависит, будут ли отображаться русские символы в программе, или нет. Программа на ТП, использующая встроенный системный

153

Page 154: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вывод текста

шрифт, не будет универсальной, независимой от свойств операционной системы. По умолчанию программа использует именно этот шрифт. Его идентификационный номер = 0.

Векторные шрифты ТП хранятся в специальных файлах с расширением ".CHR" и должны присутствовать в каталоге программы (об исключениях из этого правила будет рассказано позднее). ТП "знает" от 10 стандартных шрифтах, каждый из которых имеет свой идентификационный номер (от 1 до 10).

Идентификационны

й номер

Имя файла шрифта

Характеристика Вид

1 TRIP.CHR Утроенный шрифт2 LITT.CHR Уменьшенный шрифт3 SANS.CHR Прямой шрифт4 GOTH.CHR Готический шрифт5 SCRI.CHR Рукописный шрифт6 SIMP.CHR Одноштриховый шрифт7 TSCR.CHR Наклонный шрифт "Таймс" 8 LCOM.CHR Шрифт "Таймс"

9 EURO.CHR Шрифт "Courier"

10 BOLD.CHR Крупный двухштриховый шрифт

Если шрифт не входит в данный список, то зарегистрировать его и в дальнейшем использовать позволяет процедура InstallUserFont:Function InstallUserFont(FontFileName: string ): Integer;где FontFileName - имя файла шрифта. Возвращаемое значение представляет собой идентификационный номер шрифта.

Выводимый на экран в графическом режим текст из свойств карандаша использует только цвет (см. SetColor). Другие параметры текста устанавливаются целым набором процедур.

Основной процедурой для установки стиля шрифта является процедура SetTextStyle:Procedure SetTextStyle(Font, Direction: Word; CharSize: Word);где Font - идентификационный номер шрифта, Direction - направление вывода текста (HorizDir=0 - горизонтально, VertDir=1 - вертикально), CharSize - размер символов (от 1 до 7). По умолчанию используются значения Font=0, Direction= HorizDir, CharSize=1.

ТП позволяет выравнивать (смещать) выводимый текст относительно точки вывода с помощью процедуры SetTextJustify: Procedure SetTextJustify(Horiz, Vert: Word);где Horiz - горизонтальное выравнивание текста (LeftText=0 - точка вывода находится слева от текста, CenterText=1 - в центре текста, RightText=2 - справа от

154

Page 155: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вывод текста

текста), Vert - вертикальное выравнивание (BottomText=0 - точка вывода находится сверху от текста, CenterText=1 - в центре текста, TopText=2 - справа от текста). По умолчанию используются значения LeftText и TopText.

Для получения информации о текущем стиле шрифта используется процедура GetTextSettings:Procedure GetTextSettings(var TextInfo: TextettingsType);где TextettingsType – тип записи, определенный в модуле Graph: TextSettingsType = record Font : Word; {номер установленного шрифта} Direction : Word; {направление вывода} CharSize : Word; {размер} Horiz : Word; {горизонтальное выравнивание} Vert : Word; {вертикальное выравнивание } end;

ТП позволяет непропорционально изменять размер символов векторных шрифтов. Для этого используется процедура SetUserCharSize:Procedure SetUserCharSize(MultX, DivX, MulY, DivY: Word);Параметры процедуры используются следующим образом: ширина символов увеличивается в MultX/DivX раз, а высота – MulY/DivY раз. После использования SetUserCharSize определить текущий размер шрифта с помощью процедуры GetTextSettings становится невозможно (поле TextInfo.CharSize = 0).

Для получения высоты и ширины выводимых на экран символов (строк) используются функции TextWidth и TextHeight:Function TextWidth(TextString: string): Word;Function TextHeight(TextString: string): Word;Первая из них возвращает ширину переданной строки в пикселях, вторая - высоту. Обе функции активно используются, когда на экран требуется вывести многострочный текст, так как подобный вывод приходится производить в несколько приемов (в графическом режиме невозможно вывести несколько строк, одна под другой, используя единственную операцию вывода). В результате требуется расчет расстояния (чаще всего - по высоте) между строками.

Вывод текста на экран, с учетом всех установленных свойств шрифта, включая тип, цвет, размер и выравнивание шрифта осуществляется в ТП с помощью процедур OutText и OutTextXY:Procedure OutText(TextString: string);Procedure OutTextXY(X,Y: Integer; TextString: string);Первая из них выводит на экран строку с позиции графического курсора CP (при этом курсор перемещается в конец строки), а вторая - от точки (X,Y).

Векторные шрифты обладают множеством достоинств по сравнению с растровыми, однако скорость вывода текста с их помощью оставляет желать лучшего. Дополнительно, в ТП отсутствует процедуры вывода многострочного текста, ввода строки в графическом режиме и т.п. Для решения данной проблемы автором был создан модуль SimpFont.pas, который позволяет манипулировать растровыми шрифтами и активно используется в разрабатываемом графическом

155

Page 156: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Вывод текста

редакторе.

Задания для раздела "Вывод текста".Задание 138. Вывести на экран слово "Font" в столбец всеми шрифтами, как показано в таблице выше.Задание 139. Выполнить предыдущее задание, увеличивая каждый раз размер шрифта в полтора раза.Задание 140. В центре экрана нарисовать оси координат. Вывести на пересечении осей некоторую фразу количество раз, достаточное, чтобы показать все возможные виды выравнивания шрифта относительно точки вывода. После прорисовки очередной фразы делать задержку, затем очищать экран, выводить оси координат и фразу уже с другим выравниванием.Задание 141. Дано: текстовый файл, номер шрифта и его размер. Вывести содержимое текстового файла на экран соответствующим шрифтом и размером (без скроллинга).Задание 142. Выполнить предыдущее задание, повернув текст на 90 градусов против часовой стрелки.

Программный проект (5)Определим типы данных, необходимые для хранения информации о строке в графическом

режиме.{ модуль GrPrim.pas }…type{ текст } prTextStyle=record font,direction,horiz,vert:word; size:word; mulx,divx,muly,divy:word; str:string; end;…

2.2.2.7 Сохранение и выдача изображенийСтиль шрифта

function ImageSize(x1, y1, x2, y2: Integer): Word;Возвращает размер оперативной памяти, требуемой для сохранения изображения

procedure GetImage(x1, y1, x2, y2: Integer; var BitMap);Копирует изображение с экрана в оперативную память.

procedure PutImage(X, Y: Integer; var BitMap; BitBlt: Word);Выводит ранее сохраненное изображение из оперативной памяти на экрана.

ТП позволяет работать с прямоугольными блоками изображения, копируя их с экрана в оперативную память и обратно, причем вывод на экран осуществляется с использованием набора логических операций.

156

Page 157: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Сохранение и выдача изображений

До копирования блока с экрана в память, требуется заранее определить ее объем. Дело в том, что в различных графических режимах для сохранения одного и того же блока требуются различные объемы оперативной памяти. Функция ImageSize возвращает требуемое значение, учитывая текущий видеорежим:function ImageSize(x1, y1, x2, y2: Integer): Word;где (x1, y1)-(x2, y2) - это координаты левого верхнего и правого нижнего углов копируемого в дальнейшем блока. Возвращаемый функцией результат имеет тип Word. Это означает, что размер блока не может превышать 64 килобайта. Данное ограничение не позволяет сохранить в памяти весь экран (в большинстве графических режимах) одной операцией.

Для копирования блока с экрана в оперативную память предназначена процедура GetImage:procedure GetImage(x1, y1, x2, y2: Integer; var BitMap);где (x1, y1)-(x2, y2) - это координаты левого верхнего и правого нижнего углов копируемого блока. BitMap - переменная (чаще всего - массив, динамически выделенный из кучи), в которую происходит копирование блока.

Для вывода блока из памяти на экран используется процедура PutImage:procedure PutImage(X, Y: Integer; var BitMap; BitBlt: Word);где (X, Y) -координаты точки вывода (левого верхнего угла блока), BitMap - переменная, в которой сохранен блок, BitBlt - логическая операция между блоком и содержимым экрана, на которое накладывается блок (NormalPut, CopyPut, XORPut, OrPut, AndPut или NotPut - см. параграф 2.2.2.4 Свойства карандаша).

Задания для раздела "Сохранение и выдача изображений".Задание 143. "Размножить" набор концентрических окружностей из задания 136 (стр. 152). Количество копий вводится с клавиатуры, их местоположение выбирается случайным образом.Задание 144. Создать две программы. Первая из них сохраняет в файле изображение "домика" из задания 112 (стр. 140), вторая загружает изображение из файла и последовательно (слева - направо, сверху - вниз) заполняет им экран.Задание 145. Создать любое небольшое неоднородное изображение (например – задания 135-137), разделить его на 4 равных прямоугольника (рассечением осями по центру рисунка) и произвести (с небольшой задержкой) 4 циклических перестановки указанных квадратов (либо по-, либо против часовой стрелки)

Программный проект (6)Определим типы данных, необходимые для хранения информации об изображениях.{ модуль GrPrim.pas }…type{ изображение } prPicture=record Size:word; pBitmap:Pointer; end;

157

Page 158: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Сохранение и выдача изображений

…Теперь, зная процедуры рисования в Турбо-Паскале, можно определить, какие графические

примитивы будут использованы в редакторе. { константы видов фигур }…const

TypePoint=0;TypeLine=1;TypeRect=2;TypeBox=3;TypePoly=4;TypePolyFill=5;TypePicture=6;TypeText=7;TypeCircle=8;TypeCircleArc=9;TypeCircleFill=10;TypeEllipse=11;TypeEllipseFill=12;TypeCircleEllipse=13;TypeFill=14;

2.2.2.8 ХолстЦвет холста

procedure SetBkColor(Color:word);Устанавливает цвет фона холста.

function GetBkColor:word;Возвращает цвет фона холста.

Окнаprocedure SetViewPort(x1, y1, x2, y2: Integer; Clip: Boolean);

Устанавливает окно вывода.procedure GetViewSettings(var ViewPort: ViewPortType);

Возвращает параметры текущего окна вывода.

Очистка холстаprocedure ClearViewPort;

Очищает текущее окноprocedure ClearDevice;

Очищает экран

Страницыprocedure SetActivePage(Page: Word);

Устанавливает активную страницу.

158

Page 159: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Холст

procedure SetVisualPage(Page: Word);Устанавливает видимую страницу.

Холстом в ТП называется рабочая область экрана, на которой происходит рисование. Одной из характеристик холста является его цвет (цвет фона), код которого равен 0. По умолчанию цвет с кодом 0 - это черный цвет, изменить который можно с помощью процедуры SetBkColor:procedure SetBkColor(Color:word);где Color - это код цвета, который в дальнейшем будет использоваться для фона холста (к сожалению, при этом становится недоступным исходный черный цвет, что может быть исправлено либо вызовом SetBkColor(0), либо переустановкой палитры). Важнейшей особенностью цвета фона является то, что при его изменении мгновенно меняется цвет всех точек с кодом 0.

Для получения текущего цвета фона используется функция GetBkColor: function GetBkColor:word;

Для рисования на экране может быть выделена некоторая произвольная область, называемая окном. Весь графический вывод осуществляется в установленное окно, от левого верхнего угла которого отсчитываются координаты графических фигур. Окно позволяет отсекать изображение за его пределами. При инициализации графического режима автоматически устанавливается окно размером во весь экран.

Определение графического окна происходит в ТП с помощью процедуры SetViewPort:procedure SetViewPort(x1, y1, x2, y2: Integer; Clip: Boolean);где (x1, y1)-(x2, y2) - координаты окна, Clip - параметр, отвечающий за отсечение графического вывода на границах окна. Отсечение происходит, если Clip = true. При установке окна графический курсор перемещается в его левый верхний угол (т.е., с учетом относительности координат, в точку (0,0)).

Для получения информации об установленном окне используется процедура GetViewSettings:procedure GetViewSettings(var ViewPort: ViewPortType);где ViewPortType - тип записи, определенный в модуле Graph: ViewPortType = record x1, y1, x2, y2 : integer; {координаты окна} Clip : Boolean; {регулятор отсечения} end;

ТП позволяет очищать, т.е. заполнять цветом фона, как отдельное окно, так и весь экран. Процедура ClearViewPort очищает окно, а ClearDevice – экран.

В некоторых графических режимах (VGA или EGA 640*350, 640*200, а также Hercules) ТП позволяет эффективно использовать графические страницы. Чаще всего они применяются для создания анимации. Определить активную страницу, на которую происходит весь графический вывод, можно с помощью процедуры SetActivePage. Аналогично, с помощью процедуры SetVisualPage, устанавливается

159

Page 160: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Холст

видимая страница:procedure SetActivePage(Page: Word);procedure SetVisualPage(Page: Word);где Page – номер устанавливаемой страницы (начиная с нуля).

Задания для раздела "Холст".Задание 146. Создайте процедуру DrawSimpleCircle(x,y:integer), которая рисует окружность с центром в точке (x,y) и радиусом 30. Для рисования внутри данной процедуры должен быть использован только один оператор: Circle(0,0,30). Любые другие действия могут быть произвольными. Проверьте действие процедуры.Задание 147. Нарисуйте на экране N случайных дуг окружностей, пользуясь для рисования только процедурой Circle.Задание 148. Создайте программу, в которой две фразы двигаются одновременно: одна сверху вниз с верхней части экрана, вторая – снизу вверх с нижней части экрана. Движение заканчивается, когда первая фраза будет внизу экрана, а вторая – вверху. Мультипликация должна быть отчетливой, без мерцания. Воспользуйтесь режимом 640*350 и работой с видеостраницами.Задание 149. Воспользовавшись файлом из задания 144 (стр. 157) создайте программу, в которой два "домика" плавно перемещаются от стенке к стенке, один – по горизонтали, другой – по вертикали. Выход из программы – по нажатию на любую клавишу. Мультипликация должна быть отчетливой, без мерцания. Воспользуйтесь режимом 640*350 и работой с видеостраницами.

2.2.2.9 ПалитрыУстановка палитры

procedure SetPalette(ColorNum: Word; Color: Shortint);Устанавливает цвет палитры

procedure SetAllPalette(var Palette);Изменяет сразу несколько элементов палитры.

procedure SetRGBPalette(ColorNum, RedValue, GreenValue, BlueValue: Integer);

Изменяет элемент палитры на произвольный цвет.

Получение палитрыprocedure GetPalette(var Palette: PaletteType);

Возвращает текущую палитру.procedure GetDefaultPalette(var Palette: PaletteType);

Возвращает стандартную палитруfunction GetPaletteSize: Integer;

Возвращает количество элементов палитры

Таблица констант стандартных цветов модуля Graph

160

Page 161: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Палитры

(аналогично модулю CRT)Black=0 (черный)Blue=1 (темно-синий)Green=2 (темно-зеленый)Cyan=3 (бирюзовый)Red=4 (красный)Magenta=5 (фиолетовый)Brown=6 (коричневый)LightGray=7 (серый)

DarkGray=8 (темно-серый)LightBlue=9 (синий)LightGreen=10 (светло-зеленый)LightCyan=11 (св.-бирюзовый)LightRed=12 (розовый)LightMagenta=13 (малиновый)Yellow=14 (желтый)White=15 (белый)

Каждый стандартный цвет имеет в ТП свой код. Модуль Graph (как и модуль CRT) определяет 16 цветовых констант, мнемонические имена которых соответствует отображаемому цвету, как показано в таблице выше.

Совокупность отображаемых на экране цветов называется палитрой, которую можно рассматривать как массив цветов. При установке цвета карандаша или кисти, в процедуры SetColor, SetFillStyle и SetFillPattern передается не код цвета, а индекс элемента палитры. Т.о. цвет, индекс которого равен, например, 1, может быть как темно-синим, как предусмотрено по умолчанию, так и любым другим, при изменении элемента палитры с индексом 1. Одним из полезных свойств палитры является то, что изменение какой-либо цвета автоматически сказывается на всех пикселях экрана с данным цветом. Это свойство удобно использовать, например, когда требуется, чтобы сложный по структуре, но немногоцветный рисунок был сразу же показан на экране, минуя все стадии прорисовки. Для этого достаточно изменить в цвет фона все используемые в рисунке цвета, осуществить прорисовку, а затем восстановить все цвета в их первоначальные значения.

Для установки элемента палитры в один из стандартных цветов используется процедура SetPalette:procedure SetPalette(ColorNum: Word; Color: Shortint);где ColorNum - индекс палитры, Color - один из стандартных цветов (см. таблицу выше).

Для изменения сразу нескольких элементов палитры используются процедура SetAllPalette:procedure SetAllPalette(var Palette);где Palette - структура следующего типа:

const MaxColors = 15; type PaletteType = record Size: Byte; Colors: array[0..MaxColors] of Shortint; end;

MaxColors - количество цветов в текущем графическом режиме. Size - количество изменяемых элементов палитры, Colors - массив стандартных цветов. Если некоторый элемент массива меньше нуля, то соответствующий элемент палитры не

161

Page 162: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Палитры

изменяется.Так как параметр Palette является нетипированным, то в процедуру SetAllPalette может быть передана структура любого типа, которая интерпретируется следующим образом: первый байт определяет количество цветов в палитре, остальные - устанавливаемые цвета.Процедура SetAllPalette действительна для всех графических режимов, количество цветов в которых 16 и менее.

Для изменения элемента палитры на произвольный, нестандартный цвет используется процедура SetRGBPalette:procedure SetRGBPalette (ColorNum, RedValue, GreenValue, BlueValue: Integer);где ColorNum - индекс элемента палитры, RedValue, GreenValue, BlueValue - числа, соответствующие насыщенности красного, зеленого и синего в создаваемом цвете. В параметрах RedValue, GreenValue и BlueValue процедурой SetRGBPalette используются только младшие 6 битов (значения от 0 до 63).Процедура действительна только для адаптеров VGA и IBM8514.

Для получения текущей палитры используется процедура GetPalette:procedure GetPalette(var Palette: PaletteType);где Palette - передаваемая в процедуру структура, в которой возвращается текущая палитра (см. SetAllPalette).

Для получения первоначальной, устанавливаемой по умолчанию палитры используется процедура GetDefaultPalette:

Для получения количества элементов палитры используется функция GetPaletteSize:function GetPaletteSize: Integer;Данная функция всегда возвращает значение GetMaxColor+1.

Задания для раздела "Палитры" (150-153).Задание 150. Создать произвольный многоцветный рисунок (например – задачи 121, 127, 129 и др.). Заставить пропадать и восстанавливаться изображение с периодичностью 1 раз в секунду. Прорисовка должна быть однократной.Задание 151. Решить предыдущую задачу со следующими изменениями – с периодичностью 1 раз в секунду должен пропадать только один цвет. По окончании цвета должны быть восстановлены аналогичным образом.Задание 152. Нарисовать 15 прямоугольников 15-ю оттенками зеленого цвета.Задание 153. Создать "бегущую" полосу из 15 стоящих рядом прямоугольников различных цветов (первый прямоугольник изменяет свой цвет на 15-й, второй – на первый, третий – на второй и т.д.).

2.2.2.10 Регистрация нестандартных графических драйверов и шрифтов.

Регистрация драйвераfunction InstallUserDriver(Name: string; AutoDetectPtr: pointer): integer;

162

Page 163: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Регистрация нестандартных графических драйверов и шрифтов.

Регистрирует нестандартный графический драйверРегистрация шрифта

function InstallUserFont(FontFileName: string ): Integer;Регистрирует нестандартный шрифт

ТП поддерживает нестандартные, созданные сторонними производителями графические драйвера BGI и шрифты CHR.

Для включения в таблицу BGI-драйверов нового, нестандартного драйвера, используется функция InstallUserDriver:function InstallUserDriver(Name: string; AutoDetectPtr: pointer): integer;где Name - имя файла драйвера, AutoDetectPtr - адрес функции автоопределения типа видеоадаптера. При возникновении ошибки функция InstallUserDriver возвращает значение <0, в противном случае - идентификационный номер зарегистрированного графического драйвера.Текст функции AutoDetectPtr должен поставляться вместе с файлом графического драйвера и выглядеть примерно следующим образом:{$F+}function DetectDriver: Integer; var Found: Boolean; begin DetectDriver := grError; {Предполагаем, что тип адаптера не подходит} Found := ... {Тип адаптера подходит?} if not Found then Exit; {Нет, не подходит} DetectDriver := 3; {Да, подходит, возвращаем рекомендуемый графический

режим }end;{$F-}Если драйвер не имеет функции авторегистрации, то вторым параметром можно передавать Nil.

Для регистрации нестандартного шрифта используется функция InstallUserFont:function InstallUserFont(FontFileName: string ): Integer;где FontFileName - имя файла шрифта. При возникновении ошибки функция возвращает значение <0, в противном случае - номер идентификационный номер зарегистрированного шрифта.

Функции InstallUserFont и InstallUserDriver должны быть в общем случае использованы до инициализации графического режима процедурой InitGraph.

163

Page 164: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Инкапсуляция файлов графических драйверов и шрифтов в исполняемый файл

2.2.2.11 Инкапсуляция файлов графических драйверов и шрифтов в исполняемый файл

Инкапсуляция драйвераfunction RegisterBGIdriver(driver: pointer): Integer;

Регистрирует загруженный в оперативную память графический драйверИнкапсуляция шрифта

function RegisterBGIfont(Font: pointer): Integer;Регистрирует загруженный в оперативную память шрифт

Значительные неудобства в графических программах на ТП доставляют графические драйверы и шрифты, которые приходится копировать вместе с программой при изменении ее местоположения. Для решения данной проблемы можно скомпоновать файл драйвера или шрифта c исполняемым файлом, а затем воспользоваться специальными функциями регистрации. Функции регистрации можно использовать также при "ручной" (т.е. методами работы с файлами) загрузке шрифтов или драйверов в оперативную память.

Для компоновки шрифтов или драйверов с программой следует сначала перевести их в объектный вид (т.е. в файл с расширением ".OBJ") с помощью утилиты BINOBJ.EXE, входящей в состав ТП:binobj.exe trip2.chr trip2 trip2fontгде первый параметр - имя файла шрифта или драйвера, второй - имя получаемого OBJ-файла, третий - глобальное имя процедуры, которое позднее будет использоваться для регистрации шрифта или драйвера.

Затем следует скомпоновать получившийся объектный файл с программой в разделе объявления процедур и функций. При этом также следует определить внешнюю процедуру с именем, использованным при формировании OBJ-файла:…procedure trip2font;external; {определение процедуры}{$L trip2.obj} {компоновка с программой}…

И, наконец, для регистрации скомпонованного шрифта или драйвера следует воспользоваться функциями RegisterBGIfont и RegisterBGIdriver:function RegisterBGIfont(Font: pointer): Integer;function RegisterBGIdriver(driver: pointer): Integer;где Font и driver являются указателями на глобальные процедуры скомпонованных шрифта/драйвера, а возвращаемое функцией значение содержит либо код ошибки (<0), либо идентификационный номер шрифта/драйвера. Полученный идентификационный номер можно использовать при инициализации графического режима процедурой InitGraph (для драйвера) или установки шрифта SetTextStyle (для шрифта).

164

Page 165: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Инкапсуляция файлов графических драйверов и шрифтов в исполняемый файл

2.3 Объектно-ориентированное программирование (ООП)

2.3.1 Основные парадигмы ООП.

Объектно-ориентированное программирование (сокращенно ООР) является методом программирования, основанном на понятиях класса (объектного типа) и объекта (экземпляра класса).

Классом (объектным типом) называется специальный тип данных, включающий в себя как данные, так и методы обработки этих данных. В некотором смысле класс очень похож на тип записи ТП.

Объектом (экземпляром класса) называется переменная объектного типа.Полями класса называются данные класса.Методами класса называются процедуры и функции класса, с помощью

которых ведется обработка полей.

Объектно-ориентированное программирование характеризуют три основных свойства классов:

- ИНКАПСУЛЯЦИЯ. Это объединение данных со средствами их обработки. Таким образом можно сказать, что класс - это множество с определенными на нем операциями.

- НАСЛЕДОВАНИЕ. Это определение класса и затем использование его для построения иерархии производных классов, причем каждый производный класс ("потомок") наследует доступ к коду и данным всех своих "прародителей" и добавляет свои собственные.

- ПОЛИМОРФИЗМ. Это переопределение классом-потомком методов предка таким образом, что полностью или частично изменяются реакции предка на те или иные события, меняется действие методов класса прародителя (прародителей). Под переопределением понимается определение в потомке метода с таким же именем, как и в предке.

2.3.2 Реализация ООП средствами Турбо-Паскаля.

2.3.2.1 Класс Турбо-Паскаля

Класс ::= "object" ["("класс_предок")"]

165

Page 166: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

{["private" | "public"]полязаголовки_методов

}"end".Поля ::= определение_переменных. (см. часть 1, параграф 1.3.3.3)

Заголовки_методов ::= {заг_проц_или_функции ";" ["virtual" [целое_число]]}

Заголовки процедур и функций определяются стандартно.Раздел public предназначен для полей и данных, которые видны

программисту как внутри текущего модуля, так и вне его. Данный раздел определен по умолчанию. Раздел private предназначен для личных данных класса. Его содержимое доступно только внутри модуля, в котором описан класс.

После определения класса программист обязан определить (в разделе процедур и функций) тела всех методов класса. Определение методов класса очень схоже с определением процедур и функций. Единственное отличие заключается в имени класса и точке, которые ставятся перед именем метода.

Определение_метода_класса::=("procedure" ИД_класса "." ИД_процедуры

["(" объявление_параметра{";" объявление_параметра }")"] ";")

|("function" ИД_класса "." ИД_функции

["(" объявление_параметра{";" объявление_параметра }")"] ":" ИД_типа ";").

Извне доступ к полям и методам переменной любого класса осуществляется аналогично доступу к полям записи (имя переменной отделяется от метода или поля точкой). Внутри метода класса доступ к полям и методам этого же класса осуществляется напрямую, без использования точки.Если класс-потомок определяет метод с таким же именем, как внутри предка, то такое действие называется переопределением метода. Тогда внутри метода класса-потомка можно вызвать метод класса-предка с использованием зарезервированного слова inherited.

Задача 55. Определить класс Личность и порожденный от него класс Студент.Type Person = object {Класс Личность }

Age:integer; {возраст}Man:boolean; {пол}procedure Init(_Age:integer; _Man:boolean);

{метод создания человека (заполнение полей)}

166

Page 167: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

function IsWorking:boolean; {Метод-функция, определяющая, находится человек в работоспособном возрасте, или нет}

function InfoString:string; {возвращает фразу о типе класса}function IsWorkingString:string; {возвращает фразу о трудоспособности}function ManString:string; {возвращает фразу о поле}function AgeString:string; {возвращает фразу о возрасте}

end;

PersonStudent = object (Person) {Класс Студент, обладает всеми свойствами Личности }procedure Init(_Age:integer; _Man:boolean);

{перекрывающий метод, добавляет возможность вывода сообщения, если происходит попытка создать нетрудоспособного студента }

function InfoString:string; {перекрывающий метод, возвращает фразу о типе класса}end;

…{ раздел объявления процедур и функций }{ методы класса Person }procedure Person.Init(_Age:integer; _Man:boolean); begin

Age:=_Age;Man:=_Man;

end;

function Person.IsWorking:boolean; begin

IsWorking:=true; if age<14 then IsWorking:=falseelse if man then begin

if age>60 then IsWorking:=false; end else if age>55 then IsWorking:=false;

end;

function Person.IsWorkingString:string;var s:string;

begin if IsWorking then s:='' else s:='не ';if Man then IsWorkingString:=s+'трудоспособен' else IsWorkingString:=s+'трудоспособна'

end;

function Person.ManString:string; begin if Man then ManString:='пол - мужской' else ManString:='пол - женский'; end;

function Person.AgeString:string; var s:string;

167

Page 168: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

beginstr(age,s);case age mod 10 of

1: s := s+' год';2,3,4: s := s+' года'else s := s+' лет';

end;AgeString:='возраст – '+s;

end;

function Person.InfoString:string; begin InfoString:='Это – класс "Личность"'; end;

{ метод класса PersonStudent }procedure PersonStudent.Init(_Age:integer; _Man:boolean); begin

inherited init(_age,_man); if not isworking then writeln(age, ‘ – Возраст не студенческий’);

end;

function PersonStudent.InfoString:string; begin InfoString:='Это – класс "Студент"'; end;

{ переменные для основной программы }var a,b,c:Person; a1,b1:PersonStudent;

{основная программа}

begin

writeln('Создаем личность – десятилетний мальчик'); a.init(10,true); writeln(a.InfoString); writeln(a.IsManString); writeln(a.IsAgeString); writeln(a.IsWorkingString); readln;

writeln('Создаем личность – восемнадцатилетняя девушка'); b.init(18,false); writeln(b.InfoString); writeln(b.IsManString); writeln(b.IsAgeString); writeln(b.IsWorkingString); readln;

writeln('Создаем личность – семидесятилетний мужчина'); c.init(70,true); writeln(c.InfoString); writeln(c.IsManString); writeln(c.IsAgeString); writeln(c.IsWorkingString); readln;

writeln('Создаем студента – десятилетний мальчик ???');

168

Page 169: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

a1.init(10,true); writeln(a1.InfoString); writeln(a1.IsManString); writeln(a1.IsAgeString); writeln(a1.IsWorkingString); readln;

writeln('Создаем студента – двадцатилетний юноша'); b1.init(20,true); writeln(b1.InfoString); writeln(b1.IsManString); writeln(b1.IsAgeString); writeln(b1.IsWorkingString); readln;end.

Внутри любого метода класса существует возможность использовать псевдопеременную self, которая собственно и является данным объектом. Для получения указателя на текущий объект можно воспользоваться оператором @: @self.

Методы классов могут быть статическими и виртуальными процедурами и функциями. Виртуальный метод обычно переопределяется внутри объекта-потомка в рамках полиморфизма (допускается также переопределение статических методов, однако свойства объекта-предка при этом не изменяются). Статические методы никак не выделяются. Виртуальные методы выделяются с помощью зарезервированного слова "virtual", которое ставится после заголовка метода внутри класса. За словом "virtual" может следовать целое число, с помощью которого изменяется внутренний способ вызова метода. Такие методы называются динамическими. Динамические и виртуальные методы отличаются друг от друга только способом вызова: виртуальные вызываются быстрее, но при их использовании объект занимает больше места в оперативной памяти, динамические вызываются медленнее, но экономят память. В дальнейшем, говоря о виртуальных методах, мы будем подразумевать как виртуальные, так и динамические методы.

Если метод однажды определен виртуальным, то во всех потомках при переопределении он также обязан быть виртуальным (аналогично для динамических методов). При этом количество и тип параметров в методах потомка и предка обязаны совпадать "один в один". При переопределении статических методов параметры могут не совпадать. Если однажды в иерархии классов статический метод переопределен виртуальным, то его дальнейшее переопределение возможно только по правилам виртуальных методов.

Обращение к виртуальным методам производится через особую таблицу виртуальных методов (VMT), определенную для каждого класса. Такое обращение позволяет реализовать полиморфизм, но замедляет вызов методов.

Объектный тип ТП поддерживает также специальные методы-процедуры, которые называются констракторами и дестракторами.

Констрактором называется специальная процедура – метод класса, с помощью которой производится инициализация объекта. Констракторы

169

Page 170: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

вызываются перед началом работы с объектом. Констракторы не могут быть виртуальными. Внутри тела констрактора обычно первым же оператором вызывают констрактор предка. Если класс имеет виртуальные методы, то перед их вызовом обязательно должен быть вызван констрактор, который дополнительно к инициализации объекта свяжет его с таблицей виртуальных методов класса. Специальная процедура fail позволяет прервать выполнение констрактора и провести деинициализацию, если произошла ошибка.

Дестрактором называется специальная процедура – метод класса, с помощью которой производится завершение работы с объектом. После вызова дестрактора структура объекта разрушается вместе с таблицей виртуальных методов. Дестракторы чаще всего бывают виртуальными.

Определение переменных объектного типа и обращение к ним происходит аналогично записям (то есть с помощью символа "." или оператора With).

Присваивание объектов друг другу разрешается в случае, если объекты принадлежат к одному и тому же классу, или в случае, когда в левой части присваивания стоит объект, являющийся предком второго объекта. В процессе присваивание копируется только содержимое полей объекта, т.е. автоматического вызова констрактора объекта левой части присваивания не происходит, и последующий вызов виртуальных методов такого объекта (если, конечно он заранее не был инициализирован констрактором) завершится ошибкой. Серьезные проблемы могут также возникнуть при попытке скопировать содержимое динамического объекта, действительный тип которого, как будет показано ниже, часто не совпадает с типом переменной, в которой хранится объект. Поэтому в присваивании для объектов следует придерживаться следующего правила: присваивание возможно только для статических объектов одного класса, в котором отсутствуют виртуальные методы.

Задача 56. Создать два объекта - точка и двоеточие на текстовом экране. Предусмотреть показ, скрытие и перемещение объекта.

uses crt;type txtPoint=object {объект "точка"} cod : byte; x,y : byte; {координаты точки} procedure init; {инициализировать точку} procedure switchon; {включить точку} procedure switchoff; {выключить точку} procedure move_to(newA,newB: byte); {переместить точку} end;

txt2Point=object(txtPoint) {объект "двоеточие" - наследник объекта точка} procedure init; {инициализировать двоеточие} procedure switchon; {включить точку} procedure switchoff; {выключить точку} end;

170

Page 171: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

{------------------------------------------------} procedure txtPoint.init; begin x:=1; y:=1; cod:=46; {код точки} end; procedure txtPoint.switchon; begin gotoxy(x,y); write(chr(cod)); end; procedure txtPoint.switchoff; begin gotoxy(x,y); write(' '); end; procedure txtPoint.move_to(newA,newB: byte); begin switchoff; x:=newa; y:=newb; switchon; end;{------------------------------------------------} procedure txt2Point.init; begin x:=40; y:=12; cod:=58; {код двоеточия} end; procedure txt2Point.switchon; begin gotoxy(x,y); write(chr(cod)+chr(cod)+chr(cod)); end; procedure txt2Point.switchoff; begin gotoxy(x,y); write(' '); end;{------------------------------------------------}var vPoint: txtPoint; v2Point: txt2Point; c:char;begin clrscr; vPoint.init; {инициализировать объект - "точка"} v2Point.init; {инициализировать объект - "двоеточие"} vPoint.switchon; {высветить точку} v2Point.switchon; {высветить двоеточие} c:=readkey; {ждем нажатие клавиши}{ ---- начало некорректно работающего блока ---- } vPoint.move_to(1,1); {переместить точку} v2Point.move_to(10,10); {переместить двоеточие}{ ---- конец некорректно работающего блока ---- } c:=readkey; {ждем нажатие клавиши}end.

171

Page 172: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

Подробнее рассмотрим процедуру txtPoint.move_to. procedure txtPoint.move_to(newA,newB: byte); begin switchoff; { гашение точки } x:=newa; y:=newb; switchon; { показ точки } end;Методы точки switchoff и switchon являются статическими, а не виртуальными, в

результате чего в основной программе появляется некорректно работающий блок:… vPoint.move_to(1,1); {переместить точку} v2Point.move_to(10,10); {переместить двоеточие}…где из двух вызовов методов правильно работает только первый. Второй вместо

перемещения двоеточия перемещает точку (гасится двоеточие и на новом месте показывается точка).

Для решения проблемы следует определить методы switchoff и switchon виртуальными:txtPoint=object {объект "точка"} … procedure switchon; virtual; {включить точку} procedure switchoff; virtual; {выключить точку} …end;

txt2Point=object(txtPoint) {объект "двоеточие" } … procedure switchon; virtual;{включить точку} procedure switchoff; virtual;{выключить точку} …end;Тогда в методе txtPoint.move_to будет происходить вызов не switchoff и switchon точки, а

switchoff и switchon того экземпляра класса, для которого вызывается метод.

Любой класс может иметь любое количество потомков, но только одного непосредственного прародителя. При этом любой из потомков имеет доступ ко всем полям и методам прародителей (исключение составляет раздел private, когда предок и потомок находятся в разных модулях).

Принципы ООП гласят, что непосредственно к полям класса или объекта следует обращаться как можно реже и где только возможно для доступа к полям должны быть использованы методы класса или объекта.

Программный проект (7)Наиболее эффективным методом организации графических примитивов в редакторе будет

объектно-ориентированный подход. Прежде всего требуется создать первоначальный, абстрактный графический класс, в котором будут инкапсулированы основные поля и методы, общие для всех примитивов.

{ модуль GrPrim.pas }

172

Page 173: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

…type{ абстрактный графический класс } pGrObject=^TGrObject; tgrObject=Object(tObject) constructor Init; { инициализирует объект } function Gettype:integer;virtual; { возвращает вид класса (константы определены выше) } procedure Show;virtual; { показывает объект } procedure XorShow;virtual; { показывает объект с операцией XOR (используется для интерактивного перемещения и изменения размеров объекта) } procedure Move(dx,dy:integer);virtual;{перемещает объект на DX,DY} function PointIn(x,y:integer):boolean;virtual; { возвращает TRUE, если точка с координатами (X,Y) попала в пределы объекта } procedure SaveASText(var f:text);virtual; {запись в текстовом формате} constructor load(var s:tstream); {чтение из потока} procedure store(var s:tstream); {запись в поток} procedure disable; { запрещает показ примитива из коллекции } procedure enable; { разрешает показ примитива из коллекции } private Disabled:boolean; end;…Большинство из этих методов являются абстрактными, то есть никогда не вызываются для

экземпляра класса tgrObject, и перекрываются в классах-потомках. Собственно, никогда не будет создан экземпляр класса tgrObject, хотя указатели на данный класс будут использоваться повсеместно. Класс tgrObject порожден от TObject, определенном в модуле Objects. Класс TObject является базовым для любых классов, которые в дальнейшем будут использовать мощную иерархию классов модуля Objects (см. параграф 2.3.2.3)

Рассмотрим некоторые методы класса.function TGrObject.Gettype:integer;virtual;Функция, возвращающая одну из констант определенных в фазе 6 на стр. 157. Данная

функция обязательно должна быть перекрыта в потомках класса TGrObject. С ее помощью мы будем определять, о переменной какого конкретно класса идет речь. Дело в том, что, как будет показано в следующем параграфе, могут существовать переменные-ссылки одного класса, указывающие на экземпляр класса-потомка от данного класса. Таким образом, мы будем работать в большинстве случаев с переменными типа PGrObject, которые, на самом деле, указывают на реальные графические примитивы – линии, окружности и т.д. В результате такого свойства классов, очень часто нельзя точно определить, на переменную какого класса ссылается тот или иной указатель. Для решения данной проблемы и будет использована функция GetType.

procedure TGrObject.Show;virtual;Процедура, визуализирующая объект. Обязательно должна перекрываться в потомках.

Каждый примитив показывает себя на экране отличным от других примитивов способом.procedure TGrObject.XorShow;virtual;Для интерактивного построения примитивов в графическом редакторе, мы будем

пользоваться XorShow. С ее помощью можно нарисовать изображение, а вторым вызовом стереть его, полностью восстановив первоначальный фон. Так будет достигнут эффект мультипликации

173

Page 174: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

при построении и перемещении примитивов. Процедура XorShow может не перекрываться в примитивах, использующих при своей визуализации только стиль линии и режим вывода на экран. Это касается линий и многоугольников.

procedure TGrObject.Move(dx,dy:integer);virtual;Перемещает примитив относительно его текущего местоположения на dx, dy. В

обязательном порядке перекрывается в потомках.function TGrObject.PointIn(x,y:integer):boolean;virtual;Используется при интерактивном выборе примитива на экране в графическом редакторе.

Возвращает Истину, если переданная точка (обычно - координаты мыши), попадает в пределы примитива. Всегда перекрывается в потомках.

procedure TGrObject.SaveASText(var f:text);virtual; Сохраняет примитив в текстовом файле в виде вызовов графических процедур и функций.

Предполагается, что файл заранее открыт для записи.constructor TGrObject.load(var s:tstream); procedure TGrObject.store(var s:tstream); Чтение и запись примитива в своем собственном формате. Более подробно будет

рассмотрено при изучении потоков (параграф 2.3.2.3).procedure TGrObject.disable;procedure TGrObject.enable;Запрещает и разрешает показ примитива из графической коллекции. Понятие коллекции

будет рассмотрено в параграфе 2.3.2.3, а на текущий момент нам достаточно знать, что коллекция – это объектный тип, в котором могут хранится другие объекты, своего рода аналог динамического массива в ООП. В дальнейшем мы создадим специализированную коллекцию, которая будет хранить в себе и манипулировать набором графических примитивов. Методы disable и enable изменяют значение поля disabled, которое анализируется при показе всех примитивов в коллекции.

Теперь нам известно достаточно, чтобы создать примитивы "Точка" и "Линия", а также реализовать все методы абстрактного графического примитива:

{ модуль GrPrim.pas }…{ класс "Точка" } PGrPoint=^TGrPoint; TGrPoint=Object(TGRObject) point: prPoint; {координаты точки} color: word; {ее цвет} constructor init(x,y:integer;c:word); procedure Show;virtual; function Gettype:integer;virtual; procedure Move(dx,dy:integer);virtual; function PointIn(x,y:integer):boolean;virtual; procedure saveASText(var f:text);virtual; constructor load(var s:tstream); procedure store(var s:tstream); end;

{ абстрактный промежуточный класс, предназначенный для хранения и обработки стиля линий } TAbstractLS=Object(TGRObject) Style:prLineStyle; {стиль} constructor Init(ls,up,tn,c:word);

174

Page 175: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

procedure SetLS; { установка стиля } procedure SaveASText(var f:text);virtual; constructor load(var s:tstream); procedure store(var s:tstream); end;

{ класс "Отрезок" ("Линия") } PGrLine=^TGrLine; TGrLine=Object(TAbstractLS) CoordLine:prRect; {координаты отрезка} constructor init(x1,y1,x2,y2:integer;ls,up,tn,c:word); procedure Show;virtual; function Gettype:integer;virtual; procedure Move(dx,dy:integer);virtual; function PointIn(x,y:integer):boolean;virtual; constructor load(var s:tstream); procedure store(var s:tstream); procedure saveASText(var f:text);virtual; end;…implementationuses inter;…{ ------------ TGrObject ------------- } procedure TGRObject.disable; begin disabled:=true; end;

procedure TGRObject.enable; begin disabled:=false; end;

procedure TGRObject.XorShow; begin SetWriteMode(XorPut); show; SetWriteMode(NormalPut); end;

constructor TGRObject.Init; begin Inherited Init; end;

function TGRObject.GetType:integer; begin GetType:=-1; end;

procedure TGRObject.show; begin abstract; end;

procedure TGRObject.Move(dx,dy:integer); begin abstract; end;

function TGRObject.PointIn(x,y:integer):boolean; begin abstract; end;

procedure TGRObject.saveAsText(var f:text); begin abstract; end;

constructor TGRObject.load(var s:tstream); begin s.Read(disabled,sizeof(disabled)); end;

procedure TGRObject.store(var s:tstream); begin s.Write(disabled,sizeof(disabled)); end;

{ ------------ TAbstractLS ------------- } constructor TAbstractLS.Init(ls,up,tn,c:word); begin

175

Page 176: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

inherited init; with style do begin color:=c; thickness:=tn; linestyle:=ls; pattern:=up; end; end;

procedure TAbstractLS.SetLS; begin with Style do begin SetLineStyle(linestyle,pattern,thickness); SetColor(color); end; end;

procedure TAbstractLS.saveAsText(var f:text); begin with style do begin writeln (f, ' SetLineStyle(',LineStyle,',',Pattern,',',Thickness,')', ';','{Установка стиля линий}'); writeln (f,' SetColor(',Color,')',';','{Установка цвета линий}'); end; end;

constructor TAbstractLS.load(var s:tstream); begin inherited load(s); s.read(style,sizeof (style)); end;

procedure TAbstractLS.store(var s:tstream); begin inherited store(s); s.write(style,sizeof (style)); end;

{ ------------ TGrPoint ------------- } constructor TGrPoint.Init(x,y:integer;c:word); begin Inherited Init; point.x:=x; point.y:=y; color:=c; end;

procedure TGrPoint.Show; begin with Point do PutPixel(x,y,color); end;

function TgrPoint.GetType:integer; begin GetType:=Typepoint; end;

procedure TGrPoint.Move(dx,dy:integer); begin with Point do begin inc(x,dx);inc(y,dy); end; end;

function TGrPoint.PointIn(x,y:integer):boolean; var r:trect; begin r.assign(x,y,x,y); r.grow(2,2); pointIn:=r.contains(point); end;

constructor TGrPoint.load(var s:tstream); begin inherited load(s); s.read(point,sizeof (point)); s.read(color,2); end;

176

Page 177: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

procedure TGrPoint.store(var s:tstream); begin inherited store(s); s.write(point,sizeof (point)); s.write(color,sizeof (color)); end;

procedure TGrPoint.saveAsText(var f:text); begin writeln(f,' {Рисуется точка}'); with point do writeln (f,' putpixel','(cx+',x,',','cy+',y,',',color,');'); end;

{ ------------ TGrLine ------------- } constructor TGrLine.Init(x1,y1,x2,y2:integer;ls,up,tn,c:word); begin Inherited Init(ls,up,tn,c); CoordLine.assign(x1,y1,x2,y2); end;

procedure TGrLine.Show; begin SetLS; with CoordLine do line(a.x,a.y,b.x,b.y); end;

function TGrLine.GetType:integer; begin GetType:=Typeline; end;

procedure TGrLine.Move(dx,dy:integer); begin CoordLine.Move(dx,dy); end;

function TGrLine.PointIn(x,y:integer):boolean; var r:prrect; begin r.assign(x,y,x,y); r.grow(2,2); pointIn:=LineIntersectRect(CoordLine,r); end;

constructor TGrLine.load(var s:tstream); begin inherited load(s); s.read(CoordLine, sizeof (CoordLine)); end;

procedure TGrLine.store(var s:tstream); begin inherited store(s); s.write(CoordLine,sizeof (CoordLine)); end;

procedure TGrLine.saveAsText(var f:text); begin writeln(f,' {Рисуется линия}'); inherited saveAsText(f); with CoordLine do writeln (f,' Line(cx+',a.x,',','cy+',a.y,',','cx+',b.x,',','cy+',b.y,')',';'); writeln(f); end;

177

Page 178: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

…Рассмотрим подробнее некоторые из методов, при реализации которых могут возникать различные вопросы.

1) Обращает на себя внимание активное использование методов класса prRect, который на самом деле, как видно из фазы 3 программного проекта, является классом TRect,определенным в модуле Objects.

Вот так выглядит его заголовок:TRect = object A, B: TPoint; procedure Assign(XA, YA, XB, YB: Integer); procedure Copy(R: TRect); procedure Move(ADX, ADY: Integer); procedure Grow(ADX, ADY: Integer); procedure Intersect(R: TRect); procedure Union(R: TRect); function Contains(P: TPoint): Boolean; function Equals(R: TRect): Boolean; function Empty: Boolean; end;

Как видно из заголовка, класс обладает множеством методов для манипуляции над прямоугольником. Рассмотрим некоторые из них:

procedure TRect.Assign(XA, YA, XB, YB: Integer);Заполняет поля A и B прямоугольника соответственно значениями XA, YA и XB, YB.procedure TRect.Move(ADX, ADY: Integer);Перемещает прямоугольник на ADX, ADYprocedure TRect.Grow(ADX, ADY: Integer);Увеличивает (уменьшает) прямоугольник на ADX, ADY относительно его центра.function TRect.Contains(P: TPoint): Boolean;Возвращает ИСТИНУ, если переданная точка находится внутри прямоугольника.Многие методы класса TRect подразумевают, что в точке A находится левый верхний угол

прямоугольника, а в точке B – правый нижний. При интерактивном создании примитива "прямоугольник" данное правило не выполняется примерно в 75% случаев, в результате чего методы TRect будут работать неверно. Для решения данной проблемы можно произвести "нормализацию" нестандартного прямоугольника процедурой NormalizedRect из модуля inter.pas (см. фазу 0 программного проекта)

2) Конструкторы Init. Обязателен вызов конструктора предка перед установкой полей:constructor TGrLine.Init(x1,y1,x2,y2:integer;ls,up,tn,c:word); begin Inherited Init(ls,up,tn,c); CoordLine.assign(x1,y1,x2,y2); end;Как видно из примера, вызов конструктора предка инициализирует поле Style, а только

затем инициализируется поле CoordLine.

3) Особенности методов PointIn.Метод PointIn используется для интерактивного выбора графического примитива

манипулятором "мышь". Используя подобный "ручной" выбор примитива, очень сложно попасть курсором точно на точку или линию. Поэтому будем считать, что точка выбора является на самом деле небольшим (5*5 точек) прямоугольником:

function TGrPoint.PointIn(x,y:integer):boolean; var r:trect;

178

Page 179: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

begin r.assign(x,y,x,y); r.grow(2,2); pointIn:=r.contains(point); end;function TGrLine.PointIn(x,y:integer):boolean; var r:prrect; begin r.assign(x,y,x,y); r.grow(2,2); pointIn:=LineIntersectRect(CoordLine,r); end;Функция LineIntersectRect, используемая в методе TGrLine.PointIn, позволяет

определить, пересекает ли линия прямоугольник. Функция определена в модуле inter.pas (см. фазу 0 программного проекта) и имеет следующий заголовок:

function LineIntersectRect(var oLine,oRect:TRect):boolean;где oLine – координаты линии, oRect – координаты прямоугольника.

Задания для программного проекта (154- 164).Задание 154. Создайте программу, в которой инициализируются, показываются и деинициализируются три объекта класса TGrPoint и два объекта класса TGrLine. Координаты и цвет примитивов выбираются случайным образом.Задание 155. Создайте и отобразите объект класса TGrLine. Случайным образом заполняйте экран точками до тех пор, пока очередная точка не окажется на созданной линии. Нарисуйте окружность радиусом в 5 единиц и центром в последней точке.Задание 156. Используя модуль Mouse.pas (см. фазу 0 программного проекта) и программную заготовку вида:

uses mouse, graph, …;var x,y:integer; left,right:boolean;const Quit:boolean=false;…begin … {инициализация графики} … ChkAndReset; repeat GetMouseState(x,y,left,right); … {набор действий} until Quit; readln; CloseGraph;end.

создать программу с двумя объектами TGrLine, выход из которой производится по щелчку мыши на одной из линий.Задание 157. Используя объект класса TGrLine для секундной стрелки, организуйте секундомер в центре экрана (см. задание 116). Задание 158*1. Определите класс TGrRect (прямоугольник)2. Создайте программу для проверки правильности работы всех его методов, в том числе и методов предков (для проверки метода PointIn можете воспользоваться заготовкой из задания 156). Не определяйте методов Load и Store.

1 Звездочка означает увеличенный объем задания2 При создании класса примитива следует продумать иерархию – от какого класса он будет порожден, какие классы

будут потомками, стоит ли создавать промежуточный (абстрактный) класс и т.д

179

Page 180: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Класс Турбо-Паскаля

Задание 159*. Решите задание 158 для класса TGrCircle (окружность)Задание 160*. Решите задание 158 для класса TGrEllipse (эллипс)Задание 161*. Решите задание 158 для класса TGrPoly (ломаная)Задание 162*. Решите задание 158 для классов TGrBar (закрашенный прямоугольник), TGrFillCircle (закрашенная окружность), TGrFillEllipse (закрашенный эллипс).Задание 163**3. Решите задание 158 для класса TGrFillPoly (закрашенный многоугольник). Особую сложность в реализации представляет собой метод PointIn.Задание 164**. Решите задание 158 для классов TGrArcCircle (дуга окружности), TGrArcEllipse (дуга эллипса), TGrText (строка), TGrPicture (рисунок), TGrFill (заливка).

2.3.2.2 Динамические объекты.

Как и любые переменные, объекты в ТП могут быть динамическими, т.е. в виде указателей на объекты. Использование динамических объектов позволяет во всей полноте применять свойство полиморфизма. На текущий момент в модуле GrPrim определено несколько таких указателей:{ модуль GrPrim.pas }… type

pGrObject=^TGrObject;pGrPoint=^TGrPoint;pGrLine=^TGrLine;

…Для выделения памяти под динамический объект стандартная процедура New

расширена в двух направлениях:1) Выделение памяти под объект происходит одновременно с вызовом

констрактора объекта. При это процедура New принимает два параметра – указатель на объект и вызов констрактора для типа данного объекта.

Создадим программу, в которой определяются три динамических объекта различных типов, последовательно инициализируются различными методами, показываются и перемещаются по экрану.uses GrPrim, graph, crt; var pA:pGrObject; pB:pPoint; pC:PLine; gd, gm:integer;begin gd:=detect; initgraph(gd,gm,''); if graphresult<>grOk then halt(1);New(pB,Init(34,40,15)); {создается динамический объект "Точка" в координатах 34,40 белым цветом} ...

2) Выделение памяти и вызов констрактора может производиться для одного объекта, а присвоение указателя - объекту, обычно являющемуся предком данного. В данном случае New является функцией, возвращающей указатель на объект. ... pC:=new(pGrline,init(10,10,100,250,0,0,1,14);{создается динамический объект "Линия" в координатах 10,10,100,250, сплошная, нормальной

3 Две звездочки означают повышенную сложность и увеличенный объем задания

180

Page 181: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Динамические объекты.

толщины, желтым цветом} pA:=new(pGrline,init(100,100,20,305,1,0,3,15);{создается динамический объект "Линия" в координатах 100,100,20,305, точечная, толстая, белым цветом. В результате pA (указатель на абстрактный графический примитив) указывает, в действительности, на объект "Линия"} ...

Второй способ выделения памяти является более предпочтительным, так как способствует унификации взаимодействия с иерархией классов. Продолжаем пример:…pa^.Show;pb^.Show;pc^.Show;readkey;cleardevice;pa^.Move(100,10);pb^.Move(100,10);pc^.Move(100,10);pa^.Show;pb^.Show;pc^.Show;readkey;…

Благодаря тому, что методы Move и Show являются виртуальными (обладают свойством полиморфизма), в примере для pA будут вызваны Move и Show класса TGrLine, а не TGrObject.

Для освобождения памяти служит процедура Dispose, расширенная для использования вместе с дестрактором. Завершаем пример: ... Dispose(pa,done); Dispose(pb,done); Dispose(pс,done); closegraph;end.

В любой серьезной программе предпочтение отдают динамическим, а не статическим объектам. Прежде всего это связано с мощными возможностями полиморфизма, которые в полной мере проявляются только при использовании динамических объектов. Хорошо спроектировав первоначальный класс – корень иерархии классов, можно построить программу или библиотеку процедур и функций, ориентированную на обработку динамических объектов данного класса. В дальнейшем, при добавлении нового класса, изменять код таких процедур и функций не потребуется, так как они одинаково хорошо будут работать с любым классом, порожденным от исходного. Динамические объекты настолько прочно вошли в практику программирования, что из языка Object Pascal (в среде Delphi), были полностью удалены статические объекты, в результате чего синтаксис обращения к динамическим объектам был значительно упрощен.

В разрабатываемом графическом редакторе повсеместно применяются динамические

181

Page 182: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Динамические объекты.

объекты, причем в подавляющем большинстве случаев ведется обработка переменных типа pGrObject. Таким образом, почти не требуется вносить изменения в программу при добавлении нового графического примитива (исключение составляют точки кода, в которых происходит создание примитивов и некоторые специфичные действия над их полями).

182

Page 183: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Динамические объекты.

2.3.2.3 Модуль OBJECTS.Для работы с объектами в поставку Турбо-Паскаля входит модуль Objects.Иерархия объектов, сосредоточенных в модуле Objects (в сокращенном виде)

TBufStream

TDosStreamTEmsStream

TStream

TResourceCollection

TStringCollection

TSortedCollection

TResourceFileTCollection

TObject

TMemoryStream

Класс TObject является стартовым объектом иерархии. Все классы, рассчитанные на использование коллекций (TCollection и порожденные от него), ресурсов (TResourceFile и порожденные от него) и потоков (TStream и порожденные от него) должны быть порождены от TObject.

TObject = object constructor Init; procedure Free; destructor Done; virtual;end;Инициализация объекта типа TObject производится с помощью конструктора

Init (при этом производится обнуление всех полей объекта), завершение – дестрактором Done. Процедура Free чаще всего используется для уничтожения динамического объекта:

procedure TObject.Free; begin Dispose(PObject(@Self), Done); end;Из тела метода Free очевидно, что ее вызов для статического объекта выдаст

ошибку времени выполнения.

Потоки

Потоки (класс TStream и все его потомки) – это универсальное средство для хранения любых данных (в том числе и объектов) на диске, в памяти или на любом устройстве, которое поддерживает ввод-вывод данных.

183

Page 184: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

TBufStream

TDosStreamTEmsStream

TStream

TObject

TMemoryStreamКласс TStream – абстрактный класс, описывающий основные поля и методы

для работы с потоком.Класс TEmsStream – поток в EMS-памяти. Класс TMemoryStream – поток в обычной (conventional) памяти.Класс TDosStream – поток в файле на диске.Класс TBufStream – буферизованный поток в файле на диске.Работа с потоком состоит из трех этапов:1. Создание (открытие) специализированного потока. 2. Сохранение или чтение данных 3. Уничтожение (закрытие) потока Методы работы с потоком очень схожи с файловым вводом-выводом, однако

имеются и серьезные отличия:1. Унификация чтения-записи данных. Запись и чтение производится едиными

методами для потока любого типа. Т.о. одна и та же процедура без модификаций может обращаться к потоку на диске, в оперативной памяти, в портах ввода-вывода и т.д.

2. Файловые потоки отличаются большей гибкостью, чем стандартный файловый ввод-вывод. Увеличилось количество режимов открытия файлов, специализированных методов для записи-чтения данных отдельных типов.

TStreamПоток типа TStream является абстрактным предком для всех остальных

классов потоков. Программист никогда не создает экземпляров класса TStream, используются только его потомки, где в обязательном порядке перекрываются методы чтения, записи, обработки позиции и размера потока, обработки ошибок.

Поля класса TStream:Status: Integer;

Ошибка последнего обращения к потокуВ модуле Objects определены следующие константы для данного поля: stOk = 0; { Нет ошибки } stError = -1; { Ошибка доступа } stInitError = -2; { Невозможно инициализировать поток} stReadError = -3; { Чтение данных за концом потока}

184

Page 185: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

stWriteError = -4; { Невозможно расширить поток} stGetError = -5; { Чтение из потока объекта незарегистрированного типа } stPutError = -6; { Запись в поток объекта незарегистрированного типа }

ErrorInfo: Integer;Дополнительная информация об ошибке, если Status<>stOk.

Методы класса TStream:constructor Init;

Инициализирует поток.procedure CopyFrom(var S: TStream; Count: Longint);

Копирует Count байт из потока S в текущий поток. Копирование производится с текущей и в текущую позицию.

procedure Error(Code, Info: Integer); virtual;Вызывается при возникновении ошибки.

function Get: PObject;Читает зарегистрированный ранее объект из потока

procedure Put(P: PObject);Сохраняет зарегистрированный раннее объект в потоке

function GetPos: Longint; virtual;Возвращает текущую позицию указателя в потоке

function GetSize: Longint; virtual;Возвращает размер потока

procedure Read(var Buf; Count: Word); virtual;Читает в переменную BUF Count байтов из потока

procedure Write(var Buf; Count: Word); virtual;Пишет в поток Count байт из переменную BUF

function ReadStr: PString;Читает из потока строку, сохраняя ее в куче и возвращает указатель на нее.

procedure WriteStr(P: PString);Сохраняет в потоке строку.

procedure Reset;Сброс ошибки. При возникновении любой ошибки ввода-вывода блокируются дальнейшие чтение и запись. Отменить блокировку можно методом Reset.

procedure Seek(Pos: Longint); virtual;Устанавливает текущую позицию в потоке

function StrRead: PChar;Читает из потока строку типа Pchar

procedure StrWrite(P: Pchar);Пишет в поток строку типа PChar

procedure Truncate; virtual;Усекает поток с текущей позиции до конца

TDosStream и TBufStreamФайловые потоки позволяют хранить данные на жестком диске. Одним из

185

Page 186: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

основных преимуществ файловых потоков перед файлами является большой набор режимов открытия файла. Если, например, нетипированный файл можно открыть только для чтения и записи одновременно, то потоковый файл разрешается открывать как для чтения и записи, так и только для чтения или только для записи.

Типичным примером проблемы, разрешаемой таким свойством файловых потоков, может служить следующая ситуация: Некоторая программа читает и обрабатывает содержимое файла на диске, который может быть рисунком, набором бинарных данных и т.п., причем данный файл требуется ей исключительно для чтения. Однако, из-за несовершенства стандартных средств файлового ввода Турбо-Пасаля, открытие такого файла возможно только для чтения и записи одновременно. Поместив программу на диск, например, локальной сети, который для многих пользователей может быть доступен только для чтения, мы тем самым запрещаем этим пользователям доступ к программе, так как попытка программы открыть типированный или нетипированный файл на таком диске завершится ошибкой времени выполнения.

TDosStreamDos-поток используется для хранения данных в файле на жестком диске.

Поля и методы класса TDosStreamHandle: Word;

Уникальный ИД обрабатываемого файла.constructor Init(FileName: FNameStr; Mode: Word);

Создает поток, ассоциируя его с файлом на диске.FileName - имя файлаMode - режим открытия файла

stCreate = $3C00; { создать файл }stOpenRead = $3D00; { доступ только для чтения }stOpenWrite = $3D01; { доступ только для записи }stOpen = $3D02; { доступ для чтения и записи }

TBufStreamБуферизованные дисковые потоки используются для ускорения обращения к

файлу.Методы класса TBufStream

constructor Init(FileName: FNameStr; Mode, Size: Word);Создает буферизованный поток на дискеSize – размер буфера

TMemoryStream и TEmsStreamПотоки в памяти служат для быстрого доступа к информации, ее временного

хранения и копирования. TМemoryStream

Методы класса TМemoryStreamconstructor Init(ALimit: Longint; ABlockSize: Word);

Создает поток в обычной памяти размером до 64 КБ.Alimit - максимальное количество блоков памяти

186

Page 187: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

AblockSize - размер одного блока.Количество блоков памяти не может превышать значения 16384.

TEmsStreamМетоды класса TМemoryStream

constructor Init(MinSize, MaxSize: Longint);Создает поток в EMS-памяти размером по меньшей мере в MinSize байт, расширяемый до MaxSize байт.

Хранение данных в потоках

Хранение обычных данных в потоке схоже с хранением данных в нетипированном файле. Для записи служат методы Write, WriteStr и StrWrite, для чтения – методы Read, ReadStr и StrRead, причем в отличии от файла, в котором размер минимального блока можно установить произвольно, чтение и запись в потоке производится побайтно. Установка потоковой позиции (аналогично файловой позиции) осуществляется методом Seek, а чтение – методом GetPos.

Задача 57. Создать 2 программы. Первая заполняет массив N случайными числами, выводит его на экран и сохраняет в потоке, вторая – считывает содержимое потока и выводит его на экран.

{первая программа}uses objects; var a:array [1..1000]of integer;

s:tBufstream;i,n:integer;

begin readln(n); for i:=1 to n do begin a[i]:=random(10); write(a[i]:3); end; writeln; s.Init('noname',stCreate,1024); s.write(a,sizeof(integer)*n); s.done;end.

{вторая программа}uses objects; var s:tBufstream;

i:integer;begin s.Init('noname',stOpenRead,1024); while s.GetPos<s.GetSize do begin s.read(i,sizeof(integer)); write(i:3); end; writeln; s.done;end.

187

Page 188: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

Задания для раздела "Хранение данных в потоках".

Задание 165. Используя два объекта класса TBufStream, создать программу копирования файлов. Имя исходного и результирующего файлов вводится с клавиатуры.

Задание 166. Создать процедуру, сортирующую переданный ей массив и сохраняющую результат в переданном потоке. Передаваемый массив должен являться параметром-переменной, передаваемый поток – либо параметром переменной класса TStream, либо параметром значением – указателем типа PStream. Проверить результат ее действия.

Задание 167. Создать процедуру, считывающую из переданного ей потока данные в переданный ей массив. Параметры процедуры аналогичны предыдущей задаче. Проверить результат ее действия.

Задание 168. Создать класс потока TMyStream, хранящий данные в массиве, который является полем этого класса (статическим или динамическим). Проверить полученный результат.

Хранение объектов в потоках.

Для хранения объектов, порожденных от TObject в потоке, требуется зарегистрировать каждый класс, экземпляры которого подлежат чтению-записи. Для это требуется:

наличие в классе методов чтения полей данных из потока и сохранения полей данных в потоке. Вид методов должен быть следующим:constructor load(var s:tstream); {чтение из потока}procedure store(var s:tstream); {запись в поток}Внутри констрактора Load требуется заполнить поля данных чтением их из потока S. Внутри процедуры Store требуется аналогичным образом сохранить поля данных в потоке. Соответствие между записью и чтением должно быть "один в один", то есть, из потока должно быть считано столько же байт, сколько ранее в нем было сохранено.

наличие специализированной переменной, заполняемой индивидуально для каждого класса, подлежащего сохранению в потоке. Тип переменной TStreamRec - определен в модуле objects и выглядит следующим образом:TStreamRec = record ObjType: Word; {уникальный ИД для каждого класса} VmtLink: Word; {адрес входа в таблицу VMT для класса} Load: Pointer; {указатель на метод загрузки объекта} Store: Pointer; {Указатель на метод сохранения объекта } Next: Word; {адрес следующей записи типа TStreamRec}end;В обязательном порядке должны быть заполнены все поля переменной, кроме поля Next, которое заполняется автоматически при последующей регистрации.

3) каждый класс должен быть зарегистрирован вызовом процедуры RegisterType:

procedure RegisterType(var S: TStreamRec);После регистрации класса его экземпляры можно сохранять в потоке методом

188

Page 189: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

TStream.Put, и считывать в дальнейшем методом TStream.Get.

Программный проект (8)В фазе 7 программного проекта был описан классы TGrObject, TGrPoint, TAbstractLS и

TGrLine, в каждом из которых, в свою очередь, были определены методы Store и Load для хранения полей класса в потоке. Напомним их реализацию, а также произведем регистрацию данных классов.

{ модуль GrPrim.pas }…implementationuses inter;…{ ------------ TGrObject ------------- }…constructor TGRObject.load(var s:tstream); begin s.Read(disabled,sizeof(disabled)); end;

procedure TGRObject.store(var s:tstream); begin s.Write(disabled,sizeof(disabled)); end;…{ ------------ TAbstractLS ------------- }…constructor TAbstractLS.load(var s:tstream); begin inherited load(s); s.read(style,sizeof (style)); end;

procedure TAbstractLS.store(var s:tstream); begin inherited store(s); s.write(style,sizeof (style)); end;…{ ------------ TGrPoint ------------- }…constructor TGrPoint.load(var s:tstream); begin inherited load(s); s.read(point,sizeof (point)); s.read(color,2); end;

procedure TGrPoint.store(var s:tstream); begin inherited store(s); s.write(point,sizeof (point)); s.write(color,sizeof (color)); end;…{ ------------ TGrLine ------------- }…constructor TGrLine.load(var s:tstream);

189

Page 190: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

begin inherited load(s); s.read(CoordLine, sizeof (CoordLine)); end;

procedure TGrLine.store(var s:tstream); begin inherited store(s); s.write(CoordLine,sizeof (CoordLine)); end;…

{ типированные константы для регистрации классов в системе потокового ввода-вывода }

constrGrPoint:tstreamrec= (objtype:2097; vmtlink:ofs(typeof (TGrPoint)^); load:@TGrPoint.load; store:@TGrPoint.store);

rGrLine:tstreamrec= (objtype:2098; vmtlink:ofs(typeof (TGrLine)^); load:@TGrLine.load; store:@TGrLine.store);…begin {секция инициализации модуля} {регистрация классов в системе потокового ввода-вывода} registertype(rGrpoint); registertype(rGrline);…end.

Проанализируем некоторые интересные моменты в регистрации классов. Во первых, может возникнуть вопрос, почему из четырех классов регистрируется только

два, несмотря на то, что методы Load и Store определены в каждом из четырех? Дело в том, что храниться в потоке будут экземпляры классов TGrPoint и TGrLine, а методы Load и Store оставшихся двух классов никогда не будут вызваны напрямую.

Во вторых, обращает на себя внимание формирование значений типированных констант для регистрации классов:

rGrPoint:tstreamrec= (objtype:2097; vmtlink:ofs(typeof (TGrPoint)^); load:@TGrPoint.load; store:@TGrPoint.store);Значение поля objtype должно быть уникальным во всей потоковой системе программы.

Так как значения от 0 до 999 зарезервированы Турбо-Паскалем для своих нужд, программист в потоковых переменных должен использовать значения >= 1000.

Поле vmtlink представляет собой смещение (offset) области памяти, в которой находится таблица виртуальных методов для данного класса (сегмент, в котором находится таблица,

190

Page 191: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

известен заранее – это сегмент данных, где хранятся все глобальные переменные). Рассмотрим способ получения значения поля vmtlink:

ofs(typeof (TGrPoint)^)Функция ofs возвращает смещение области памяти переменной, которая ей передана в

качестве аргумента. Функция typeof возвращает указатель на таблицу VMT переданного ей класса.

Задания для программного проектаЗадание 169. Определить методы Load и Store для классов примитивов TGrRect, TGrCircle, TGrEllipse, TGrPoly, TGrBar, TGrFillEllipse (см. задания 158- 164). Зарегистрировать каждый класс.Задание 170. Определить методы Load и Store для классов примитивов TGrFillPoly, TGrArcCircle, TGrArcEllipse, TGrText, TGrPicture, TGrFill (см. задания 158- 164). Зарегистрировать каждый класс.Задание 171. Определить массив, состоящий из графических примитивов. Случайным образом заполнить его точками и линиями. Визуализировать содержимое массива. Сохранить в потоке. Очистить массив. Загрузить примитивы из потока в массив. Снова визуализировать массив, предварительно очистив экран.Задание 172. Выполнить задание 171 для классов примитивов, определенных в задании 169.Задание 173. Выполнить задание 171 для классов примитивов, определенных в задании 170.

Коллекции

Коллекции (TCollection и все от него порожденные) являются структурой данных, в которой могут храниться другие данные.

Коллекции используются как аналог массивов для объектов, порожденных от TObject, имеют динамический размер и могут увеличивать свой размер в процессе заполнения. Нумерация элементов коллекции всегда начинается с 0.

Основные поля класса TCollection:Count:integer - количество элементов коллекции

Основные методы:

constructor Init(ALimit, ADelta: Integer);Инициализирует коллекциюALimit - максимальное кол-во элементов в коллекцииADelta - количество эл-тов для приращения при переполнении коллекции

destructor Done;virtual;Завершает работу с коллекцией, уничтожая ее содержимое с помощью вызова метода FreeAll

procedure Insert(Item: Pointer); virtual;Вставляет элемент в конец коллекции.Item - указатель на объект.

procedure AtInsert(Index: Integer; Item: Pointer);Вставляет элемент в коллекцию в позицию Index и сдвигает все последующие элементы на одну позицию вправо.

procedure AtPut(Index: Integer; Item: Pointer);

191

Page 192: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

Вставляет элемент в коллекцию в позицию Index, заменяя стоящий в этой позиции.

function At(Index: Integer): Pointer;По номеру элемента возвращает указатель на него

function IndexOf(Item: Pointer): Integer; virtual;По указателю на элемент возвращает его номер в коллекции или -1, если такого элемента в коллекции нет.

procedure Delete(Item: Pointer);Удаляет элемент из коллекции и сдвигает все последующие элементы на одну позицию влево.

procedure AtDelete(Index: Integer);Удаляет элемент по его номеру из коллекции и сдвигает все последующие элементы на одну позицию влево.

procedure DeleteAll;Удаляет все элементы из коллекции.Удаление объекта из коллекции не уничтожает его. Для уничтожения удаляемого объекта требуется либо вызвать после удаления Dispose, либо воспользоваться следующими методами.

procedure Free(Item: Pointer);Удаляет элемент из коллекции и уничтожает его (вызывая FreeItem).

procedure FreeAll;Удаляет все элементы из коллекции и уничтожает их (вызывая FreeItem).

procedure FreeItem(Item: Pointer);virtual;Уничтожает элемент. Никогда не вызывается напрямую.

function GetItem(var S: TStream): Pointer; virtual;Загружает элемент коллекции из потока и возвращает указатель на него. Перекрывается в коллекциях, элементы которых не являются объектами или не порождены от TObject.

procedure PutItem(var S: TStream; Item: Pointer); virtual;Сохраняет элемент коллекции Item в потоке. Перекрывается в коллекциях, элементы которых не являются объектами или не порождены от TObject.

constructor Load(var S: TStream);Загружает содержимое коллекции из потока

procedure Store(var S: TStream);Сохраняет содержимое коллекции в потоке

Методы коллекции, которые манипулируют нетипированными указателями, на самом деле подразумевают, что данные указатели являются динамическими объектами, порожденными от класса TObject. Фактически, в коллекции можно хранить не только объекты, но и любые структуры данных. Для этого надо четко понимать, в каких случаях элементы коллекции рассматриваются как объекты, а в каких – как обычные указатели: при уничтожении, сохранении в потоке и чтении из потока элементы коллекции обрабатываются как динамические объекты,

192

Page 193: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

порожденные от TObject . Таким образом, класс TCollection можно использовать для хранения любых

данных, если никогда прямо или косвенно не вызвать методы FreeItem, PutItem и GetItem. Из этого правила очевидно следует два приема:

1) Не сохранять содержимое коллекции в потоке и не производить оттуда чтения.

2) Перед уничтожением коллекции удалять из нее все элементы.

В модуле Objects определена переменная RCollection типа TStreamRec. Однако регистрацию коллекции в потоке программист обязан произвести самостоятельно, в начале программы или в одной из секций инициализации модулей программы вызовом RegisterType(RCollection).

Задача 58. Создать коллекцию из 20 случайных элементов - точек или линий, вывести ее на экран, а затем удалить. var Pcl:PCollection; po:pGrObject; i,k:integer; begin ... new(pcl, init(20,0)); for i:=1 to 20 do begin k:=random(2); if k=0 then po:=new(PPoint,Init(Random(640),random(350),random(16))

else po:=new( PLine, Init ( Random(640) , random(350), Random(640),random(350), 0,0,1,random(16));

pcl^.Insert(po); end; for i:=0 to pcl^.count-1 do begin pGrObject(pcl^.at(i))^.Show; end; pcl^.FreeAll; ....

Программный проект (9)Для управления набором графических примитивов мы создадим специализированную

графическую коллекцию для хранения примитивов, методы которой позволят нам показывать примитивы, сохранять всю коллекцию в текстовом файле и определять примитив, на который указывает курсор мыши.{ модуль GrPrim.pas }…{ класс "Коллекция графических примитивов"} TGrCollection=object(TCollection) procedure SaveASPas(filename,procname:string);

{ сохраняет содержимое коллекции в виде процедуры в подключаемом ($I) к паскалевской программе файле }

procedure Show; { показывает коллекцию }

193

Page 194: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

function ObjectOnPoint(TP:TPoint):PGrObject;{ возвращает последний (ближний в Z-упорядочивании) объект, включающий в себя переданную точку. Возвращает nil, если такого объекта нет }

end;…implementationuses inter;…{ ------------ TGrCollection ------------- } procedure tgrCollection.saveaspas(filename,procname:string); var f:text; i:integer; begin assign(f,filename); rewrite (f); writeln(f,'Procedure '+procName+'(cx,cy:integer)'+';'); writeln(f,'Begin'); for i:=0 to count-1 do pgrobject(at(i))^.saveastext(f); writeln(f,'End;'); close(f) ; end;

procedure tgrCollection.show; var i:integer; begin for i:=0 to count-1 do with pgrobject(at(i))^ do if not disabled then show; end;

function tgrCollection.ObjectOnPoint(TP:TPoint):PGrObject; var i:integer; begin ObjectOnPoint:=nil; for i:=count-1 downto 0 do if pgrobject(at(i))^.PointIn(tp.x,tp.y) then begin ObjectOnPoint:=at(i); exit; end; end;

Задания для программного проектаЗадание 174. Создать и заполнить произвольным набором примитивов две графических коллекции. Визуализировать по нажатию клавиши поочередно первую, затем вторую коллекции, затем снова первую и т.д. до тех пор, пока не будет нажата клавиша ESC.Задание 175. Создать и заполнить произвольным набором примитивов графическую коллекцию. Сохранить ее в потоке и паскалевском файле. Уничтожить коллекцию. Загрузить коллекцию из потока и визуализировать ее, предварительно очистив экран.Задание 176. Создать и заполнить произвольным набором примитивов графическую коллекцию. Используя программную заготовку из задания 156, удалять из коллекции те примитивы, на которых произошел щелчок левой кнопкой мыши. Перерисовывать коллекцию после каждого успешного удаления. Выход из программы по щелчку правой кнопкой.Задание 177. Создать и заполнить произвольным набором примитивов, состоящем из точек, линий и прямоугольников, три графических коллекции. Последовательно визуализировать все три коллекции. Переместить все точки в первую коллекцию, все линии – во вторую, все

194

Page 195: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

прямоугольники – в третью. Снова последовательно визуализировать все три коллекции.

Ресурсы

Ресурсы (TResourceFile)- это потоки произвольного доступа, где содержатся объекты, каждый из которых доступен по уникальному ключу - строке, идентифицирующей объект. Существует возможность узнать количество элементов в ресурсе, получить ключ по номеру элемента в ресурсе, загрузить элемент по его ключу, удалить элемент и т.д. Ключи в ресурсе всегда хранятся в алфавитном порядке.

Одним из специфичных свойств ресурсов является возможность дозаписи их к концу EXE-файла с последующим чтением оттуда. Т.о. можно создавать и распространять программы, которые будут состоять из одного EXE-файла и произвольно самомодифицироваться в области данных.

Поля и методы класса TResourceFileStream: PStream;

Указатель на поток, ассоциированный с данным ресурсом.Modified: Boolean;

True, если ресурс был изменен (внесены или удалены данные)constructor Init(AStream: PStream);

Инициализирует ресурс, передавая ему ранее созданный поток. Если в текущей позиции переданного потока находится ИД EXE-файла, то конструктор передвигает позицию на конец файла, или на начало ресурса, который уже находится в EXE-файле.

destructor Done; virtual;Уничтожает ресурс, закрывая при этом ассоциированный с ним поток.

function Count: Integer;Возвращает количество объектов в ресурсе, их нумерация начинается от 0.

procedure Put(Item: PObject; Key: String);Добавляет объект в ресурс, ассоциируя его с ключевой строкой. Если объект с такой ключевой строкой уже имеется в ресурсе, то он заменяется новым объектом.

function Get(Key: String): PObject;Возвращает указатель на объект, считанный по ключевой строке из ресурса

function KeyAt(I: Integer): String;Возвращает строку, ассоциированную с I-м объектом в ресурсе.

procedure Delete(Key: String);Удаляет объект из ресурса по ключевой строке. Объект не удаляется физически, исчезает только ссылка на него. Для физического удаления следует в дальнейшем воспользоваться функцией SwitchTo.

function SwitchTo(AStream: PStream; Pack: Boolean): PStream;Переключает (копирует) ресурс с текущего потока на поток Astream. Старый поток возвращается как результат функции. Если Pack=true, то данные,

195

Page 196: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

переносимые из старого потока в новый пакуются, т.е. освобождаются от удаленных объектов.

Задача 59. Создать программу, управляющую ресурсом, состоящим из графических коллекций и хранящимся в самом файле программы. Предусмотреть добавление коллекций в ресурс и их показ.

uses grprim,crt,graph,objects;function CreateRandomGrC:PGrCollection;

{ создает и возвращает графическую коллекцию, заполняя ее 15 произвольными линиями 15 цветами }

var P:PGrCollection; i:integer; begin randomize; p:=new(PGrCollection,init(100,100)); for i:=1 to 15 do p^.insert(new(pgrLine, init(random(640),random(480),random(640),random(480),0,0,1,i))); CreateRandomGrC:=p; end;

procedure ShowGrC(p:PGrCollection);{ инициализирует графический режим, показывает коллекцию, ожидает нажатия клавиши Enter и завершает работу с графикой }

var grDriver: Integer; grMode: Integer; ErrCode: Integer; begin grDriver:=Detect; InitGraph(grDriver, grMode,''); p^.show; Readln; CloseGraph; end;

var RF:TResourceFile; Pgrc:PGrCollection; s:string; i,num:integer;begin RF.Init(New(PBufStream, Init(paramstr(0), stOpen, 1024)));

{ инициализируем ресурс, передавая ему в качестве параметра создаваемый поток в файле, который является самой программой }

repeat clrscr; writeln('В ресурсе имеются следующие рисунки:'); if rf.count=0 then writeln(' ------- пусто ------- ') else for i:=0 to rf.count-1 do writeln(' ',i,'. ',rf.KeyAt(I)); writeln('Выберите один из них (номер),'); writeln('введите -1 для создания нового рисунка,'); writeln('или -2 для выхода из программы'); readln(num); if num=-1 then begin write('Введите новый ключ: ');readln(s); pgrc:=CreateRandomGrC; rf.put(pgrc,s); ShowGrC(pgrc);

196

Page 197: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Модуль OBJECTS.

dispose(pgrc,done); end else if num<>-2 then begin if (num>=0)and(num<rf.count) then begin pgrc:=pgrcollection(rf.Get(rf.keyAt(num))); ShowGrC(pgrc); dispose(pgrc,done); end; end; until num=-2; rf.done;end.

Проанализируйте и проверьте решение.

Задания для раздела "Ресурсы".Задание 178. В примере, показанном выше, добавьте возможность удаления элементов из ресурса.Задание 179*. Создать программу сохраняющую набор графических коллекций в ресурсе отдельным файлом. Создать вторую программу, присоединяющую ресурс в отдельном файле, имя которого вводится с клавиатуры, к самой себе и циклически визуализирующую элементы ресурса с паузой в 1 секунду. Если имя ресурса неверно или не введено, считается, что ресурс уже присоединен к программе. Если введено правильное имя ресурса, но ресурс уже присоединен к программе, то старый ресурс заменяется новым. Выход из программы – по нажатию на любую клавишу. Задание 180. Используя файл ресурса, созданный предыдущей программой, последовательно показать только те коллекции, имена которых находятся в текстовом файле, переданном программе в командной строке.

197

Page 198: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Отладка программ.

2.4 Отладка программ.Отладкой называется процесс поиска и исправления ошибок в программах.

Процесс отладки – обязательный атрибут современного программирования, и от знания приемов и методов, а также совершенства средств отладки зависит скорость создания программ и надежность конечного программного продукта.

2.4.1 Виды ошибокОшибки в программах подразделяются на 2 больших классах -

синтаксические и семантические.Синтаксические ошибки возникают обычно из-за нарушений правил языка

программирования. Компилятор или интерпретатор программы сам определяет их местоположение. Таким образом не представляет труда локализировать и исправить такие ошибки.

Иногда исправление синтаксических ошибок вызывает затруднения, и чаще всего причина этого – плохое знание языка программирования. Например, в зарезервированном слове implementation легко сделать сразу несколько ошибок, также как и в слове constructor (особенно, если писать его так, как оно произносится). Иногда по вине программиста в зарезервированном слове появляются русские буквы, что компилятору переварить не под силу (хотя чисто визуально и русское и латинское "o" выглядит одинаково).

Большие трудности вызывают ошибки, связанные с незакрытыми блоками begin..end или скобками в выражениях. Для их исправления нужна большая внимательность и тщательный подсчет. По этой причине и предлагают выделять любые блоки едиными отступами в строках.

Семантические ошибки - это ошибки связанные с содержанием и смыслом программы. Причины ошибок могут быть самыми различными: может быть неверным алгоритм, при написании программы произошла опечатка, не нарушившая синтаксис (вместо 2 написали 3, вместо "+" напечатали "-") и т.д. Локализация таких ошибок и является главной задачей отладки.

По результатам своего действия семантические ошибки в контексте ТП делятся еще на два вида: ошибки времени выполнения (Runtime Errors - RTE) и логические ошибки.

Ошибки времени выполнения вызывают аварийный останов программы (переполнение стека из-за ошибок в рекурсии, переход за границы массива, запись на переполненный диск, переполнение числового значения и т.д.). Местоположение ошибки времени выполнения выявляется сразу по ее возникновении. ТП останавливает программу и переводит курсор на строку, где возникла ошибка.

Например, функция следующего вида:function f(x:integer):real; begin if x=1 then f:=1 else f:=f(x-1)*x end; {x! при x N}с первого взгляда не содержит логических ошибок. Однако серьезный анализ покажет сразу две семантические ошибки – ошибки времени выполнения. Первая ошибка, при относительно небольших значениях х, – это ошибка переполнения вещественного значения (Floating point overflow), вторая, при больших значениях х, – переполнение стека (Stack overflow error). Проверьте эту функцию с различными значениями параметра x.

ТП позволяет отключить слежение за такими ошибками, однако это не

198

Page 199: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Виды ошибок

рекомендуется делать во время отладки программы. Отключение слежения уменьшает размер и увеличивает скорость работы программы, однако в случае возникновения ошибки может привести к непредсказуемым последствиям (чаще всего – зависание программы).

Слежение за ошибками времени выполнения реализуется с помощью элемента меню Options/Compiler/ или специальных директив компилятора:

Options/Compiler/ Range checking - слежение за ошибками выхода за границу. Директива {$R+} или {$R-}Options/Compiler/ Stack checking - слежение за ошибками переполнения стека. Директива {$S+} или {$S-}Options/Compiler/ I/O checking - слежение за ошибками ввода-вывода. Директива {$I+} или {$I-}Options/Compiler/ Overflow checking - слежение за ошибками переполнения. Директива {$O+} или {$O-}Результатом логических ошибок является неверная работа программы, т.е.

программа делает то, что ей сказано, а не то, что хотелось бы. Это наиболее сложный для локализации вид ошибок, хотя сложность их исправления соответствует сложности исправления Runtime ошибок.

Рассмотрим предыдущий пример, немного видоизменив его:function f(x:integer):real; begin if x=1 then f:=0 else f:=f(x-1)*x end; {x!}

В данном случае, добавилась логическая ошибка, которая обычно является результатом невнимательности или незнания формулы вычисления факториала. В результате функция будет возвращать 0 вне зависимости от значения x. Интересным побочным результатом такой ошибки является исчезновении ошибки переполнения вещественного значения.По вероятности возникновения семантические ошибки делятся на явные и

потенциальные. Явные ошибки всегда возникают при прохождении ошибочного участка кода (например – при делении на 0 или на переменную, значение которой в данной точке программы всегда равно нулю). Для возникновения потенциальных ошибок обычно требуется совпадение нескольких, иногда и маловероятных условий (например – при вычислении гипотенузы по теореме Пифагора можно в некоторых случаях получить ошибку переполнения числового значения). Потенциальные ошибки наиболее сложны в констатации, локализации и исправлении. Такие ошибки могут проявится через несколько месяцев, а то и лет, после ввода программы в эксплуатацию.

Снова рассмотрим функцию вычисления факториала:function f(x:integer):real; begin if x=1 then f:=1 else f:=f(x-1)*x end;

Обе ошибки времени выполнения, присутствующие в решении, являются потенциальными, так как при небольших значениях x функция работает верно, а ошибки возникают при увеличении значения аргумента.

Задания для раздела "Виды ошибок" Задание 181. Найдите и исправьте ошибки в следующей программе:

var c:pgrcollection;begin

199

Page 200: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Задания для раздела "Виды ошибок"

c.init(10,10); for i:=1 to random(1000) do begin c.insert(new(pgrpoint,init(random(100,100,15))); for i:=1 to c.count do with pgrpoint(c.at(i)).point do writeln(x:5,y:5);end.

Задание 182. Найдите и исправьте ошибки в следующей программе:var s;n:integer;

begin readln(n); for i:=1 to n do begin s:=s+n; writeln(s) end;end;

Задание 183. Определите, какие из семантических ошибок в предыдущем задании являются явными, а какие – потенциальными.

2.4.2 Констатация и локализация ошибокПроцесс отладки состоит из двух частей: констатации и локализации ошибки.

1) Констатация ошибки.До поиска ошибки требуется выяснить, существуют ли вообще ошибки в

программе. Для решения этой задачи программу пропускают на контрольных примерах, причем стараются, чтобы выполнение программы прошло по всем элементам блок-схемы алгоритма. Как только выяснилось, что результат выполнения программы вступает в противоречие с эталонным, или происходит RTE, вступает в действие второй этап отладки.

Возвратимся снова к примеру с вычислением факториала.function f(x:integer):real; begin if x=1 then f:=1 else f:=f(x-1)*x end; {x!}

Не смотря на явное наличие двух ошибок времени выполнения, констатировать их наличие можно не при любых значениях x. Это одна из основных проблем в констатации ошибок. Без проверки граничных условий резко уменьшается надежность программы и повышается вероятность возникновения трудноуловимых семантических ошибок. Особенно трудноуловимы ошибки, результат которых непредсказуем или проявляется в различных, не связанных с первого взгляда друг с другом ситуациях. При отключении проверки на возникновение ошибок времени выполнения резко повышается сложность как их констатации, так и локализации. В это случае RTE могут не иметь никаких последствий, а могут стать результатом "зависания" программы. Данная ситуация служит прекрасной иллюстрацией к поговорке "раз на раз не приходится".

2) Локализация ошибки.RTE в большинстве случаев не требуют локализации, так как местоположение

такой ошибки становится известным при ее возникновении. Исключение составляют случаи, когда RTE происходят в модулях без исходных текстов. Тогда возвращаемый адрес памяти не может быть сопоставлен со строкой программы и сложность локализации RTE становится сопоставимой со сложностью локализации логических ошибок.

200

Page 201: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Констатация и локализация ошибок

Для поиска логических ошибок в программе существует несколько методов.а) Метод промежуточных результатов, заключающийся в том, что в

"подозрительном" месте программы устанавливают ловушку, которая выводит на экран или в файл содержимое тех переменных, неверное значение которых может стать причиной ошибки. После окончания (в случае вывода в файл) или во время работы (при выводе на экран), анализируются значения переменных. Если ошибка не найдена, то ловушку переносят в другое подозрительное место и все начинается сначала, до тех пор пока ошибка не будет найдена.

Данный метод является одним из наиболее старых, трудоемких и требующих определенных навыков. В то же время владение этим методом - один из признаков профессионализма программиста. С определенными изменениями и для совершенно других целей данный метод используется при хакинге и крекинге особо защищенных программ.

б) Использование встроенного или внешнего отладчика, позволяющего трассировать программу, то есть выполнять ее шаг за шагом, устанавливать условные и безусловные точки прерывания, просматривать и изменять значения переменных, просматривать значения констант, перемещаться по процедурам, из которых была вызвана текущая.

Т.о. для локализации логической ошибки требуется обычно несколько раз запустить программу, анализируя полученные результаты и все более уточняя местоположение ошибочных действий.

С появлением отладчиков и увеличением быстродействия компьютеров резко повысилась скорость создания программ. Побочным же результатом явилось понижение качества и культуры программирования. Если ранее любой создаваемый алгоритм тщательно анализировался и оптимизировался "на бумаге", где и выявлялось большинство семантических ошибок, то теперь, после поверхностного анализа, а иногда и без оного, алгоритм переносится на машину, где и "прогоняется" на предмет ошибок. Именно поэтому во многих областях науки и техники с успехом применяются программы двадцатилетней давности, в то время как в новейших разработках каждый месяц выявляются все новые и новые ошибки, на исправление которых уходят гигантские человеко-машинные ресурсы.

2.4.3 Использование встроенного отладчика.Встроенный отладчик в ТП включается помощью меню или опций

компилятора Debug Information и Local symbols в Options/Compiler, а также кнопки Integrated в Options/Debugger.

Под точкой прерывания понимается строка программы, где произойдет остановка при ее выполнения. Безусловные точки прерывания устанавливаются с помощью Ctrl-F8 (Debug/Toggle breakpoint). Для задания условия прерывания требуется выбрать прерывание в элементе меню Debug/Breakpoints и записать условие прерывания в соответствии с общими правилами записи условий Турбо-Паскаля.

Там же можно установить счетчик, показывающий, при котором прохождении через точку прерывания произойдет останов программы.

Просмотр и изменение значения переменных можно сделать с помощью Ctrl-F4 (Debug/Evaluate/modify).

201

Page 202: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Использование встроенного отладчика.

С помощью окна стека можно увидеть весь вложенный набор процедур с их параметрами. Можно также войти выбрать и войти в любую из этих процедур с помощью Enter.

Изменение значений переменных и выражений во время пошагового выполнения программы можно просмотреть с помощью окна выражений (Window/Watch), если эти переменные были туда внесены с помощью Ctrl-F7 (Debug/Watches/Add watch). В окно выражений можно войти и редактировать внесенную переменную, нажав на ней Enter, либо использовав элемент меню Debug/Watches/Edit watch.

Пошаговое выполнение программы производится с помощью F7 и F8 (Run/Trace into и Run/Step over). Также существует возможность выполнить программу до точки, где находится курсор, с помощью F4 (Run/Go to cursor).

202

Page 203: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Разработка больших программ.

2.5 Разработка больших программ.

2.5.1 Общие принципы разработки программ.Существует два наиболее общих принципа создания программ.

2.5.1.1 Метод организации «сверху-вниз». Сначала строится основная программа (процедура, функция и т.д.), в

котором словесно или ограниченно-синтаксически (с помощью последовательности действий, блок-схем или диаграмм Насси-Шнайдермана) описываются все требуемые действия. Процесс может повторяться циклически, все более и более уточняя и раскрывая набор действий.

Затем словесная и ограниченно-синтаксическая организация заменяется набором действий и вызовами других подпрограмм (процедур, функций и т.д.), описанных в других модулях или еще не определенных. Попутно определяется набор переменных и других структур, требуемых для выполнения программы.

Каждая неопределенная подпрограмма (заглушка) определяется тем же методом, что и основная до тех пора, пока все модули и основная программа (подпрограмма) не будут созданы.

2.5.1.2 Метод организации «снизу-вверх».Данный метод используется в случае, когда конечный результат известен

только в общих чертах, однако с достаточной точностью определено, какой набор подпрограмм и модулей может потребоваться для построения программы или искомой подпрограммы.

Определяются подпрограммы самого низкого уровня. На их основе создаются подпрограммы и модули более высокого уровня.

Процесс продолжается циклически до тех пор, пока не будет создана основная программа или подпрограмма.

2.5.1.3 Достоинства и недостатки обоих методов:Первый метод требует детальной разработки структуры программы с

постоянными уточнениями на каждом этапе. Этот процесс удобен для определения, изменения и уточнения общей идеи проекта, однако результат работы программы может быть протестирован только в самом конце.

Достоинством второго метода является возможность проверки каждой подпрограммы нижнего и среднего уровня сразу после создания, т.е. тестирования и отладки отдельных частей программы. Однако в этом случае процесс уточнения общей идеи проекта заставляет видоизменять уже созданные подпрограммы и

203

Page 204: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Достоинства и недостатки обоих методов:

модули, разрывая отлаженные связи. Поэтому при реализации данного метода надо стремиться к максимальной автономности каждой подпрограммы, каждого модуля, их независимости от других подпрограмм и модулей.

Наиболее часто встречается комбинирование первого и второго методов в различных пропорциях. При разработке библиотек процедур и функций, объеденных некоторой концепцией, в большей степени применяют второй метод. При разработке больших программ на начальных этапах активно применяется первый метод, а на промежуточных и заключительных – второй.

Рассмотрим, как мог бы проходить процесс решения задачи номер 59. Напомним ее условие: Создать программу, управляющую ресурсом, состоящим из графических коллекций и хранящимся в самом файле программы. Предусмотреть добавление коллекций в ресурс и их показ.

Метод организации "сверху-вниз":Этап 1. Разработка основной модели.4. Создаем ресурс5. Организуем цикл для вывода меню, ввода данных и их обработки.6. Закрываем ресурс.

Этап 2. Уточнение основной модели.Уточняем пункт 2 основной модели2.1 Выводим меню выбора, созданное на основе строк ресурса с возможными

вариантами: просмотра соответствующей коллекции, создания и добавления новой коллекции в ресурс, выхода из программы.

2.2 Обрабатываем варианты просмотра и добавления коллекции, завершаем цикл обработкой варианта выхода из программы.

2.3 Создаем процедуры просмотра и создания коллекции.Этап 3. Реализация модели на языке программирования.

Второй метод организации ("снизу-вверх") применим здесь ограниченно, хотя его комбинация с первым методом может дать неплохие результаты. Дело в том, что вполне очевидны требования к наличию подпрограмм создания, просмотра, удаления (в расширенном условии задачи) и т.д. коллекции. С их реализации и можно начать разработку программу, с учетом, конечно, полной автономности этих подпрограмм, так как изначально отсутствуют любые глобальные структуры данных. Затем можно создать подпрограмму для обработки меню, что еще более упростит основную программу, и, наконец, создать основную программу, разработав предварительно упрощенную модель по методу "сверху-вниз".

204

Page 205: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Достоинства и недостатки обоих методов:

2.5.2 Концепции разработки больших программных проектов (БПП).

Для создания БПП следует определить основные концепции его разработки:1. Ясная цель и концептуальное единство.2. Рабочая сила.3. Материалы.4. Достаточное кол-во времени.5. Соответствующую технологию.6. Организация связи между разработчиками программного проекта.

Одним из самых важных элементов процесса создания ПП является постановка и определение задачи (1), предварительное проектирование и разбиение ее на несколько небольших частей, каждая из которых может быть решена и отлажена как единое целое (1) одним человеком либо коллективом программистов.

Затем следует определение базовой платформы (3), программного обеспечения (3,5), требуемого для решения задачи, временные рамки, за которые должен быть создан проект и в соответствии с этим - количество программистов, отвечающих за отдельные блоки программы (2).

И, наконец, создание системы связи между разработчиками проекта (6).

2.5.2.1 Руководство программным проектом и коллектив программистов.

И опыта разработки больших ПП следует, что определение задачей и целей проекта, связь с заказчиком, постановка временных рамок должны производиться одним человеком, так как только в этом случае может быть достигнуто общее концептуальное единство проекта. Этот человек называется руководителем проекта, имеет в своем подчинении администратора, отвечающего за смету проекта и системного архитектора, отвечающего за разбиение задачи на отдельные части, каждая из которых должна быть поручена для разработки коллективу программистов.

Любой коллектив (бригада) программистов для оптимального достижения своей цели должен быть организован по следующему принципу:

1) Главный программист.Пишет и отлаживает программу, согласовывает входные и выходные

спецификации со своим архитектором, готовит документацию. Наиболее квалифицированное звено программного проекта.

2) Помощник главного программиста (второй пилот). Работает совместно с главным программистом, но не настолько опытен. Может взять на себя выполнение

205

Page 206: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Руководство программным проектом и коллектив программистов.

любой части поставленной задачи. До тонкостей знает всю программу. Ищет альтернативные стратегии решения, представляет бригаду на обсуждениях и дискуссиях с архитекторами и другими бригадами.

3) Инструментальщик (системный программист). Разрабатывает ресурсозависимые приложения для решения задачи, получая условия от главного программиста. Работает обычно на языке низкого уровня. До тонкостей знает все нюансы операционной системы и компьютера, на которых будет работать готовая программа.

4) Контролер. Готовит тесты для программы и прогоняет их на каждом варианте решения задачи. Отвечает за констатацию ошибок.

5) Языковед. Человек, посвященный во все тонкости языка программирования высокого уровня, на котором пишется программа. Обязан оказывать помощь главному программисту в случае появления чисто языковых проблем.

6) Администратор. Отвечает за предоставление машинных мест и времени, за все материальные запросы бригады. При необходимости может обслуживать несколько бригад.

7) Редактор. Отвечает за правильное оформление всей документации по проекту.

8) Архивариус. Отвечает за хранение всех версий решения за дачи. Всегда может предоставить хирургу или помощнику один из старых вариантов решения для отладки, тестирования и т.д. В настоящее время функции архивариуса обычно инкапсулированы в инструментальную систему коллективной разработки программных проектов.

При использовании средств мультимедиа в состав бригады включаются художники и музыканты.

В случае небольшого объема задачи состав как руководства, так и бригад может быть изменен. Руководитель проекта может взять на себя функции системного архитектора, главный программист - функции инструментальщика и языковеда, второй пилот - функции редактора, архивариуса и контролера, администратор проекта - функции всех администраторов бригад.

В этом случае руководство проектом состоит из руководителя проекта и администратора, которые управляют набором бригад, каждая из которых состоит из двух человек - главного программиста и его помощника.

2.5.2.2 Концептуальное единство проекта.Как было показано выше, любой программный проект для решения

разбивается на отдельные модули. Отлаженная связь между этими модулями и подразумевается под концептуальным единством проекта.

Определяя подзадачи, системный архитектор активно использует метод разработки программ "сверху-вниз", руководствуясь при этом несколькими

206

Page 207: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Концептуальное единство проекта.

правилами:1) Четко и однозначно определяет входные и выходные данные каждого

модуля.2) Определяет максимальные системные ресурсы, которые могут быть

выделены под данную задачу.3) Передает информацию о пунктах 1 и 2 для каждой группы программистов

главному программисту каждой группы. Таким образом главный программист сможет учесть и использовать обращения к параллельно создаваемым модулям при решении своей задачи.

4) Предпочитает отлаженный и работоспособный модуль любому другому (более скоростному, менее ресурсоемкому, но не отлаженному).

2.5.2.3 Ошибки при реализации проекта.К обычной проблеме нахождения и исправления ошибок в отдельно взятом

модуле добавляются проблемы ошибок во всем программном проекте. При объединении модулей могут возникнуть несоответствия, связанные с

неверной моделью общей задачи, неправильным определением подзадач или несогласованностью ресурсовыделения для каждого модуля. Эти проблемы возникают по вине системного архитектора и часто не могут быть замечены программистами. Исправление таких ошибок чрезвычайно дорогостояще, так как приходится отвергать готовые решения задач и переформулировать их, в результате чего теряется время и ресурсы, потраченные на создание полностью работоспособных модулей.

Один из способов решить данную проблему - после общей формулировки подзадач провести совещание с главными программистами всех групп для поиска возможных несоответствий.

Задания для раздела "Концепции разработки больших программных проектов(БПП)."

Задание 184. Определите состав руководства и бригады программистов для разработки векторного графического редактора. Определите задачи каждого члена бригады и руководства в разработке данного БПП.Задание 185. Выполните функции системного архитектора при разработке векторного графического редактора.

207

Page 208: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Событийная модель программного проекта.

2.5.3 Событийная модель программного проекта.

2.5.3.1 Понятие события при разработке больших программных проектов.

Основным способом реакции большого программного проекта на действия пользователя является получение и обработка событий.

Под событием понимается любой сигнал со внешнего устройства (клавиатура, мышь, коммуникационный порт, джойстик и т.д.) или от самой программы (сигнал о завершении работы программы, о требовании перерисовать некоторую область в результате ее изменения, о требовании сохранить результаты работы в файле и т.д.). В многозадачных системах события к программе могут приходить от других программ и операционной системы.

Для реакции программы на внешние и внутренние события разработан механизм их получения и обработки. Для хранения полученных, но еще необработанных событий используется так называемая очередь событий, представляющая собой область памяти, где хранятся необработанные события, организованная по принципу FIFO (first in, first out - первый вошел, первый вышел). Примером аппаратной реализации данного принципа служит очередь событий клавиатуры, в которую помещаются нажатия клавиш (о переполнении этой очереди свидетельствует характерный писк). Типичным программным примером является событийный блок объектно-ориентированной библиотеки Turbo Vision, которая полностью основана на положениях, описанных в следующих параграфах.

2.5.3.2 Реализация механизма получения и обработки событий в однозадачной среде.

Простейшая программа, реализующая механизм получения и обработки событий, содержит три основных процедуры и несколько дополнительных:

1. Процедура получения события, которая опрашивает состояние внешних устройств, кодирует полученные события и вызывает процедуру, помещающую их в конец очереди. Затем изымает событие из начала очереди и возвращает его в качестве результата. Таким образом, если очередь событий была пуста при обращении к процедуре, то внешнее событие передается прямо в программу, а очередь снова становится пустой. Наличие дополнительной процедуры перемещения события в очередь связано с возможностью ее использования в любом месте программы для создания внутренних событий.

2. Процедура обработки события. Ее параметром является некоторое событие, внешнее или внутреннее, которое требуется обработать. В зависимости от типа события процедура производит обращение к тем или иным блокам программы, которые содержат реакцию на соответствующее событие и в зависимости от текущего состояния программы совершают те

208

Page 209: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Реализация механизма получения и обработки событий в однозадачной среде.

или иные действия. Пример. При создании текстового редактора процедура обработки события передает нажатие клавиш процедуре обработки клавиш, которая уже проводит анализ нажатой клавиши и совершает требуемые действия для активного окна (ввод символа, перемещение курсора, удаление строки и т.д.). Если же активное окно отсутствует, что реально, например при работе с меню, то обработка клавиатурного события происходит совершенно другим образом (для меню - отрабатываются нажатия клавиш курсора, клавиша "Enter", "горячие" клавиши и т.д.). Аналогичным образом происходит обработка для событий других типов. Например, в случае получения внутреннего события, являющимся требованием о завершении работы, управление передается в процедуру, которая выполняет диалоговый запрос типа "Вы уверены?" или "Текст в окне 3 не сохранен, сохранить?" и в зависимости от ответа совершает те или иные действия.3. Основная процедура, совмещающая в себе получение и обработку

событий. Может состоять всего из нескольких строк:Procedure RUN; {Основная процедура} Var Event:Tevent; {Tevent - предопределенный тип записи, в котором хранится

информация о событии любого типа} Begin Repeat GetEvent(Event); {Получение события} HandleEvent(Event); {Обработка события} Until Quit; {Выход из процедуры, если получено сообщение о завершении работы.

Quit - переменная логического типа, первоначально имеющая значение false}

End;

Данная процедура запускается из основной программы после проведения инициализации всех переменных, установки режима экрана и т.д. После ее выполнения производится завершение работы, закрытие всех открытых файлов, установка первоначального режима экрана и т.д.

Т.о. основная программа может состоять всего из 5 строк:Begin Init; {процедура инициализации} Run; {процедура получения и обработки событий} Done; {процедура завершения работы}End.

2.5.3.3 Реализация механизма получения и обработки событий в многозадачной среде.

При разработки многозадачных операционных систем системные программисты изначально опиралась на концепцию получения и обработки событий, поэтому в многозадачной среде механизм получения и обработки событий обычно встроен в операционную систему. Таким образом программисту не нужно определять очередь и организовывать получение событий. Значение имеет только

209

Page 210: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Реализация механизма получения и обработки событий в многозадачной среде.

обработка получаемых и создание своих собственных событий.События в многозадачной среде могут приходить из гораздо большего набора

источников и количество их типов на несколько порядков выше, чем в однозадачной программе, разработанной одним или группой программистов.

Отличительной особенностью события в многозадачной среде является его конкретная направленность, то есть полученное событие всегда направляется в конкретное окно, к конкретному приложению и т.д. Таким образом, для прикладного программиста не существует просто клавиатурных событий, имеются события от клавиатуры для некоторого объекта. Аналогично не существует абстрактных мышиных событий, имеются события от манипулятора мышь для конкретной кнопки, элемента меню, окна и т.д.

В отличие от однозадачной среды, в многозадачной существует также несколько типов очередей событий. Среди них можно выделить одну глобальную и множество локальных очередей, связанных с конкретными приложениями. В глобальную поступают аппаратные события и события, предназначенные для передачи из одной программы в другую, в локальные - преобразованные события из глобальной (например - мышиное событие для какого-либо окна приложения поступает из глобальной очереди в локальную, меняя в процессе преобразования свои глобальные координаты на локальные - относительно левого верхнего угла соответствующего окна), и внутренние события программы.

При создании программы в многозадачной среде определяют главную процедуру обработки событий со специфичным названием (например в Windows - это MainWndProc), а также несколько дополнительных, связанных с различными параллельными процессами внутри одного приложения. Операционная система вызывает эти процедуры, передавая им события для обработки. Таким образом, задача программиста - реализовать реакцию приложения на различные типы событий.

Некоторые системы визуальной разработки программ (Delphi, C++ Builder, Visual Basic и др.) искусно скрывают механизмы передачи событий, позволяя программисту кодировать только соответствующие обработчики, в результате чего время разработки программы значительно сокращается.

2.5.3.4 Пример реализации получения и обработки событий в однозадачной среде.

1. Разработаем структуру для хранения одиночного событияconst{ События } evMouseUp = $0001; { Отжатие кнопки мыши } evMouseDown = $0002; { Нажатие кнопки мыши } evMouseMove = $0004; { Перемещение мыши } evKeyDown = $0010; { Нажатие клавиши } evCommand = $0100; { Внутренняя команда }{ Маски событий }

210

Page 211: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример реализации получения и обработки событий в однозадачной среде.

evNothing = $0000; evMouse = $0007; evKeyboard = $0010;{ Команды } cmQuit = 1;{ Маски клавиш мыши } mbLeft=1; mbRight=2;

type { тип записи для хранения событий } TEvent=Record case TypeEvent:word of evNothing:(); evKeyBoard:(Code:char; Ext: boolean; LShift,LAlt,LCtrl:boolean; RShift,RAlt,RCtrl:boolean); evMouse:(XY:TPoint; Buttons:byte); evCommand:( Command:integer; pInfo:pointer ); end;

Рассмотрим подробно тип TEvent. Поле TypeEvent определяет вид полученного события. Событие отсутствует,

если значение TypeEvent=evNothing. Такая ситуация возможна, если при обращении к процедуре получения события очередь событий пуста, или полученное из очереди событие предается последовательно нескольким объектам (процедурам, функциям и т.д.), причем обработавший событие объект устанавливает TypeEvent в evNothing для предотвращения дальнейшего распространения сообщения.

При нажатии клавиши поле TypeEvent устанавливается в evKeyDown, при этом заполняются поля Code (код нажатой клавиши), Ext (признак расширенного кода) и поля, соответствующие нажатым клавишам Ctrl, Alt, Shift.

При возникновении мышиного события поле typeEvent устанавливается в evMouseUp, evMouseDown или evMouseMove в зависимости от типа события. Поле XY устанавливается в координаты мыши, а поле Buttons – в состояние клавиш мыши.

При создании пользовательского события поле typeEvent устанавливается в evCommand, поля Command и pInfo – соответственно в значение пользовательского события и дополнительной информации, которая может быть указателем на некоторую структуру данных, объект или просто целочисленным значением, преобразованным в тип pointer.

2. Очередь событийconst MaxEvent=100;

{максимальное количество событий в очереди}var ChainEvent:array[1..MaxEvent] of TEvent;

{очередь событий в виде массива}

211

Page 212: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример реализации получения и обработки событий в однозадачной среде.

const CountEvent:integer=0; {текущее количество событий}

3. Процедуры добавления события в очередь и получения его оттуда.{процедура добавления события в очередь}procedure PutEvent(Event:Tevent); var i:integer; begin if CountEvent=MaxEvent then Exit; for i:=CountEvent Downto 1 do begin ChainEvent[i+1]:=ChainEvent[i]; end; ChainEvent[1]:=Event; inc(CountEvent); end;

{ переменные для хранения "старой" информации о состоянии мыши }const MouseX:integer=0; MouseY:integer=0; MouseLeftDown:boolean=false; MouseRightDown:boolean=false;{процедура получения события}procedure GetEvent(Var Event:Tevent); var c:char; k1,k2:byte; E:Tevent; Left, Right:boolean; begin FillChar(E,sizeof(e),0);{ проверяем на клавиатуру } k1:=mem[$40:$17]; k2:=mem[$40:$18]; with E do begin LShift:=(k1 and 2)<>0; RShift:=(k1 and 1)<>0; if (k1 and 4)<>0 then if (k2 and 1)<>0 then LCtrl:=true else RCtrl:=true; if (k1 and 8)<>0 then if (k2 and 2)<>0 then LAlt:=true else RAlt:=true; if LShift or LAlt or LCtrl or RShift or RAlt or RCtrl or keypressed then begin TypeEvent:=evKeyDown; ext:=true; if keypressed then begin Ext:=false; Code:=readkey; if Code=#0 then begin Ext:=true; Code:=readkey; end; end; PutEvent(e); end; end;{ проверяем на мышь } fillchar(e,sizeof(e),0); with E do begin GetMouseState(XY.x,XY.y,left,right); if (XY.x<>MouseX) or (XY.y<>MouseY) then begin TypeEvent:=evMouseMove; PutEvent(e); end; if Left<>MouseLeftDown then begin TypeEvent:=evMouseUp shl byte(left); buttons:=mbLeft; PutEvent(e);

212

Page 213: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример реализации получения и обработки событий в однозадачной среде.

end; if Right<>MouseRightDown then begin TypeEvent:=evMouseUp shl byte(right); buttons:=mbRight; PutEvent(e); end; MouseX:=XY.X;MouseY:=XY.Y; MouseLeftDown:=left; MouseRightDown:=right; end;{теперь возвращаем события из конца очереди событий} if Countevent=0 then exit; Event:=ChainEvent[CountEvent]; Dec(CountEvent); end;При получении события мыши используется процедура GetMouseState.

Данная процедура возвращает состояние клавиш и местоположение мыши, и находится в модуле Mouse (см. фазу 0 программного проекта)

4. Обработка события (каркас)Процедура, показанная ниже, может использоваться для обработки всех

событий программы. Она вызывается из процедуры Run (см. параграф 2.5.3.2)procedure HandleEvent(Var Event:Tevent); begin case Event do begin if TypeEvent or evMouse <>0 then begin … {некоторые действия, единые для любых событий мыши, перед обработкой этих

событий } case TypeEvent of evMouseUp: begin … {обработка отжатия кнопки мыши} TypeEvent:=0; end; evMouseDown: begin … {обработка нажатия кнопки мыши} TypeEvent:=0; end; evMouseMove: begin … {обработка перемещения мыши} TypeEvent:=0; end;… {некоторые действия, единые для любых событий мыши, после обработкой этих

событий } end; Case typeEvent of evKeyDown: begin … {обработка нажатия клавиш} TypeEvent:=0; end; evCommand: begin … {обработка команд пользователя}

213

Page 214: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Пример реализации получения и обработки событий в однозадачной среде.

TypeEvent:=0; end; end; end;

2.5.3.5 Программный проект (10)Создадим модуль Events, в который поместим наиболее общие типы данных, переменные,

константы, процедуры и функции, которые будут использованы при реализации программного проекта. Это касается:

1) Всех констант и типов данных, необходимых для хранения событий (TEvent, константы событий, команд и масок) – в интерфейсную секцию.

2) Переменных и констант очереди событий (MaxEvent, CountEvent, ChainEvent) – в секцию реализации.

3) Процедуры добавления события в очередь (PutEvent) – в интерфейсную секцию4) Процедуры получения события из очереди (GetEvent) – в интерфейсную секцию, и всех

глобальных типированных констант для этой процедуры (MouseX, MouseY, MouseLeftDown, MouseRightDown) – в секцию реализации.

Наш графический редактор основан на объектно-ориентированной модели, поэтому в дальнейшем мы создадим специализированный объект, в который будут включены остальные процедуры событийной модели.

Откомпилируйте полученный модуль, убедитесь в отсутствии синтаксических ошибок.

214

Page 215: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (10)

2.5.4 Объектно-событийная модель программы.

2.5.4.1 Объектная модель программы Объектной моделью программы называется такая организация

программного кода, когда (в идеальном случае) имеется только одна глобальная переменная-объект, в результате вызова методов которой выполняется программа. Все данные, в том числе и объекты, находятся внутри глобального. При этом практически не существует никаких глобальных процедур и функций, кроме тех, которые выполняют некоторые общие служебные действия, несвязанные с данными внутри объектов.

Наборы объектов внутри главного организованы в виде иерархического дерева, напоминающего иерархию классов. Каждый объект может содержать в себе набор таких же объектов или объектов, порожденных от данного класса. Объект, содержащий в себе другие объекты, является хозяином по отношении к ним, а они – подчиненными по отношению к хозяину. Одним из основных свойств хозяина является то, что он обязан уничтожить все подчиненные объекты при своем собственном уничтожении (внутри дестрактора).

Пример иерархии объектов:Первичный класс – ОБЪЕКТ-ДЕРЕВО, порожденные – ОКНО, КНОПКА и

ПРИЛОЖЕНИЕ.В этом случае иерархия объектов в программе может выглядеть следующим

образом:

ПРИЛОЖЕНИЕ

ОКНО

ОКНО

ОКНО

КНОПКА

КНОПКА

КНОПКА КНОПКА

ОБЪЕКТ-ДЕРЕВО

В данном случае объект-приложение содержит в себе 6 других объектов, один из которых содержит два объекта.

215

Page 216: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Объединение объектной и событийной модели программ.

2.5.4.2 Объединение объектной и событийной модели программ.

Один из наиболее эффективных путей использования объектной модели – это интегрирование ее с событийной моделью. Получающаяся в результате объектно-событийная модель обладает следующими свойствами:

1. Каждый объект иерархии обладает своим собственным виртуальным обработчиком событий.

2. Любой обработчик событий обязан не только сам обрабатывать события, но и предоставлять возможность подчиненным объектам делать то же самое.

3. Каждый объект может быть модальным, то есть уметь монопольно (совместно со своими подчиненными) получать и обрабатывать все возникающие в системе события.

4. Среди подчиненных объектов хозяина один может являться активным, то есть таким, к которому прежде всего приходят события

5. Каждый из объектов иерархии может быть запрещенным, то есть таким, к которому не приходят события.

6. Для визуальной среды каждый объект иерархии имеет средства визуализации.

Например:Создадим 2 класса – Событийный класс (TEventObject) и Приложение (TApp). Для

построения иерархии объектов событийный класс порожден от TCollection.{***************-TEventObject-****************} { событийный класс } PEventObject=^TEventObject; TEventObject=object(TCollection) constructor Init(_Owner:PEventObject); destructor Done;virtual; procedure GetEvent(Var Event:Tevent);virtual; procedure PutEvent(Event:Tevent);virtual; { получает и посылает событие, используя процедуры модуля Events } procedure HandleEvent(Var Event:Tevent);virtual; {обработка событий} function HandleModal:integer;virtual; {модальная обработка событий} procedure SetOwner(_Owner:PEventObject); procedure SetActive; procedure DeActivate; procedure Disable; procedure Enable; public ModalResult:integer; {результат модальной обработки объекта} Owner,Active:PEventObject; {хозяин и активный объект иерархии} Disabled:boolean; {запрещенность объекта} end;

TApp=object(TEventObject) constructor Init;

216

Page 217: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Объединение объектной и событийной модели программ.

procedure Run; {эквивалент основной программы в событийной модели} destructor Done;virtual; procedure EndApp; {завершает модальное состояние объекта-приложения,

устанавливая ModalResult в 1} procedure HandleEvent(Var Event:Tevent);virtual; {обрабатывает несколько дополнительных команд } end;

{ ------- Реализация --------}

constructor TApp.Init; begin inherited init(nil); end;

procedure TApp.Run; begin HandleModal; end;

destructor TApp.Done; begin inherited done; end;

procedure TApp.EndApp; begin ModalResult:=1; end;

procedure TApp.HandleEvent(Var Event:Tevent); begin inherited HandleEvent(event); with Event do begin case typeEvent of evKeyDown:if code=#27 then EndApp; evCommand:if command=cmQuit then EndApp; end; end; end;

{-----------------------------------------------}

constructor TEventObject.Init(_Owner:PEventObject); begin inherited Init(10,10); SetOwner(_Owner); end;

destructor TEventObject.Done; begin inherited done; end;

procedure TEventObject.PutEvent(Event:Tevent); begin events.putevent(event) end;

procedure TEventObject.GetEvent(var Event:Tevent); begin events.Getevent(event) end;

function TEventObject.HandleModal:integer; var E:TEvent; begin

217

Page 218: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Объединение объектной и событийной модели программ.

ModalResult:=0; repeat GetEvent(e); HandleEvent(e); until ModalResult<>0; HandleModal:=ModalResult; end;

procedure TEventObject.HandleEvent(Var Event:Tevent); var i:integer; P:PEventObject; begin if active<>nil then active^.HandleEvent(event); for i:=count-1 downto 0 do begin if Event.TypeEvent=evNothing then exit; p:=PEventObject(at(i)); if (p<>active) and (not p^.disabled) then p^.HandleEvent(event); end; end;

procedure TEventObject.SetOwner(_Owner:PEventObject); begin if owner<>nil then owner^.Delete(@self); owner:=_owner; if owner<>nil then owner^.Insert(@self); end;

procedure TEventObject.SetActive; begin if owner<>nil then owner^.Active:=@self; end;

procedure TEventObject.DeActivate; begin if owner<>nil then owner^.Active:=nil; end;

procedure TEventObject.Disable; begin disabled:=true; end;

procedure TEventObject.Enable; begin disabled:=false; end;

Для разработки программы в рамках объектно-событийной модели определяют набор необходимых классов, порожденных от событийного класса, а также класс-оболочку, порожденный от класса–приложения, перекрывая в случае необходимости требуемые виртуальные методы для организации интерфейса, реакций на события и т.д.

2.5.4.3 Программный проект (11)Дополним классами TEventObject и TApp модуль Events и начнем создание интерактивной среды

графического редактора.Применяя к разрабатываемому графическому редактору объектно-событийную модель, можно

определить классы

218

Page 219: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

Визуальный класс (TView=object(TEventObject)),Кнопка (TButton= object(TView)):Зависимая кнопка (TCheckButton= object(TButton))Прямоугольник выбора цвета (TColorBar= object(TView))Холст (TCanvas= object(TView)),Приложение (TApplication=object(TApp)), со следующими характеристиками

Визуальный классВизуальный класс определяет абстрактный метод Show, используемый потомками для

визуализации своего содержимого, а также обработку команды cmShow. Визуальный класс рассчитывает, что все подчиненные ему объекты также являются визуальными, поэтому (при обработке cmShow) для каждого из них вызывается метод Show. Визуальный класс имеет координаты в виде прямоугольника, может устанавливать область вывода в эти координаты.

Кнопка:Кнопки используются для передачи команд другим объектам приложения, формируя эти

команды из событий мыши и нажатия клавиш. При инициализации экземпляра кнопки ей передаются координаты прямоугольника, строка, обозначающая надпись на кнопке, код клавиши, при нажатии которую происходит срабатывание кнопки, а также команда, которая должна возникать при срабатывании кнопки. Анализируя поступающие к ней события, кнопка в требуемый момент посылает свою команду в очередь событий.

Зависимая кнопка:Имеет следующие отличия от обычной кнопки:При нажатии посылает команду в очередь событий, причем остается нажатой. Кнопки

данного типа могут группироваться. В этом случае нажатие на одну из кнопок группы вызывает отжатие уже нажатой в данной группе. При инициализации ей дополнительно к стандартным для кнопки параметрам передается номер группы, в которую она входит.

Прямоугольник выбора цветаПрямоугольник выбора цвета используется для интерактивного выбора цвета в

графическом редакторе. Представляет собой прямоугольник с набором из 16 цветов, один из которых всегда выбран (отмечен). Нажатие на другой цвет выбирает его.

Холст:Холст используется для хранения и визуализации коллекции графических объектов,

обрабатывает события мыши и команды переключения режимов, направленные от кнопок или другого источника. При инициализации ему передаются координаты рабочего прямоугольника, в котором происходит визуализация коллекции графических объектов. Коллекция графических примитивов хранится отдельным полем внутри холста, не входя в иерархию объектов программы.

Приложение:Приложение реализует инициализацию и завершение графики (в методах INIT, DOWN), а

также подготовку рабочего стола (в методе INIT), которая заключается во вставке туда одного холста, требуемого набора кнопок и прямоугольника для выбора цвета (вставка производится в сам объект Приложение). Дополнительно, приложение дублирует возможности Визуального класса.

Реализацию холста и приложения мы проведем в фазе 12 программного проекта, так как

219

Page 220: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

концепция режима, активно используемая в методах холста, будет подробно рассмотрена только в следующем параграфе, а в конструкторе приложения кнопкам назначаются команды, обрабатываемые холстом.

Создадим новый модуль GRED.PAS, где разместим собственно тело редактора, то есть все объекты, определенные в текущей фазе, и все сопутствующие данные, процедуры, функции и т.д.

Unit GRED;Interfaceuses Graph,objects,crt,mouse,grprim,events;…{ определим команду, используемую зависимой кнопкой при своем собственном нажатии

для "отжатия" уже нажатой кнопки в группе }const cmUnCheck=333;

type PView=^TView; PButton= ^TButton; PCheckButton= ^TCheckButton; PColorBar= ^TColorBar;

{ -- TView -- } { Визуально-событийный абстрактный класс } TView=object(TEventObject) Rect:TRect; { прямоугольник вывода } constructor Init(_Owner:PEventObject; x1,y1,x2,y2:integer); procedure Show;virtual; { абстрактный метод } procedure HandleEvent(Var Event:Tevent);virtual; { обрабатывает команду cmShow} procedure SetView; { устанавливает окно вывода } procedure SetStandartView;{ устанавливает окно вывода на весь экран} procedure ResetView; { устанавливает окно вывода, существовавшее до вызова

SetView и SetStandartView} private oldView:ViewPortType; {поле для хранения "старого" окна вывода} end;

{ --TButton-- } { Класс "Кнопка". При нажатии посылает команду в очередь событий } TButton= object(TView) Caption:string[20]; { надпись на кнопке } Code:Char; { код клавиши ... } Ext:boolean; {... и признак расширенного кода, при нажатии на которую

срабатывает кнопка } Command:integer; {команда. которая посылается в очередь событий} constructor Init(_Owner:PEventObject; x1,y1,x2,y2:integer;s:string; c:char;

_ext:boolean;cm:integer); procedure Show;virtual; procedure HandleEvent(Var Event:Tevent);virtual; procedure ButtonDown;virtual; { Вызывается при нажатии на кнопку. В классе TButton анимирует нажатие }

220

Page 221: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

end;

{--TCheckButton--} { Класс "Зависимая кнопка". При нажатии посылает команду в очередь событий, причем остается нажатой. Кнопки данного типа могут группироваться. В этом случае нажатие на одну из кнопок группы вызывает отжатие уже нажатой в данной группе. Активно используется для переключения в режимы рисования различных примитивов }

TCheckButton= object(TButton) Checked:boolean; { признак нажатия-отжатия } Group:integer; { номер группы } constructor Init(_Owner:PEventObject; x1,y1,x2,y2:integer;s:string; c:char;

_ext:boolean;cm:integer; _group:integer); procedure Show;virtual; procedure ButtonDown;virtual; { визуализирует нажатую кнопку и посылает в очередь событий команду cmUnCheck } procedure HandleEvent(Var Event:Tevent);virtual; { обрабатывает команду cmUnCheck } end;

{--TColorBar--} { "Прямоугольник выбора цвета". Используется для интерактивного выбора цвета } TColorBar= object(TView) Color:word; { выбранный цвет } constructor Init(_Owner:PEventObject; x1,y1,x2,y2:integer); procedure Show;virtual; procedure ShowCell(R:TRect; _Color:word); { показывает одну ячейку в переданном прямоугольнике и переданным цветом} procedure SetBarColor(_Color:word); { рисует маркер на выбранном цвете } function GetCell(x,y:integer):word; { по координатам возвращает номер цвета } procedure GetCellRect(_Color:word; var R:TRect); { по цвету возвращает координаты цветового прямоугольника } procedure HandleEvent(Var Event:Tevent);virtual; end;…

implementationuses inter;

{ ------------ TView ------------- } procedure Tview.Show; begin abstract; end;{ абстрактный метод для визуализации объекта, перекрывается во всех потомках }

procedure TView.HandleEvent; var i:integer; begin if (Event.TypeEvent=evCommand) and (Event.Command=cmShow) then begin{Обработка команды cmShow}

221

Page 222: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

Show; For i:=0 to count-1 do PView(at(i))^.Show;{показ самого объекта, затем – показ всех подчиненных} Event.TypeEvent:=0;exit; end; inherited HandleEvent(Event); end;

constructor TView.Init(_Owner:PEventObject; x1,y1,x2,y2:integer); begin inherited init(_Owner); Rect.assign(x1,y1,x2,y2); end;

procedure TView.SetView; begin GetViewSettings(oldView); with rect do SetViewPort(a.x,a.y,b.x,b.y,true); end;

procedure TView.SetStandartView; begin GetViewSettings(oldView); SetViewPort(0,0,GetMaxX,GetMaxY,true); end;

procedure TView.ResetView; begin with oldView do SetViewPort(x1,y1,x2,y2,true); end;

{ ------------ TButton ------------- }constructor TButton.Init(_Owner:PEventObject;x1,y1,x2,y2:integer;

s:string;c:char;_ext:boolean;cm:integer); begin inherited init(_owner,x1,y1,x2,y2); Caption:=s; Code:=C; Ext:=_ext; Command:=cm; end;

procedure TButton.ButtonDown; begin with rect do begin hidemouse; SetStandartview; setcolor(15); setWriteMode(XorPut); SetLineStyle(SolidLn,0,1); rectangle(a.x,a.y,b.x,b.y); delay(100); rectangle(a.x,a.y,b.x,b.y); setWriteMode(NormalPut); ReSetview; showmouse; end; end;

procedure TButton.Show; var dx,dy,x,y:integer; begin hidemouse; SetStandartView; with rect do begin Showbar(a.x,a.y,b.x,b.y,7,true);

222

Page 223: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

if not disabled then SetColor(0) else setcolor(8); SetTextstyle(2,0,0); dx:=TextWidth(caption); dy:=TextHeight(caption); x:=a.x+(b.x-a.x-dx)div 2; y:=a.y+(b.y-a.y-dy)div 2; OutTextXY(x,y,Caption); end; ResetView; showmouse; end;

procedure TButton.HandleEvent(Var Event:Tevent); var E:TEvent; begin if ((event.typeEvent=evKeyBoard) and(event.code=code) and(event.ext=ext)) or ((event.typeEvent=evMouseDown) and rect.contains(event.xy)) then begin e.TypeEvent:=evCommand; e.Command:=Command; PutEvent(e); Event.TypeEvent:=0; ButtonDown; end; inherited HandleEvent(Event); end;

{ ------------ TCheckButton ------------- }constructor TCheckButton.Init(_Owner:PEventObject; x1,y1,x2,y2:integer; s:string;

c:char;_ext:boolean;cm:integer; _group:integer); begin inherited init(_owner,x1,y1,x2,y2,s,c,_ext,cm); checked:=false; group:=_group; end;

procedure TCheckButton.ButtonDown; var E:TEvent; begin checked:=true; show; e.TypeEvent:=evCommand; e.Command:=cmUnCheck; e.pinfo:=@self; PutEvent(e); end;

procedure TCheckButton.Show; var dx,dy,x,y:integer; begin hidemouse; SetStandartView; with rect do begin showbar(a.x,a.y,b.x,b.y,7,not checked); if not disabled then SetColor(0) else setcolor(8); SetTextstyle(2,0,0); dx:=TextWidth(caption); dy:=TextHeight(caption);

223

Page 224: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

x:=a.x+(b.x-a.x-dx)div 2; y:=a.y+(b.y-a.y-dy)div 2; OutTextXY(x,y,Caption); end; ResetView; showmouse; end;

procedure TCheckButton.HandleEvent(Var Event:Tevent); begin if (event.typeEvent=evCommand) and(event.Command=cmUnCheck) and(event.pinfo<>@self) and(pCheckButton(event.pinfo)^.group=group) and(checked) then begin checked:=false; show; end; inherited HandleEvent(Event); end;

{ ------------ TColorBar ------------- } constructor TColorBar.Init(_Owner:PEventObject; x1,y1,x2,y2:integer); begin inherited init(_Owner,x1,y1,x2,y2); SetBarColor(15); end;

function TColorBar.GetCell(x,y:integer):word; var dx,dy:integer; begin with rect do begin x:=x-a.x; y:=y-a.y; dx:=(b.x-a.x)div 8; dy:=(b.y-a.y)div 2; GetCell:=(x div dx)+8*(y div dy); end; end;

procedure TColorBar.GetCellRect(_Color:word; var R:TRect); var dx,dy,x,y,i:integer; begin with rect do begin dx:=(b.x-a.x)div 8; dy:=(b.y-a.y)div 2; x:=a.x+dx*(_color mod 8); y:=a.y+dy*(_color div 8); end; R.assign(x,y,x+dx-1,y+dy-1); end;

procedure TColorBar.ShowCell(R:TRect; _color:word); begin with r do Showbar(a.x,a.y,b.x,b.y,_color,false); end;

procedure TColorBar.Show; var i:integer;R:TRect; begin hidemouse; SetStandartView; with rect do for i:=0 to 15 do begin GetCellRect(i,R); ShowCell(R,i) end; SetBarColor(Color); ResetView; showmouse;

224

Page 225: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (11)

end;

procedure TColorBar.SetBarColor(_Color:word); var R:trect; oldColor:word; begin hidemouse; SetStandartView; GetCellRect(Color,R); oldColor:=Color; Color:=_Color; ShowCell(R,OldColor); GetCellRect(Color,R); if Color in [3,7,10..15] then SetColor(0) else Setcolor(15); with r do Circle(a.x+(b.x-a.x)div 2,a.y+(b.y-a.y)div 2,2); ResetView; showmouse; end;

procedure TColorBar.HandleEvent(Var Event:Tevent); begin inherited HandleEvent(event); if (event.typeEvent=evMouseDown) and Rect.contains(event.xy) then begin SetBarColor(GetCell(event.xy.x,event.xy.y)); event.typeevent:=0; end; end;

Рассмотрим некоторые моменты в реализации методов классов.1. Стандартный способ прорисовки любого класса, порожденного от TView состоит в

следующих действиях: hidemouse; SetStandartview;… { прорисовка объекта в абсолютных координатах }ResetView; showmouse;

или:hidemouse; SetView;… { прорисовка объекта в относительных координатах }ResetView; showmouse;

2. При нажатии на зависимую кнопку в очередь событий посылается не одно, а два события: одно – в унаследованным от кнопки методе HandleEvent, второе – в перекрытом методе ButtonDown. В последнем случае посылается команда cmUnCheck, которую обрабатывают все зависимые кнопки в группе, кроме пославшей команду.

3. В большом программном проекте любой класс должен поддерживать универсальность отображения, реакции на события и т.д. Поэтому вывод текста в TButton и TCheckButton и цветов в TColorBar универсален. И текст и цвета всегда будут отображаться правильно вне зависимости от размеров объектов.

2.5.4.4 Режим работы объекта в объектно-событийной моделиПри разработке БПП большое значение имеет понятие режима. Под режимом (MODE) будем понимать состояние объекта (программы), в

котором он обладает уникальной реакцией на совокупность событий.Рассмотрим несколько примеров из графического редактора:Объект зависимая кнопка может находится в двух состояниях – нажатом и отжатом. В

зависимости от текущего состояния (режима) изменяется реакция на события (если кнопка нажата,

225

Page 226: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Режим работы объекта в объектно-событийной модели

то щелчок мыши на ней не вызовет ответной реакции)Объект холст может находится в нескольких состояниях – удаления, рисования,

перемещения примитива и т.д. Реакция холста на события мыши и клавиатуры, таким образом, напрямую зависит от текущего режима.

Программирование режимов объекта (программы) обладает некоторыми особенностями:

1. Всегда существует специальное средство для определения текущего режима – переменная(-ые), поле(-я) объекта, функция, метод объект, сам(и) объект(ы) и т.д., которое мы будем называть идентификатором режима (ИДР)

2. Установка режима сопровождается некоторым программным кодомМало установить значение поля, отвечающие за "нажатость" кнопки, в true, требуется еще и перерисовать кнопку в "нажатом" виде.

3. Выход из режима (вне зависимости от нового значения ИДР) также сопровождается программным кодомВ графическом редакторе переход из режима рисования фигуры в любой другой режим (то есть выход из режима рисования), должен сопровождаться действиями, которые либо отменяют рисование, либо помещают рисуемую в настоящий момент фигуру в графическую коллекцию (в зависимости от соглашения), а также перерисовывают холст. Эти действия сопровождают и неразрывно связаны именно с выходом из режима рисования фигур, а не с переходом в какой-либо другой режим.

4. Для удобства программирования ИДР может быть составным. В результате программа или объект может иметь несколько режимов на одном (нулевом) уровне, причем любой из них может иметь один или несколько подрежимов (SUBMODE) первого уровня, определяемых своими собственными ИДР, каждый из которых может иметь подрежимы второго уровня и т.д.В графическом редакторе режим рисования имеет два подрежима – статический режим (до начала рисования) и динамический (в процессе рисования), причем второй имеет еще один подрежим – для обозначения рисуемого примитива.

2.5.4.5 Программный проект (12)Дополним модуль GRED.PAS реализацией холста (TCanvas) и приложения (TApp).

Определим константы режимов холста графического редактора:

Unit GRED;Interface…{РЕЖИМЫ ДЛЯ TCanvas} modeStandart=0; modeRis=1; {рисование} {ПОДРЕЖИМ1} {подрежим 1 соответствует подготовке и самому процессу рисования} smodeRisBegin=0; {подготовка рисования} smodeRis=1; {процесс рисования} {ПОДРЕЖИМ2}

226

Page 227: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

{подрежим 2 соответствует типу рисуемого примитива} modeDel=2; {удаление примитива} {подрежимов нет} modeMove=3; {перемещение примитива} {ПОДРЕЖИМ1} {подрежим 1 соответствует подготовке и самому процессу перемещения} smodeMoveBegin=0; {подготовка перемещения} smodeMove=1; {процесс перемещения}

{ Определим команды, которые будут обрабатывать холст. Для простоты все команды, кроме команды выхода, обрабатываются холстом}

{ одиночные команды }

cmRead=2; cmSave=3; cmClear=4; cmShow=5; cmSaveToPas=9;

{команды переключения в режимы} cmToLine=10001; cmToCircle=10002; cmToRect=10003; cmToEllipse=10004; cmToDel=10011; cmToMove=10012;

type{--TCanvas--}

{ "Холст". Используется для интерактивного построения и прорисовки набора графических примитивов }

PCanvas= ^TCanvas; TCanvas= object(TView) PG:PGrCollection; { коллекция графических примитивов } Mode:integer; { текущий режим } SubMode,SubMode2:integer; { подрежимы } CurrObj:PGrObject; { текущий рисуемый (перемещаемый и т.д.) примитив } constructor Init(_Owner:PEventObject;x1,y1,x2,y2:integer); destructor Done;virtual; procedure Show;virtual; procedure Clear; { очищает холст, уничтожая коллекцию примитивов } procedure HandleDown(xy:tpoint; buttons:byte); procedure HandleMove(xy:tpoint; buttons:byte); procedure HandleUp(xy:tpoint; buttons:byte); { процедуры HandleDown, HandleMove и HandleUp вызываются из HandleEvent при

соответствующих событиях мыши } procedure CancelDynamicMode; { отменяет динамический подрежим (smodeRis,smodeMove), если он установлен, переводя

его в соответствующий подготовительный подрежим (smodeRisBegin,smodeMoveBegin).

227

Page 228: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

Используется обычно перед установкой другого режима или подрежима (например, до завершения рисования линии пришла команда о начале рисования окружности) }

procedure BeginRis(xy:tpoint); procedure EndRis(xy:tpoint); procedure MoveRis(xy:tpoint); { процедуры BeginRis, EndRis и MoveRis вызываются из HandleDown и HandleMove в

начале, завершении и протяжении рисования примитива. Используются в целях установки специфичных для каждого графического примитива параметров }

procedure HandleEvent(Var Event:Tevent);virtual; { в дополнении к обработке команд производит перевод координат мыши из абсолютных

в относительные } procedure LoadFromFile; procedure SaveToFile; procedure SaveToPas; { процедуры чтения и сохранения коллекции примитивов в файле, а также сохранения в

паскалевском формате} private OldPoint:TPoint; end;

{--TApplication--} { "Приложение" } TApplication=object(TApp) constructor Init; { создает и располагает на экране набор визуальных объектов } procedure ShowAll; { так как TApplication порожден не от TView, требуется метод ShowAll для показа

содержимого приложения } destructor Done;virtual; end;

{--Переменные--} var ColorBar:PColorBar; { ссылка на прямоугольник выбор цвета. Используется для доступа к текущему

установленному цвету примитивов }…

implementationuses inter;…

{ ------------ TCanvas ------------- } procedure TCanvas.CancelDynamicMode; begin if (mode=moderis)and(submode=smoderis) then begin submode:=smodeRisBegin; pg^.Delete(currobj); hidemouse; SetView; show; ReSetView; showmouse; CurrObj:=nil; end else

228

Page 229: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

if (mode=modeMove)and(submode=smodeMove) then begin submode:=smodeRisBegin; hidemouse; SetView; currObj^.enable; show; ReSetView; showmouse; CurrObj:=nil; end; end;

procedure TCanvas.BeginRis(xy:tpoint); begin case submode2 of typeline: CurrObj:=new(pGrline, init(xy.x,xy.y,xy.x,xy.y,0,1,1,ColorBar^.Color)); typeRect: CurrObj:=new(pGrRect, init(xy.x,xy.y,xy.x,xy.y,0,1,1,ColorBar^.Color)); typeCircle: CurrObj:=new(pGrCircle,init(xy.x,xy.y,0,0,1,1,ColorBar^.Color)); typeEllipse: ; end; end;

procedure TCanvas.EndRis(xy:tpoint); begin case submode2 of typeline,typerect: with pgrline(CurrObj)^.CoordLine do begin b.x:=xy.x; b.y:=xy.y; if submode2=typerect then begin normalizedRect(pgrRect(CurrObj)^.CoordLine); end; end; typeCircle: with pgrCircle(CurrObj)^ do begin with coordCircle do radius:=round(sqrt(sqr(int(x-xy.x))+sqr(int(xy.y-y)))); end; typeEllipse: ; end; end;

procedure TCanvas.MoveRis(xy:tpoint); begin case submode2 of typeline,typeRect: with pgrline(CurrObj)^.CoordLine do begin b.x:=xy.x; b.y:=xy.y; end; typeCircle:with pgrCircle(CurrObj)^ do begin with coordCircle do radius:=round(sqrt(sqr(int(x-xy.x))+sqr(int(y-xy.y)))); end; typeEllipse: ; end; end;

procedure TCanvas.HandleDown(xy:tpoint; buttons:byte); begin case mode of modeRis: begin

229

Page 230: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

case submode of smodeRisBegin: begin BeginRis(xy); pg^.Insert(CurrObj); hidemouse; SetView; CurrObj^.show; ResetView; showmouse; submode:=smodeRis; end; smodeRis: begin if buttons=mbRight then begin CancelDynamicMode; exit; end; EndRis(xy); submode:=smodeRisBegin; hidemouse; SetView; show; ReSetView; showmouse; CurrObj:=nil; end; end; end; modeDel:begin CurrObj:=pg^.ObjectOnPoint(XY); if CurrObj<>nil then begin pg^.Delete(CurrObj); show; end; end; modeMove:begin case submode of smodeMoveBegin: begin CurrObj:=pg^.ObjectOnPoint(XY); if CurrObj<>nil then begin hidemouse; SetView; submode:=sModeMove; OldPoint:=XY; CurrObj^.disable; Show; CurrObj^.XorShow; ResetView; showmouse; end; end; smodeMove: begin if buttons=mbRight then begin CancelDynamicMode; exit; end; submode:=smodeRisBegin; hidemouse; SetView; currObj^.enable; show; ReSetView; showmouse; CurrObj:=nil; end; end; end; end; end;

procedure TCanvas.HandleMove(xy:tpoint; buttons:byte); var dx,dy:integer; begin case mode of modeRis: begin if submode=smodeRis then begin hidemouse; SetView; CurrObj^.XorShow; MoveRis(xy);

230

Page 231: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

CurrObj^.XorShow; ResetView; showmouse; end; end; modeMove:begin if submode=smodeMove then begin hidemouse; SetView; CurrObj^.XorShow; dx:=xy.x-oldpoint.x; dy:=xy.y-oldpoint.y; CurrObj^.Move(dx,dy); OldPoint:=xy; CurrObj^.XorShow; ResetView; showmouse; end; end; end; end;

procedure TCanvas.HandleUp(xy:tpoint; buttons:byte); begin { зарезервировано } end;

constructor TCanvas.Init(_Owner:PEventObject; x1,y1,x2,y2:integer); begin inherited init(_owner,x1,y1,x2,y2); mode:=modeStandart; pg:=new(pGrCollection,Init(100,10)); end;

destructor TCanvas.Done; begin dispose(pg,done); inherited done; end;

procedure TCanvas.Clear; begin pg^.freeall; show; end;

procedure TCanvas.Show; var V:ViewPortType; begin hidemouse; setView; setfillstyle(solidfill,0); with rect do bar(0,0,b.x-a.x,b.y-a.y); pg^.show; ResetView; showmouse; end;

procedure TCanvas.HandleEvent(Var Event:Tevent); var s:string; begin inherited HandleEvent(event); if event.typeEvent and evMouse <> 0 then begin if Rect.contains(event.xy) then begin dec(event.xy.x,rect.a.x); dec(event.xy.y,rect.a.y); with event do begin case event.TypeEvent of evMouseDown: HandleDown(xy, buttons);{обработка нажатий} evMouseMove: HandleMove(xy, buttons);{перемещений}

231

Page 232: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

evMouseUp: HandleUp(xy, buttons); {отжатий} end; Event.TypeEvent:=0; end; exit; end; end; if event.TypeEvent=evCommand then begin case Event.Command of cmToLine:begin CancelDynamicMode; Mode:=ModeRis; SubMode:=sModeRisBegin; SubMode2:=typeLine; end; cmToRect:begin CancelDynamicMode; Mode:=ModeRis; SubMode:=sModeRisBegin; SubMode2:=typeRect; end; cmToCircle:begin CancelDynamicMode; Mode:=ModeRis; SubMode:=sModeRisBegin; SubMode2:=typeCircle; end; cmToDel:begin CancelDynamicMode; Mode:=ModeDel; end; cmToMove:begin CancelDynamicMode; Mode:=ModeMove; end; cmRead:begin CancelDynamicMode; LoadFromFile; end; cmSave:begin CancelDynamicMode; SaveToFile; end; cmSaveToPas:begin CancelDynamicMode; SaveToPas; end; cmClear:begin CancelDynamicMode; Clear; end else exit; end;

232

Page 233: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

end; end;

procedure TCanvas.LoadFromFile; var s:string; stm:tbufstream; begin s:='noname.stm'; if inputstring(12,'Загрузка файла',s) then begin if not exists(s) then begin messagebox('Такого файла нет!'); exit; end; dispose(pg,done); stm.init(s,stopenread,1024); pg:=pgrcollection(stm.Get); stm.done; show; end; end;

procedure TCanvas.SaveToFile; var s:string; stm:tbufstream; begin s:='noname.stm'; if inputstring(12,'Сохранение файла',s) then begin stm.init(s,stCreate,1024); stm.Put(pg); stm.done; end; end;

procedure TCanvas.SaveToPas; var s,n:string; begin s:='include.inc'; n:='Paint'; if inputstring(12,'Сохранение в тексте',s) and inputstring(24,'Введите имя процедуры',n) then pg^.saveAsPas(s,n); end;

{ ------------ TApplication ------------- } constructor TApplication.Init; var obj:pView; dr,dm,gError:Integer; x,y,dx,dy:integer; begin inherited Init; dr := vga; dm := vgaHi; InitGraph(dr,dm,' '); gError := GraphResult; if gError <> grOk then begin Writeln('Graphics error:', GraphErrorMsg(gError)); halt(1); end; CHKAndReset; obj:=new(PCanvas,Init(@Self,20,20,getmaxx-20,400)); x:=20;y:=410; dx:=65; dy:=17; obj:=new(PCheckButton,Init(@Self,x,y,x+dx,y+dy,'Линия',#0,false,cmtoline,0)); inc(x,0); inc(y,dy+2); obj:=new(PCheckButton,Init(@Self,x,y,x+dx,y+dy,'Прям.',#0,false,cmtorect,0));

233

Page 234: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

inc(x,dx+2); inc(y,-dy-2); obj:=new(PCheckButton,Init(@Self,x,y,x+dx,y+dy,'Окр.',#0,false,cmtocircle,0)); inc(x,0); inc(y,dy+2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'Эллипс',#0,false,cmtoellipse,0)); obj^.disable; inc(x,dx+2); inc(y,-dy-2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'Ломаная',#0,false,cmtocircle,0)); obj^.disable; inc(x,0); inc(y,dy+2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'З.Прям.',#0,false,cmtoellipse,0)); obj^.disable; inc(x,dx+2); inc(y,-dy-2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'З.Окр.',#0,false,cmtocircle,0)); obj^.disable; inc(x,0); inc(y,dy+2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'З.Элл.',#0,false,cmtoellipse,0)); obj^.disable; inc(x,dx+2); inc(y,-dy-2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'З.Мног.',#0,false,cmtocircle,0)); obj^.disable; inc(x,0); inc(y,dy+2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'Заливка',#0,false,cmtoellipse,0)); obj^.disable; inc(x,dx+10); inc(y,-dy-2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'Удал.',#66,true,cmToDel,0)); inc(x,0); inc(y,dy+2); obj:=new(PCheckButton, Init(@Self,x,y,x+dx,y+dy,'Перем.',#0,false,cmToMove,0)); x:=20; y:=455; dx:=70; dy:=20; obj:=new(PButton,Init(@Self,x,y,x+dx,y+dy,'Выход',#0,false,cmQuit)); inc(x,dx+5); obj:=new(PButton,Init(@Self,x,y,x+dx,y+dy,'Загр.',#61,true,cmread)); inc(x,dx+5); obj:=new(PButton,Init(@Self,x,y,x+dx,y+dy,'Сохр.',#60 ,true,cmsave)); inc(x,dx+5); dx:=100; obj:=new(PButton, Init(@Self,x,y,x+dx,y+dy,

'Сохр. в PAS',#63,true,cmSavetoPas)); x:=364; obj:=new(PButton,Init(@Self,x,y,x+dx,y+dy,'Очистка',#59,true,cmclear)); ColorBar:=new(pColorBar,init(@Self,500,420,620,460)); ShowAll; end;

destructor TApplication.Done; begin CloseGraph; inherited Done; end;

procedure TApplication.ShowAll; var e,e1:TEvent;i:integer; begin hidemouse; setfillstyle(solidfill,7); bar(0,0 ,getmaxx,getmaxy);

234

Page 235: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

with e1 do begin TypeEvent:=evCommand; Command:=cmShow end; for i:=0 to Count-1 do begin e:=e1; PView(at(i))^.HandleEvent(e); end; showmouse; end;…end.

Прокомментируем некоторые методы:1. Метод ShowAll приложения дублирует возможности метода Show класса TView.2. Иерархия объектов приложения строится внутри констрактора. Любые изменения в

интерфейсе желательно сосредоточить именно там.3. Для простоты управления иерархия объектов в графическом редакторе одноуровневая,

то есть все объекты принадлежат объекту "приложение" напрямую.4. Принцип интерактивного создания примитива состоит в следующем: При щелчке

мыши на холсте в режиме рисования происходит переход в режим динамического рисования, создается соответствующий примитив, временно запрещается и вставляется в коллекцию. Указатель на этот примитив дублируется в специальной переменной, с которой и ведется дальнейшая работа. При перемещении мыши изменяется одна из групп координат примитива, причем прорисовка ведется методом XorShow. При повторном нажатии снова изменяются координаты примитива, он разрешается для показа, обнуляется временная переменная для хранения указателя на примитив, холст перерисовывается, происходит переход в режим рисования.

5. Принцип интерактивного перемещения примитива состоит в следующем: при щелчке мыши в режиме перемещения определяется примитив, на котором произошло нажатие и если такой существует, то происходит переход в режим динамического перемещения, примитив временно запрещается, указатель на него копируется в специальную переменную для дальнейшей работы. При изменении координат курсора мыши в режиме динамического перемещения, изменяются и координаты примитива методом TGrObject.Move. Перерисовка примитива производится методом TGrObject.XorShow. При повторном щелчке кнопкой мыши происходит переход из режима динамического перемещения в режим перемещения, а переменная для хранения указателя на примитив обнуляется. Методы для прорисовки и перемещения примитива являются виртуальными, поэтому добавление нового вида примитива не требует изменения кода для перемещения примитивов.

6. Принцип интерактивного удаления примитива состоит в следующем: при щелчке мыши в режиме удаления определяется примитив, на котором произошло нажатие и если такой существует, то происходит его удаление из коллекции, после чего холст перерисовывается.

7. Для интерактивного создания нового вида примитивов следует:a. Определить команду-событие для перехода в режим рисования соответствующего

примитива (например - cmToPoly)b. Создать кнопку или другое средство для возникновения данного события.c. Реализовать переход в режим рисования примитива в разделе обработки команд

метода TCanvas.HandleEvent.d. Добавить соответствующие действия (по аналогии с уже существующими) в методы

TCanvas.BeginRis, TCanvas.EndRis, TCanvas.MoveRis. При необходимости добавить действия в TCanvas.CancelDynamicMode.

235

Page 236: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

Теперь, по завершении работы с модулем gred.pas, следует создать основную программу, которая будет выглядеть очень просто:

uses Gred; var A:TApplication; begin a.init; a.run; a.done; end.Графический редактор готов к использованию.

Задания для программного проектаЗадание 186. Определите класс TSpeedButton – кнопка с растровым рисунком вместо текста. Проверьте его работоспособность.Задание 187. Определите класс TVSpeedButton – кнопка с векторным рисунком вместо текста. Проверьте его работоспособность.Задание 188. Определите класс для интерактивного выбора стиля линий (по аналогии с TColorBar). Проверьте его работоспособность.Задание 189. Определите класс для интерактивного выбора толщины линий (по аналогии с TColorBar). Проверьте его работоспособность.Задание 190. Определите класс для интерактивного выбора стиля заливки (по аналогии с TColorBar). Проверьте его работоспособность.Задание 191. Реализуйте интерактивную прорисовку классов TGrEllipse, TGrBar, TGrFillEllipse.Задание 192. Реализуйте интерактивную прорисовку классов TGrArcCircle, TGrArcEllipse.Задание 193. Реализуйте интерактивную прорисовку класса TGrText.Задание 194. Реализуйте интерактивную прорисовку класса TGrPicture.Задание 195. Реализуйте интерактивную прорисовку классов TGrPoly, TGrFillPoly.Задание 196. Реализуйте интерактивную прорисовку класса TGrFill

236

Page 237: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Программный проект (12)

2.5.5 Особенности отладки больших программных проектов (БПП), основанных на объектно-событийной

модели.

Виды ошибок идентичны как для небольших программ, так и для БПП. Однако размеры БПП и специфическая структура программы значительно усложняют процесс отладки.

2.5.5.1 Синтаксические ошибки в БПП.Частота возникновения синтаксических ошибок не зависит от структуры и

размеров программы. Однако особенности процесса ввода БПП в компьютер позволяют сделать несколько выводов. В отличие от малых программ, БПП компилируются и тестируются гораздо большими по объему блоками. При этом компилятор может найти целый набор синтаксических ошибок, которые являются либо идентичными (например - недопустимые символы в имени некоторой переменной, отсутствие скобок в условных операторах при наличии логических операций и т.д.), либо одна из ошибок служит причиной генерации других (например - отсутствие end в составном операторе вызовет лавину ошибок в оставшейся части программы, особенно, если данная ошибка произошла не составном операторе программы, а в одном из составных операторов вышеопределенных процедур и функций).

Для ускорения отладки в первом случае можно произвести исправление всех идентичных ошибок, не дожидаясь перекомпиляции. Второй случай возникает только на компиляторах, отслеживающих все ошибки программы до аварийной остановки (Turbo C, C++, C++ Builder, Delphi и др.). Если программист предпочитает корректировать все найденные ошибки до повторной перекомпиляции программы, то он сталкиваться с ситуацией, когда исправлять приходится несуществующие ошибки. Таким образом, не следует искать причину синтаксической ошибки, если она не видна сразу и ошибка не является первой в списке синтаксических ошибок. Устранение первой ошибки и перекомпиляция программы часто автоматически устраняет и последующие.

2.5.5.2 Семантические ошибки в БПП.

Предупреждение семантических ошибок в БПП.

Констатация и локализация семантических ошибок в БПП реализуется более сложными средствами, чем в небольших программах.

Поэтому были выработаны специальные методы, которые в значительной

237

Page 238: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Семантические ошибки в БПП.

степени позволяют уменьшить количество семантических ошибок в программе. Суть данных методов заключаются в определенном стиле программирования, в основу которого положена независимость и надежность каждого логически завершенного участка программного кода:

1) Независимость программного кода от таких критичных параметров, как объем доступной памяти, свободное место на жестком диске, набор коммуникационных устройств, тип видеоадаптера и т.д., либо правильная обработка всех критических ситуаций (например - перед NEW проверить MEMAVAIL).

2) Самодостаточность программного кода, что подразумевает общение с вызвавшим кодом с помощью только входных и выходных параметров (заранее четко и однозначно определенных), а также независимость программного кода от места его вызова.

3) Уникальность любого набора данных и методов определения состояния программы. Например - если некоторое поле объекта отвечает за состояние объекта (видим-невидим, запрещен-разрешен, активен-неактивен) и т.д., то никакие другие поля (или методы, ссылающиеся на эти поля) не должны отвечать за то же самое состояние.

4) Минимальное использование глобальных переменных. В идеальном случае программа имеет только одну глобальную переменную - корень иерархии экземпляров объектов.

Констатация семантических ошибок в БПП.

В программах с последовательной структурой констатация ошибки не является обычно проблемой, так как имеется ограниченное количество путей прохождения от начала до конца алгоритма и практически всегда можно определить, откуда выполнение программы пришло в некоторую точку и куда затем последует. Для констатации ошибки в такой программе требуется небольшое количество контрольных примеров, на которых выполнение программы захватит все ветви алгоритма.

В БПП с событийной структурой логически завершенные участки кода могут выполнятся в произвольном порядке произвольное количество раз. Поэтому существует бесконечное количество вариантов выполнения такой программы. Метод контрольных примеров может лишь частично помочь в констатации ошибки. С его помощью можно добиться прохождения по всем элементам блок-схемы алгоритма, но невозможно перебрать все варианты порядка выполнения частей программы. (на сегодняшний день не существует методов полной констатации ошибок в БПП. Типичный пример - постоянные дополнения к Windows, Office и другим событийно-ориентировнным БПП)

238

Page 239: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Семантические ошибки в БПП.

Локализация семантических ошибок в БПП.

Локализация ошибок в БПП - более сложная задача, чем в небольших программах.

Причины:1) Большой объем программного кодаБольшой объем программного кода усложняет локализацию ошибки по

следующим причинам - невозможность использования встроенного или внешнего отладчика из-за нехватки оперативной памяти, большое количество модулей, использование неотлаженных модулей других групп программистов проекта, активное использование не протестированных модулей сторонних фирм.

2) Разрывность программного кода из-за событийной организации БПП.Разрывность программного кода в общем случае не позволяет четко и

однозначно определить, откуда произойдет вызов метода обработки некоторого события и какой метод будет вызван следующим. Таким образом, участки программы, в которых программист не учел возможности вызова из любой другой части программы, могут в некоторых случаях работать неверно, то есть содержать потенциальные ошибки. (например - совместное использование глобальных переменных, несогласованность в использовании динамической памяти и т.д. ).

3) Влияние процесса трассировки программы на результаты выполнения того или иного участка кода.

Это особенно заметно при ошибках в реализации событийной модели или в различных обработчиках событий. Если требуется протестировать последовательность, состоящую из нескольких внешних событий, таких как события от клавиатуры или мыши, то использование трассировки внесет неизбежные искажения в саму последовательность.

4) Высокодинамичная структура данных в БПП.Ошибки, связанные с динамической организацией иерархии экземпляров

объектов чрезвычайно трудно локализовать. Отсутствие общих методов визуального представления такой иерархии не позволяет проанализировать динамическую структуру данных программы в любой момент времени.

Методы локализации семантических ошибок в БПП.

Общий подход к локализации ошибок в БПП состоит в использовании условных и безусловных точек прерывания, трассировки отдельных участков кода после срабатывания точки прерывания, просмотра и изменения значения переменных, а также в организации отладочных файлов или окон на экране, визуализирующих динамическую структуру данных программы или любой ее части. Таким образом, основной метод отладки небольших программ - трассировка, используется очень ограниченно.

Большинство из этих средств предоставляются встроенным или внешним отладчиком, однако исследование динамической структуры данных можно

239

Page 240: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Семантические ошибки в БПП.

организовать только программно. Таким образом сам программный код будет включать в себя множество средств для отладки.

Проблема быстрого перехода от отладочной версии к рабочей во многих языках решается использованием условной компиляции.{$DEFINE Условный_символ},{$UNDEF Условный_символ } {$IFDEF Условный_символ},{$IFNDEF Условный_символ },{$ELSE},{$ENDIF}

Использование условных символов позволяет заключать отладочные участки программы в блоки, которые либо будут, либо не будут компилироваться в зависимости от того, определен или нет условный символ. Ряд условных символов автоматически определяется (или отменяется) компилятором ТП:

VER70 – версия ТП – 7.0MSDOS – операционная система – DOSWINDOWS - операционная система – WindowsCPU86 – микропроцессор – серии Intel xxx86CPU87 – сопроцессор – серии Intel xxx87DPMI –программа предназначена для защищенного режимаДиректива DEFINE позволяет определить условный символ, директива

UNDEF – отменить его. Директивы IFDEF и IFNDEF открывают блок условной компиляции, ENDIF – закрывает. Директива ELSE применяется аналогично соответствующему оператору ТП.

Задача 60. В некоторой программе активно используются вещественные значения различных типов. Однако отладка программы проходит на нескольких компьютерах, одни из которых оборудованы математическим сопроцессором, а другие – нет. Определить блок условной компиляции, позволяющий компилировать и тестировать программу на любом из этих компьютеров.

Решение состоит в переопределении вещественных типов на компьютерах, не оборудованных математическим сопроцессором. Наличие сопроцессора определятся с помощью условного символа CPU87:

{$IFDEF CPU87} {$N+} type Real = Double;{$ELSE} {$N-} type Single = Real; Double = Real; Extended = Real; Comp = Real;{$ENDIF}Рассмотрим пример, в котором динамическая структура иерархии объектов

или любая ее ветка сохраняется в файле для последующего анализа. Вызов созданных отладочных процедур может производится по нажатию на неиспользуемые в программе клавиши.

Определим условный символ

240

Page 241: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Семантические ошибки в БПП.

{$Define DEBUG} Определим в классе TEventObject несколько отладочных процедур.

{$IFDEF DEBUG}Function GetDebugInfo:string;virtual;Procedure Debug(var F:Text; FirstString:string);Procedure BeginDebug(FN:string);{$ENDIF}

Функция GetDebugInfo должна перекрываться в каждом, порожденном от TEventObject объекте и возвращать в строке специфичную для каждого объекта информацию.

{$IFDEF DEBUG}Procedure TeventObject.GetDebugInfo:string; Begin GetDebugInfo:='TeventObject'; End;Процедура Debug выводит в файл отладочную информацию для данного объекта и всех

подчиненных; Procedure TeventObject.Debug(var F:Text;

FirstString:string{отступ}); Var s:string; i:integer Begin

S:=firstString;If (owner=nil) or

((owner<>nil) and (owner^.Active=@self)) then s:=s+'*';

if disabled then s:=s+'-';Writeln(f,s+GetdebugInfo);FirstString:=firstString+' ';With components^ do begin

For i:=0 to Count-1 do PeventObject(at(i))^.Debug(f,FirstString);End;

End;Процедура BeginDebug открывает файл, записывает в него отладочную информацию и

закрывает файл.Procedure TeventObject.BeginDebug(FN:string); Var F:Text; Begin Assign(f,FN); Rewrite(f); Debug(f,'') Close(f); End;{$ENDIF}Таким образом, после констатации ошибки, причиной которой может быть неверно

сформированная структура динамических данных или для проверки работоспособности процедур, отвечающих за формирование такой структуры, может быть вызвана процедура BeginDebug для любого объекта иерархии.

В окончательной версии программы для удаления отладочного кода можно отменить условный символ DEBUG, заменив директиву Define на Undef.

241

Page 242: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Семантические ошибки в БПП.

Задания для раздела "Методы локализации семантических ошибокв БПП."Задание 197*. Внести в класс TEventObject процедуры и функции, предназначенные для отладки (GetDebugInfo, Debug, BeginDebug), а в каждом классе графического редактора, порожденном от TEventObject – перекрыть функцию GetDebugInfo. По нажатию на клавишу F1 в графическом редакторе создавать файл отладки, используя отладочные функции.Задание 198. Расширить решение предыдущей задачи. Создать класс окна для визуализации текстового файла в графическом режиме. По нажатию на клавишу F2 на экране появляется окно с информацией об иерархии объектов редактора.

242

Page 243: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Список литературы.

Список литературы.1. Абрамов С.А., Гнездилова Г.Г., Капустина Е.Н., Селюн М.И. Задачи по

программированию. - М.: Наука, 1988. - 224 с.12. Архитектура среды для разработки приложений. Киев: "Крещатник", 1992 – 240

с.23. Вирт Н. Алгоритмы + структуры данных = программы / Пер. с англ. - М.: Мир,

1985. - 406 с., ил.34. Вирт Н. Систематическое программирование. Введение / Пер. с англ. - М.: Мир,

1977. - 183 с.45. Вьюкова Н.И., Галатенко В.А., Ходулев А.Б. Систематический подход к

программированию. - М.: Наука, 1988. - 208 с.56. Епанешников А., Епанешников В. Программирование в среде Turbo-Pascal 7.0. -

4-е изд. испр. и дополн. - М.:"Диалог-МИФИ", 1998. - 367с.67. Райли Д. Абстрация и структуры данных: Вводный курс: Пер. с англ. – М.:Мир,

1993. – 752 с., ил.78. Слинкин Д.А. Программирование. Часть 1. Язык программирования Турбо-

Паскаль: Учебное пособие для студентов вузов. Шадринск: Изд-во Шадринского пединститута, 1999. - 143 с.8

9. Слинкин Д.А. Программирование. Часть 2. Методы программирования на Турбо-Паскале: Учебное пособие для студентов вузов. Шадринск: Изд-во Шадринского пединститута, 2000. - 141 с.9

10.Справочник программиста и пользователя/Под ред. А.Г. Шевчика, Т.В. Демьянкова. - М.: "Кварта", 1993. - 128с.10

11.Толковый словарь по вычислительным системам/Под ред. В.Иллингуорта и др.: Пер. с англ. А.К. Белоцкого и др.; Под ред. Е.К. Масловского. - М.: Машиностроение, 1990. - 560с.: ил.11

12.Фаронов В.В. Турбо-Паскаль (в 3 книгах). Кн. 3. Практика программирования. Часть 1. – М.: Учебно-инженерный центр "МВТУ – ФЕСТО ДИДАКТИК", 1993. – 256 с., ил.12

13.Федоров А. Borland Pascal: практическое использование Turbo Vision 2.0. Киев: "Диалектика", 1993. – 273 с., ил.13

14.Turbo Vision для языка Pascal. Описание. М: "И.В.К.-Софт", 1992. – 224 с.1415.Turbo Vision для языка Pascal. Справочник. М: "И.В.К.-Софт", 1992. – 288 с.15

243

Page 244: ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕirbis.shgpi.edu.ru/biblioteka/katfree/2.pdf · 681.3.066.3 c47 Слинкин Д.А. Основы программирования

Учебно-методическое пособие для студентов вузов

Слинкин Дмитрий Анатольевич

ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ТУРБО-ПАСКАЛЕ

Лицензия ЛР №020057 от 7 апреля 1997 г.Формат 6090 / 1/16, усл. печ. л. 15.1, тираж 100 экз.