КулЛиб - Классная библиотека! Скачать книги бесплатно 

Самоучитель по программированию на Free Pascal и Lazarus [Евгений Ростиславович Алексеев] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]
Министерство образования и науки, молодежи и спорта Украины
ГВУЗ «Донецкий национальный технический университет»
серия «Компьютерные науки и технологии»
90-летию ДонНТУ посвящается

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В.

Самоучитель по программированию
на Free Pascal и Lazarus

УНИТЕХ
ДОНЕЦК 2011

УДК 004.43
ISBN 978-966-8248-26-9
Рецензенты:

А 47

Аноприенко А.Я. — кандидат технических наук, профессор, декан факультета компьютерных наук и технологий Донецкого национального технического
университета.
Кононов Ю.Н. — доктор физико-математических
наук, профессор кафедры прикладной механики и
компьютерных технологий Донецкого национального
университета.

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель
по программированию на Free Pascal и Lazarus. - Донецк.:
ДонНТУ, Технопарк ДонНТУ УНИТЕХ, 2011. - 503 с.

Рекомендовано Министерством образования и науки Украины как учебное
пособие для студентов высших учебных заведений (письмо от 29.12.2010 №1/11
- 122361).
Ответственный за выпуск: заведующий кафедрой вычислительной математики и программирования Донецкого национального технического университета, доктор технических
наук, профессор Павлыш В.Н.
Книга является учебником по алгоритмизации и программированию. В учебнике описан
язык Free Pascal и среда визуального программирования Lazarus. Free Pascal и Lazarus являются мощными и свободно распространяемыми средствами программирования. В книге
приведено большое количество примеров алгоритмов и программ. Особое внимание уделено
работе с визуальными компонентами, их свойствами и методами. Подробно описаны такие
этапы программирования как работа с подпрограммами и файлами. Также в книге можно познакомиться с основами объектно-ориентированного программирования и графическими
средствами Lazarus. Книга содержит 25 вариантов заданий для самостоятельного решения по
всем рассматриваемым темам.
Издание предназначено для школьников, студентов, аспирантов и преподавателей, а
также для всех, кто изучает программирование на Free Pascal и Lazarus.
Материалы, составляющие данную книгу, распространяются на условиях лицензии
GNU FDL.
ISBN 978-966-8248-26-9

ООО «Технопарк ДонНТУ УНИТЕХ»

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В., 2011

3

Содержание
Введение......................................................................................................7
Сведения об авторах.................................................................................10
1 Средства разработки программ на языке Free Pascal........................11
1.1 Процесс разработки программы...................................................11
1.2 Среда программирования Free Pascal..........................................13
1.2.1 Работа в текстовом редакторе Free Pascal.............................17
1.2.2 Запуск программы в среде Free Pascal и просмотр результатов.......................................................................................................18
1.3 Текстовый редактор Geany............................................................19
1.4 Среда визуального программирования Lazarus..........................20
1.4.1 Установка Lazarus в ОС Linux................................................22
1.4.2 Установка Lazarus под управлением ОС Windows...............25
1.4.3 Среда Lazarus...........................................................................28
1.4.4 Главное меню Lazarus.............................................................30
1.4.5 Окно формы.............................................................................34
1.4.6 Окно редактора Lazarus..........................................................34
1.4.7 Панель компонентов................................................................43
1.4.8 Инспектор объектов................................................................43
1.4.9 Первая программа в Lazarus...................................................44
1.4.10 Полезная программа..............................................................53
1.4.11 Консольное приложение среды Lazarus..............................59
1.4.12 Операторы ввода - вывода данных......................................61
2 Общие сведения о языке программирования Free Pascal.................64
2.1 Структура проекта Lazarus............................................................64
2.2 Структура консольного приложения............................................65
2.3 Элементы языка.............................................................................67
2.4 Данные в языке Free Pascal...........................................................68
2.4.1 Символьный тип данных........................................................69
2.4.2 Целочисленный тип данных...................................................69
2.4.3 Вещественный тип данных....................................................70
2.4.4 Тип дата-время.........................................................................70
2.4.5 Логический тип данных..........................................................71
2.4.6 Создание новых типов данных..............................................71
2.4.7 Перечислимый тип данных....................................................71
2.4.8 Интервальный тип...................................................................72

4

2.4.9 Структурированные типы.......................................................72
2.4.10 Указатели................................................................................75
2.5 Операции и выражения.................................................................76
2.5.1 Арифметические операции....................................................78
2.5.2 Операции отношения..............................................................80
2.5.3 Логические операции..............................................................80
2.5.4 Операции над указателями.....................................................81
2.6 Стандартные функции...................................................................81
2.7 Задачи для самостоятельного решения........................................94
3 Операторы управления........................................................................96
3.1 Основные конструкции алгоритма...............................................96
3.2 Оператор присваивания.................................................................97
3.3 Составной оператор.......................................................................98
3.4 Условные операторы......................................................................98
3.4.1 Условный оператор if…then…else.........................................98
3.4.2 Оператор варианта case ........................................................117
3.5 Обработка ошибок. Вывод сообщений в среде Lazarus...........121
3.6 Операторы цикла..........................................................................125
3.6.1 Оператор цикла с предусловием while .. do........................126
3.6.2 Оператор цикла с постусловием repeat … until..................127
3.6.3 Оператор цикла for … do......................................................129
3.7 Операторы передачи управления...............................................132
3.8 Решение задач с использованием циклов..................................132
3.9 Ввод данных из диалогового окна в среде Lazarus...................147
3.10 Задачи для самостоятельного решения....................................156
3.10.1 Разветвляющийся процесс..................................................156
3.10.2 Циклический процесс.........................................................161
4 Подпрограммы....................................................................................164
4.1 Общие сведения о подпрограммах. Локальные и глобальные
переменные..........................................................................................164
4.2 Формальные и фактические параметры. Передача параметров в
подпрограмму......................................................................................165
4.3 Процедуры....................................................................................166
4.4 Функции........................................................................................171
4.5 Решение задач с использованием подпрограмм........................176
4.6 Рекурсивные функции.................................................................198
4.7 Особенности работы с подпрограммами...................................202
4.7.1 Параметры-константы...........................................................202

5

4.7.2 Процедурные типы................................................................202
4.8 Разработка модулей......................................................................206
4.9 Задачи для самостоятельного решения......................................210
5 Использование языка Free Pascal для обработки массивов............213
5.1 Общие сведения о массивах........................................................213
5.2 Описание массивов......................................................................214
5.3 Операции над массивами............................................................216
5.4 Ввод-вывод элементов массива..................................................217
5.4.1 Организация ввода-вывода...................................................217
5.4.2 Ввод-вывод данных в визуальных приложениях...............221
5.5 Вычисление суммы и произведения элементов массива.........230
5.6 Поиск максимального элемента в массиве и его номера.........231
5.7 Сортировка элементов в массиве...............................................232
5.7.1 Сортировка методом «пузырька».........................................232
5.7.2 Сортировка выбором.............................................................235
5.8 Удаление элемента из массива....................................................237
5.9 Вставка элемента в массив..........................................................241
5.10 Использование подпрограмм для работы с массивами..........242
5.11 Использование указателей для работы с динамическими массивами..................................................................................................245
5.11.1 Работа с динамическими переменными и указателями...246
5.11.2 Работа с динамическими массивами с помощью процедур
getmem и freemem............................................................................249
5.12 Примеры программ....................................................................252
5.13 Задачи для самостоятельного решения....................................282
6 Обработка матриц во Free Pascal......................................................285
6.1 Ввод-вывод матриц......................................................................287
6.2 Алгоритмы и программы работы с матрицами.........................300
6.3 Динамические матрицы...............................................................341
6.4 Задачи для самостоятельного решения......................................344
7 Обработка файлов средствами Free Pascal.......................................347
7.1 Типы файлов.................................................................................347
7.2 Работа с типизированными файлами ........................................348
7.2.1 Процедура AssignFile................................................................348
7.2.2 Процедуры reset, rewrite...........................................................349
7.2.3 Процедура СloseFile..................................................................349
7.2.4 Процедура rename.....................................................................350
7.2.5 Процедура erase.........................................................................350

6

7.2.6 Функция eof...............................................................................350
7.2.7 Чтение и запись данных в файл...............................................350
7.3 Бестиповые файлы в языке Free Pascal......................................376
7.4 Обработка текстовых файлов в языке Free Pascal.....................390
7.5 Задачи для самостоятельного решения......................................396
8 Работа со строками и записями ........................................................399
8.1 Обработка текста.............................................................................399
8.2 Работа с записями............................................................................405
8.3 Задачи для самостоятельного решения по теме «Строки»..........415
8.4 Задачи для самостоятельного решения по теме «Записи»..........416
9 Объектно-ориентированное программирование.............................421
9.1 Основные понятия.......................................................................421
9.2 Инкапсуляция...............................................................................432
9.3 Наследование и полиформизм....................................................437
9.4 Перегрузка операций...................................................................451
9.5 Задачи для самостоятельного решения......................................467
10 Графика во Free Pascal......................................................................471
10.1 Средства рисования в Lazarus...................................................471
10.2 Построение графиков................................................................482
10.3 Задачи для самостоятельного решения....................................495

7

Введение
Авторы книги давно хотели написать учебник по программированию, предназначенный для пользователей различных операционных
систем.
Учебник основан на курсе, который авторы читали в Донецком
национальном техническом университете (ДонНТУ) студентам общеинженерных специальностей. Многие годы в ДонНТУ в качестве языка обучения программированию будущих инженеров используется
Pascal, который является ясным, логичным и гибким языком и
приучает к хорошему стилю программирования. Кроме того, в средней школе основы программирования преподают именно на базе
Pascal. Вместе с тем именно Pascal лежит в основе современной мощной системы визуального программирования Delphi, c помощью которой разрабатываются многие современные программные продукты.
В учебнике используется язык программирования Free Pascal,
компиляторы с которого являются свободно распространяемыми.
Free Pascal является очень мощным средством программирования, и
вместе с тем за использование компиляторов студенту, школьнику и
преподавателю не придется платить. Этим компилятором можно
пользоваться абсолютно легально.
Свободно распространяемые компиляторы с языка Free Pascal реализованы во многих дистрибутивах Linux, есть свободные компиляторы и для ОС Windows. Кроме того, в этой книге мы попытались познакомить читателя с принципами создания визуальных приложений
в среде Lazarus. Бурно развивающаяся среда визуального программирования Lazarus является серьезным конкурентом Delphi.
В настоящее время существует множество подходов к изучению
программирования. По мнению авторов, нельзя изучать программирование на каком-либо языке, не изучив методы разработки алгоритмов.
Как свидетельствует опыт авторов, одним из наиболее наглядных методов составления алгоритмов является язык блок-схем. Мы попытались написать учебник по алгоритмизации и программированию. Насколько нам это удалось судить читателю.
Авторы надеются, что читатель имеет первоначальные навыки работы на персональном компьютере под управлением ОС Linux или
Windows и знаком со школьным курсом математики.

8

Книга состоит из десяти глав.
В первой главе читатель узнает о средствах разработки программ
на Free Pascal, напишет свои первые программы.
Во второй главе изложены основные элементы языка (переменные, выражения, операторы) Free Pascal. Описаны простейшие операторы языка: присваивания и ввода-вывода. Приведена структура программы на Free Pascal, а также примеры программ линейной структуры.
Третья глава является одной из ключевых в изучении программирования. В ней изложена методика составления алгоритмов с помощью блок-схем. Приведено большое количество примеров алгоритмов и программ различной сложности. Авторы рекомендуют внимательно разобрать все примеры и выполнить упражнения этой главы и
только после этого приступать к изучению последующих глав книги.
В четвертой главе читатель на большом количестве примеров
познакомится с подпрограммами. Описан механизм передачи параметров между подпрограммами. Один из параграфов посвящен рекурсивным подпрограммам. В завершении главы рассмотрен вопрос создания личных модулей.
Пятая и шестая главы посвящены алгоритмам обработки массивов и матриц. Здесь же читатель познакомится и с реализацией этих
алгоритмов на языке Free Pascal. Именно эти главы совместно с третьей являются ключом к пониманию принципов программирования.
Седьмая глава знакомит читателя с обработкой файлов на языке
Free Pascal под управлением операционных систем Linux и Windows.
На практических примерах изложен механизм прямого и последовательного доступа к файлам и обработки ошибок ввода-вывода. Описана работа с бестиповыми и текстовыми файлами.
Восьмая глава посвящена обработке строк и записей. Приведенные примеры позволят читателю разобраться с принципами обработки таблиц в языке Free Pascal.
В девятой главе авторы описали принципы объектно-ориентированного программирования и их реализацию в языке Free Pascal.
В десятой главе описаны графические возможности Lazarus, подробно описан алгоритм построения графиков непрерывных функций
на экране дисплея. Приведены тексты программ изображения графиков функций с подробными комментариями.

9

К каждой теме прилагаются 25 вариантов задач для самостоятельного решения, что позволит использовать книгу не только начинающим самостоятельно изучать программирование, но и преподавателям
в учебном процессе.
С рабочими материалами книги можно познакомиться на сайтах
Евгения Ростиславовича Алексеева — www.teacher.dn-ua.com,
www.teacher.ucoz.net.
Авторы выражают благодарность своим родным за помощь и понимание.
Алексеев Е.Р., Чеснокова О.В., Кучер Т.В.
Донецк, сентябрь 2011 г.

10

Сведения об авторах
Алексеев Евгений Ростиславович — кандидат технических наук,
доцент кафедры «Вычислительная математика и программирование»
Донецкого национального технического университета, доцент кафедры «Документоведение и информационная деятельность» Донецкого
инженерно-экономического колледжа. Преподавательский стаж Алексеева Е.Р. — 17 лет. Евгений Ростиславович — автор двенадцати книг,
вышедших в Москве и Донецке, общий тираж которых превышает 65
тыс. экземпляров. Е.Р. Алексеев — автор более 60 научных и методических работ. Область его научных интересов — программирование,
вычислительная математика, Интернет-технологии, использование
свободно распространяемого программного обеспечения.
Чеснокова Оксана Витальевна — старший преподаватель кафедры «Вычислительная математика и программирование» Донецкого
национального технического университета. Преподавательский стаж
Чесноковой О.В. — 15 лет. Оксана Витальевна — автор девяти книг,
общий тираж которых превышает 40 тыс. экземпляров, а также —
около 40 научных и методических работ. Область ее научных интересов — программирование, вычислительная математика.
Кучер Татьяна Викторовна — ассистент кафедры «Вычислительная математика и программирование» Донецкого национального технического университета, ассистент кафедры «Документоведение и информационная деятельность» Донецкого инженерно-экономического
колледжа. Татьяна Викторовна — автор 30 научных и методических
работ. Преподавательский стаж Кучер Т. В. — 14 лет. Область ее научных интересов — программирование, вычислительная математика.

11

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

Pascal
В этой главе мы начинаем знакомство с программированием на
языке Free Pascal. Язык программирования Free Pascal ведет свое начало от классического языка Pascal, который был разработан в конце
60-х годов XX века Николасом Виртом. Он разрабатывал этот язык
как учебный язык для своих студентов. С тех пор Pascal, сохранив
простоту и структуру языка, разработанного Н. Виртом, превратился
в мощное средство программирования. С помощью современного
языка Pascal можно производить простые расчеты, разрабатывать программы для проведения сложных инженерных и экономических вычислений.
1.1 Процесс разработки программы
Разработку программы можно разбить на следующие этапы:
1. Составление алгоритма решения задачи. Алгоритм — это описание последовательности действий, которые необходимо выполнить
для решения поставленной задачи.
2. Написание текста программы. Текст программы пишут на каком-либо языке программирования (например на Free Pascal) и вводят
его в компьютер с помощью текстового редактора.
3. Отладка программы. Отладка программы — это процесс
устранения ошибок из текста программы. Все ошибки делятся на синтаксические и логические. При наличии синтаксических ошибок
(ошибок в написании операторов) программа не запускается. Подобные ошибки исправляются проще всего. Логические ошибки — это
ошибки, при которых программа работает, но неправильно, выдавая
не те результаты, которые ожидает разработчик или пользователь. Логические ошибки исправить сложнее, чем синтаксические, иногда для
этого приходится переписывать отдельные участки программы, а иногда перерабатывать весь алгоритм.
4. Тестирование программы. Тестирование программы — процесс выявления ошибок в ее работе.
Процессы отладки и тестирования сопровождаются неоднократным запуском программы на выполнение. Процесс запуска может
быть осуществлен только после того, как введенная в компьютер про-

12

грамма на алгоритмическом языке Pascal1 будет переведена в двоичный машинный код и создан исполняемый файл.
Процесс перевода текста программы в машинный код называют
трансляцией. Все трансляторы делятся на два класса:
• интерпретаторы — трансляторы, которые переводят каждый
оператор программы в машинный код и по мере перевода операторы
выполняются процессором;
• компиляторы переводят всю программу целиком, и если этот
перевод прошел без ошибок, то полученный двоичный код можно
запускать на выполнение.
Если в качестве транслятора выступает компилятор, то процесс
перевода текста программы в машинный код называют компиляцией.
При переводе программы с языка Pascal в машинный код используются именно компиляторы2.
Рассмотрим основные этапы обработки компилятором программы на языке Pascal.
1. Компилятор анализирует, какие внешние библиотеки 3 нужно
подключить, разбирает текст программы на составляющие элементы,
проверяет синтаксические ошибки и в случае их отсутствия формирует объектный код (в Windows — файл с расширением .obj, в Linux —
файл с расширением .o). Получаемый на этом этапе двоичный файл
(объектный код) не включает в себя объектные коды подключаемых
библиотек.
2. На втором этапе компоновщик подключает к объектному коду
программы объектные коды библиотек и генерирует исполняемый код
программы. Этот этап называется компоновкой, или сборкой, программы. Полученный на этом этапе исполняемый код можно запускать на выполнение.
На сегодняшний день существует множество компиляторов языка
Pascal, среди которых можно выделить компиляторы языка Pascal разработки фирмы Borland (Borland Pascal), а также свободно распространяемые кроссплатформенные компиляторы языка Free Pascal и
среду визуального программирования Lazarus.
1 Как и на любом другом языке.
2 Вместо термина «компилятор» в литературе иногда используют термин «транслятор компилирующего типа».
3 В библиотеках языка Pascal хранится объектный (двоичный) код стандартных (таких, как sin(x),
cos(x) и др.) функций и процедур языка.

13

1.2 Среда программирования Free Pascal
Рассмотрим процесс установки компилятора Free Pascal в ОС
Linux. Для установки программ в операционной системе Linux служит менеджер пакетов Synaptic. В ОС Ubuntu он вызывается с помощью команды Система — Администрирование — Менеджер пакетов Synaptic. В ALT Linux менеджер пакетов вызывается командой
Система — Программа управления пакетами Synaptic. Окно
Synaptic представлено на рис. 1.1.
Обратите внимание, что для установки программ необходимо
установить список источников программ (список репозиториев4). После установки ОС Ubuntu Linux первоначальный список репозиториев
установлен. В ОС ALT Linux первоначальный список репозиториев
надо установить.
Для установки окне Synaptic (см. рис. 1.1) необходимо щелкнуть
по кнопке Найти. И в открывшемся окне ввести fpc (см. рис. 1.2).
Менеджер программ находит программу Free Pascal, после чего в
окне Synaptic необходимо пометить программы fpc (Free Pascal
Compiler Meta Package) для установки (с помощью контекстного
меню или с помощью кнопки Отметить для обновления) и начать
установку, щелкнув по кнопке Применить. После этого начнется
процесс скачивания пакетов из Интернета и их установки.
В состав метапакета fpс входит компилятор языка Free Pascal
fpc и среда разработки fp-ide. Для запуска среды разработки в
Linux необходимо просто в терминале набрать fp. На рис. 1.3 представлено окно среды разработки программ на языке Free Pascal в ОС
Linux.
Для установки Free Pascal в операционной системе Windows
необходимо запустить скачанный со страницы загрузки http://www.freepascal.org/down/i386/win32.var инсталяционный файл. Первое диалоговое окно сообщит о начале процесса установки Free Pascal на
компьютер. Для продолжения процесса установки во всех следующих
окнах нужно выбирать кнопку Next, для возврата к предыдущему
шагу — кнопку Back, а для прерывания процесса установки — кнопку Cancel. В следующем окне нужно определить путь для установки
Free Pascal. По умолчанию установка происходит в корневой каталог
диска С. Для выбора другого пути установки можно воспользоваться
4 Список репозиториев — список официальных сайтов, с которых можно устанавливать программы.

14

кнопкой Browse.... Кроме того, в этом окне выводится информация о
количестве свободного места на диске. В следующих четырех окнах
пользователь сможет выбрать из списка тип установки: Full
Installation (полная), Minimum Installation (минимальная), Custom
Installation (выбор компонентов), указать название устанавливаемого
приложения в главном меню, выбрать типы файлов, поддерживаемых
средой, и начать процесс инсталляции Free Pascal, нажав кнопку
Install. Контролировать процесс установки можно с помощью линейного индикатора, а прервать кнопкой Cancel.
Запуск среды программирования Free Pascal в Windows можно
осуществить из главного меню: Пуск — Программы — Free Pascal
— Free Pascal. На экране появится окно, представленное на рис. 1.4.
Установив пакет Free Pascal, мы получили компилятор и среду
программирования.
Компилятор Free Pascal работает в командной строке. Для того
чтобы создать исполняемый файл из текста программы, написанного
на языке Pascal, необходимо выполнить команду
fpc name.pas
здесь fpc — имя исполняемого файла компилятора командной строки Free Pascal, name.pas — имя файла с текстом программы. В результате в Linux будет создан исполняемый файл с именем name (в
Windows — имя исполняемого файла name.exe).
При использовании компилятора fpc после компиляции автоматически происходит компоновка программы (запуск компоновщика
make).
Технология работы с компилятором Free Pascal может быть такой:
набираем текст программы в стандартном текстовом редакторе, затем
в консоли запускаем компилятор, после исправления синтаксических
ошибок повторно запускаем компилятор. После успешной компиляции запускаем исполняемый файл. При необходимости опять вносим
изменения в текст программы и запускаем компилятор. При такой
технологии работы с компилятором необходимо не забывать сохранять текст программы, иначе при запуске компилятора будет компилироваться старая версия текста программы.

15

Рисунок 1.1: Менеджер пакетов Synaptic

16

Рисунок 1.2: Окно поиска компилятора Free Pascal в Synaptic

Рисунок 1.3: Среда программирования Free
Pascal в ОС Linux

Рисунок 1.4: Окно компилятора Free Pascal

17

Среда программирования Free Pascal позволяет значительно
упростить процесс разработки программ. В состав среды программирования входит текстовый редактор, транслятор и отладчик.
Рассмотрим их работу подробнее.
1.2.1 Работа в текстовом редакторе Free Pascal
С помощью редактора Free Pascal можно создавать и редактировать тексты программ. После открытия пустого окна (File — New)
или загрузки текста программы (File — Open) пользователь находится в режиме редактирования, признаком чего является наличие в
окне курсора (небольшого мигающего прямоугольника). Для перехода
из режима редактирования к главному меню нужно нажать клавишу
F10, обратно — Esc. Кроме того, этот переход можно осуществить
щелчком мыши либо по строке главного меню, либо по полю редактора.
Редактор Free Pascal обладает возможностями, характерными для
большинства текстовых редакторов. Остановимся на некоторых особенностях.
Работа с фрагментами текста (блоками) в редакторе Free
Pascal может осуществляться с помощью главного меню и функциональных клавиш.
В главном меню для работы с фрагментами текста предназначены
команды пункта редактирования Edit:
Copy (Ctrl+C) — копировать фрагмент в буфер;
Cut (Ctrl+X) — вырезать фрагмент в буфер;
Paste (Ctrl+V) — вставить фрагмент из буфера;
Clear (Ctrl+Del) — очистить буфер;
Select All — выделить весь текст в окне;
Unselect — отменить выделение.
Команды Copy и Cut применяют только к выделенным фрагментам текста. Выделить фрагмент текста можно с помощью клавиши
Shift и клавиш перемещения курсора (стрелок). Кроме того, пункт
меню Edit содержит команды Undo и Redo, с помощью которых можно отменять и возвращать выполненные действия.
Комбинации клавиш, предназначенные для работы с блоком:
Ctrl+K+B – пометить начало блока;
Ctrl+K+K – пометить конец блока;
Ctrl+К+Т – пометить в качестве блока слово слева от курсора;
Ctrl+K+Y – стереть блок;

18

Ctrl+K+C – копировать блок в позицию, где находится курсор;
Ctrl+K+V – переместить блок в позицию, где находится курсор;
Ctrl+K+W – записать блок в файл;
Ctrl+K+R – прочитать блок из файла;
Ctrl+K+P – напечатать блок;
Ctrl+К+Н – снять пометку блока; повторное использование этой
комбинации клавиш вновь выделит блок.
Работа с файлами в среде Free Pascal осуществляется с помощью
команд File главного меню и функциональных клавиш:
New — открыть окно для создания новой программы;
Open (F3) — открыть ранее созданный файл;
Save (F2) — сохранить созданный файл;
Save As — сохранить файл под другим именем;
Exit (Alt+X) — выйти из среды программирования;
При создании новой программы ей по умолчанию присваивается
стандартное имя NONAMEOO.PAS (NO NAME — нет имени).
При первом сохранении файла пользователю будет предложено
ввести его имя. При повторном сохранении файл сохраняется под тем
же именем. Команда Save As аналогична первому сохранению. Если
файл не был сохранен, то при попытке завершить работу со средой
появится запрос о необходимости сохранить изменения в файле. При
открытии ранее созданного файла его имя выбирают из списка существующих файлов.
В редакторе Free Pascal допускается работа с несколькими окнами. Для переключения в окно с номером от первого до девятого нажать комбинацию клавиш Alt+i, где i – номер окна (например Alt+5
— вызов пятого окна). Для вывода списка окон на экран нажать комбинацию клавиш Alt+0, появится список активных окон, в котором
необходимо будет выбрать нужное и нажать Enter.
1.2.2 Запуск программы в среде Free Pascal и просмотр результатов
После того как текст программы был набран, его следует перевести в машинный код. Для этого необходимо вызвать транслятор с
помощью команды Compile — Compile (комбинация клавиш Alt+F9).
На первом этапе транслятор проверяет наличие синтаксических ошибок. Если в программе нет синтаксических ошибок, то на экране сообщается о количестве строк транслированной программы и объеме
доступной оперативной памяти.

19

Если на каком-либо этапе транслятор обнаружит ошибку, то в
окне редактора курсор указывает ту строку программы, где при трансляции обнаружена ошибка. При этом в верхней строке редактора появляется краткое диагностическое сообщение о причине ошибки.
Для запуска транслированной программы необходимо выполнить
команду Run — Run (комбинация клавиш Ctrl+F9), после чего на
экране появляется окно командной строки, в котором пользователь и
осуществляет диалог с программой. После завершения работы программы пользователь опять видит экран среды Free Pascal.
Для просмотра результатов работы программы в OC Windows
необходимо нажать комбинацию клавиш Alt+F5. Для возврата в оболочку следует нажать любую клавишу.
При использовании среды программирования в ОС Linux существует проблема вывода кириллического текста в консольном приложении. Альтернативой среды программирования Free Pascal является
текстовый редактор Geany (http://www.geany.org), который позволяет
разрабатывать программы на различных языках программирования.
1.3 Текстовый редактор Geany
Текстовый редактор Geany есть в репозитарии большинства
современных дистрибутивов Linux5. Разработка программ с использованием Geany довольна удобна. Установка Geany также может быть
осуществлена с помощью менеджера пакетов Synaptic.
Последовательно рассмотрим основные этапы разработки программы с использованием Geany.
1. Необходимо создать шаблон приложения на Pascal (или другом
языке программирования) с помощью команды Файл — New (with
Template) — Pascal source file. После чего появится окно с шаблоном
исходного кода (рис. 1.5), в котором необходимо ввести текст программы и сохранить его (рис. 1.6).
2. Для компиляции и запуска программы на выполнение служит
пункт меню Построить. Для компиляции программы следует использовать команду Построить — Собрать (F8). В этом случае будут созданы файл с объектным кодом программы и исполняемый файл. После компиляции программы ниже окна с программой будет представлен подробный отчет (рис. 1.6) о результатах компиляции. Следует
его внимательно изучить. Этот отчет позволит быстро исправлять
5 Существует версия Geany и для Windows (http://www.geany.org/Download/Releases)

20

синтаксические ошибки. В сообщении об ошибке указана строка, где
она найдена и ее краткое описание на английском языке. В отчетах по
результатам компиляции могут быть ошибки (error) и сообщения
(warning). Сообщения — это обнаруженные компилятором неточности, при которых возможно создание исполняемого кода программы.
3. Для запуска программы следует выполнить команду Построить — Выполнить (F5). После чего на экране появляется окно
терминала (рис. 1.7), в котором можно вводить данные и увидеть результаты работы программы.
В редакторе Geany (хотя часто его называют и средой программирования) можно настроить команду вызова компиляции, компоновки и запуск. Для это служит команда Построить — Установить
включения и аргументы. Это окно для работы с файлами с расширением pas представлено на рис. 1.8. При настройке строк Compile и
Запуск следует учитывать, что %f — имя компилируемого файла, %e
— имя файла без расширения.
Какую среду выбрать для разработки консольных программ на
Free Pascal — это дело пользователя. Авторы советуют под управлением ОС Linux использовать Geany6. Хотя можно использовать для
набора текста программы обычный текстовый редактор (например,
gedit, tea, kate и др.), а компиляцию осуществлять в терминале.
Под управлением Windows логичнее использовать fp-ide.
1.4 Среда визуального программирования Lazarus
Lazarus - это среда визуального программирования. Здесь программист получает возможность не просто создавать программный
код, но и наглядно (визуально) показывать системе, что бы он хотел
увидеть.
Технология визуального программирования позволяет строить
интерфейс7 будущей программы из специальных компонентов, реализующих нужные свойства. Количество таких компонентов достаточно
велико. Каждый из них содержит готовый программный код и все
необходимые для работы данные, что избавляет программиста от создания того, что уже создано ранее.
6 Это субъективный совет авторов.
7 Интерфейс – диалог, обмен информацией.

21

Рисунок 1.5: Окно Geany c шаблоном программы на Free Pascal

22

Подобный подход во много раз сокращает время написания программы. Кроме того, быстрота создания программного кода в Lazarus
достигается за счет того, что значительная часть текста формируется
автоматически.
Среда визуального программирования Lazarus сочетает в себе
компилятор, объектно-ориентированные средства визуального программирования и различные технологии, облегчающие и ускоряющие
создание программы.
1.4.1 Установка Lazarus в ОС Linux
Для установки Lazarus в окне Synaptic (см. рис. 1.1) необходимо
щелкнуть по кнопке Найти. В появившемся окне поиска (см. рис. 1.9)
вводим имена необходимых программ (Lazarus, fpc, fpc-source) и щелкаем по кнопке Найти.
Менеджер программ находит программы Lazarus и Free Pascal,
после чего в Lazarus, fpc, fpc-source для установки (с помощью
контекстного меню или с помощью кнопки Отметить для обновления) и начинает установку, щелкнув по кнопке Применить. После
этого Synaptic предложит установить еще несколько пакетов, которые
необходимы для установки Lazarus. Надо соглашаться. После этого
начнется процесс скачивания файлов пакетов и установки Lazarus на
компьютер. После установки запуск программы осуществляется с помощью команды меню Программирование — Lazarus8.
Можно начинать работать. В старых версиях операционной системы Linux (например, Ubuntu 8.10 и более ранних) при запуске
Lazarus вместо русских пунктов меню появятся непонятные символы.
Подробно о том, как добиться правильного отображения символов кириллицы в меню Lazarus, описано на следующих страницах:
http://www.freepascal.ru/article//lazarus/20080316091540/,
http://forum.sources.ru/index.php?showtopic=243159,
http://forum.ubuntu.ru/index.php?topic=18539.0;all.
Кроме того, можно использовать и запуск с английским интерфейсом командой терминала LANG=C startlazarus.
Но, на взгляд авторов, наиболее универсальным и простым методом добиться корректного отображения символов кириллицы будет
следующий.
8 Не исключено, что вызов Lazarus в других дистрибутивах Linux можно осуществлять и с помощью
другой команды главного меню.

23

Рисунок 1.6: Окно Geany c текстом программы на языке Free Pascal

24

Рисунок 1.7: Окно терминала с результатами работы программы

Рисунок 1.8: Окно Установить включения
и аргументы для Free Pascal

Рисунок 1.9: Окно поиска пакета
Lazarus для установки

25

1. Запускаем Lazarus c английским интерфейсом с правами администратора9.
2. Выполняем команду Tools — Conigure «Build — Lazarus»... .
В открывшемся окне Conigure «Build — Lazarus» на вкладке Quick
Build Options устанавливаем следующие параметры компиляции
Build Options — Build All, LCL interface — IDE — gtk2 (betta), после чего щелкаем по кнопке Build и ждем, пока произойдет перекомпиляция среды Lazarus с новыми параметрами.
3. После этого запускаем Lazarus из меню (или из терминала командой startlazarus) и видим корректную русскоязычную среду
Lazarus.
Конечно, для установки Lazarus можно не использовать менеджер
пакетов Synaptic, а самостоятельно скачать все необходимые пакеты с
сайта http://sourceforge.net/project/showfiles.php?group_id=89339 и затем их вручную установить. Подробно процесс ручной установки
можно
найти
в
Интернете,
например
на
странице
http://freepascal.ru/article//lazarus/20080316091540.
1.4.2 Установка Lazarus под управлением ОС Windows
Рассмотрим особенности установки среды визуального программирования Lazarus для операционной системы Windows. Перед установкой необходимо скачать установочный файл со страницы загрузки
http://sourceforge.net/project/showfiles.php?group_id=89339. Установка
Lazarus на компьютер осуществляется с помощью ряда окон Мастера
установки. Для того чтобы Мастер установки начал свою работу,
необходимо запустить программу установки Lazarus Setup. Появится
диалоговое окно (рис. 1.10), в котором пользователь может выбрать из
списка язык для дальнейшего диалога с Мастером установки. Нажатие кнопки ОК приведет к появлению следующего окна10.
Следующее окно (рис. 1.11) информационное. Оно сообщает
пользователю о начале процесса установки. Здесь кнопка Далее приведет к следующему шагу Мастера установки, кнопка Отмена прервет процесс установки приложения.
9 В Ubuntu команда будет такой sudo LANG=C startlazarus
10 В этом и во всех последующих окнах использование кнопки Отмена приведет к прерыванию работы Мастера установки.

26

Рисунок 1.10: Окно Мастера установки.
Выбор языка.
На следующем этапе (рис. 1.12) необходимо выбрать путь для
установки Lazarus. По умолчанию программа будет установлена на
диск С. Для выбора иного пути для установки следует воспользоваться кнопкой Обзор. Щелчок по кнопке Далее приведет к следующему
шагу процесса установки11.

Рисунок 1.11: Начало процесса установки
Lazarus

11 В этом и во всех последующих окнах с помощью кнопки Назад можно вернуться к предыдущему
шагу Мастера установки.

27

Рисунок 1.12: Окно выбора пути для установки Lazarus
Следующий шаг – это выбор необходимых компонентов из полного перечня средств системы (рис. 1.13). По умолчанию будут установлены все компоненты системы. Отменить установку компонента
можно, если щелчком мыши убрать метку рядом с его именем. Кнопка Далее продолжает процесс установки. В следующих окнах Мастера установки пользователь сможет выбрать папку меню Пуск, в которой будет создан ярлык для устанавливаемого приложения 12, и создать на рабочем столе ярлык для приложения Lazarus13.
Далее Мастер установки сообщит о том, куда будет установлено
приложение Lazarus, каков тип установки, какие компоненты системы
были выбраны, где будет создан ярлык и будет ли создан значок на рабочем столе. После этого начнется процесс установки приложения на
компьютер. Контролировать инсталляцию приложения пользователь
может с помощью линейного индикатора, а прервать – кнопкой Отмена. Завершается процесс установки щелчком по кнопке Завершить.
Запуск Lazarus можно осуществить из главного меню командой
Пуск — Программы — Lazarus — Lazarus.
12 По умолчанию ярлык создается в меню Пуск — Программы.
13 С помощью щелчка мыши установить метку в поле рядом с командой Создать значок на рабочем столе.

28

Рисунок 1.13: Окно выбора компонентов для
установки приложения
1.4.3 Среда Lazarus
На рис. 1.15 показано окно, которое появится после запуска
Lazarus. В верхней части этого окна размещается главное меню и панель инструментов. Слева расположено окно инспектора объектов, а
справа окно редактора исходного кода. Если свернуть или сдвинуть
окно редактора, то станет доступным окно формы, представленное на
рис. 1.14.

Рисунок 1.14: Окно формы

29

Рисунок 1.15: Среда визуального программирования Lazarus

30

Работу над программой в среде визуального программирования
условно можно разбить на две части. Первая это создание внешнего
вида (интерфейса) будущей программы, вторая — написание программного кода. Итак, инспектора объектов и окно формы нужны
для создания интерфейса программы, а редактор исходного кода —
для работы с ее текстом. Файлы, из которых в результате получается
программа, называют проектом.
1.4.4 Главное меню Lazarus
Все команды, необходимые для работы в среде визуального программирования Lazarus, содержатся в главном меню. Доступ к командам главного меню осуществляется одинарным щелчком левой
кнопкой мыши.
Работа с файлами в среде Lazarus осуществляется при помощи
пункта меню Файл. Команды этого пункта меню можно разбить на
группы:
• создание новых файлов – Создать модуль, Создать форму, Создать...;
• загрузка ранее созданных файлов – Открыть, Открыть недавнее,
Вернуть;
• сохранение файлов – Сохранить, Сохранить как…, Сохранить
все;
• закрытие файлов – Закрыть, Закрыть все файлы редактора;
• вывод на печать – Печать…;
• перезагрузка среды – Перезапуск;
• выход из среды – Выход.
Команды, предназначенные для редактирования текста программного кода, собраны в меню Правка. В основном это команды
характерные для большинства текстовых редакторов:
• команды отмены или возврата последней операции – Отменить,
Вернуть;
• команды переноса, копирования и вставки выделенного фрагмента
текста в буфер – Вырезать, Копировать, Вставить;
• команды, работающие с выделенным блоком текста – Сдвинуть
блок вправо, Сдвинуть блок влево;
• команды смены регистра – Верхний регистр выделения, Нижний
регистр выделения;
• команды выделения фрагмента текста собраны в пункте меню Выделить.

31

Далее будут перечислены специфические команды редактора программного кода Lazarus.
Команда Закомментировать добавляет в начале каждой строки
выделенного фрагмента два символа «косая черта», что превращает
выделенный текст в комментарий14, команда Раскомментировать
выполняет обратное действие.
Команда Заключить выделение в... приводит к открытию диалогового окна (рис. 1.16), в этом окне пользователь может выбрать
конструкцию языка программирования, в которую будет заключен выделенный фрагмент текста.
Команда Сортировка выбранного... открывает диалоговое окно,
в котором можно установить параметры сортировки текста в выделенном фрагменте.

Рисунок 1.16: Выбор конструкции языка для заключения в нее выделенного фрагмента программного кода
Команды меню Поиск можно разделить на группы. Первая группа — это непосредственно команды поиска и замены, вторая - это команды перехода, а третья — работа с закладкой. В четвертой группе
объединены команды поиска, замены и перехода в выделенном фрагменте. Большинство из этих команд используются в текстовых редакторах, смысл остальных понятен из названия.
Пункт меню Просмотр применяют для настройкивнешнего вида
14 Комментарий — фрагмент программного кода, который игнорируется компилятором. Обычно комментарии используют для пояснений к программе или для временного исключения фрагментов
текста при отладке.

32

среды программирования. Первая группа команд открывает или активизирует следующие окна:
• Инспектор объектов — окно, с помощью которого можно описать
внешний вид и поведение выделенного объекта (подробно см. п.
1.4.8);
• Редактор исходного кода — окно, в котором можно создавать и редактировать текст программы (подробно см. п. Ошибка: источник
перекрестной ссылки не найден);
• Обозреватель кода — содержит общую информацию о проекте;
• Редактор LazDoc — редактор шаблонов;
• Браузер кода — окно проводника проекта.
Следующая группа команд пункта меню Просмотр тоже открывает диалоговые окна. Эти окна носят информационный характер. Так
команды Модуль... и Форма... выводя список модулей и форм данного проекта. Назначение команд Показать зависимости модулей и
Показать сведения о модуле говорят сами за себя. Последняя команда этой группы Переключить модуль/форму активизирует либо
окно редактора, либо форму.
В последней группе команд следует отметить команды Показать
палитру компонентов и Показать кнопки быстрого доступа. Устанавливая метки рядом с этими командами, пользователь выводит на
экран или наоборот убирает панели инструментов. Командой Окна
отладки пользуются во время отладки программного кода. Здесь
можно вызывать Окно наблюдений, Окно отладчика, просматривать точки останова и значения переменных в процессе выполнения
программы.
Команды пункта меню Проект предназначены для выполнения
различных операций с проектом:
• команды создания проекта — Создать проект и Создать проект из
файла;
• команды вызова ранее созданного проекта — Открыть проект,
Открыть недавний проект, Закрыть проект;
• команды сохранения проекта — Сохранить проект, Сохранить
проект как..., Опубликовать проект;
• команды управления проектом — Инспектор проекта, Настройка
проекта..., Параметры компилятора и т.д.
Команды, позволяющие запускать проект на выполнение и выполнять его отладку, содержатся в пункте главного меню Запуск:

33

Собрать — сборка программы из откомпилированных файлов;
• Собрать все — скомпоновать все файлы проекта;
• Быстрая компиляция — компиляция файлов программы;
• Запуск — запуск проекта с помощью отладчика (компиляция,
компоновка и выполнение);
• Пауза — приостановка выполнения программы до нажатия любой
клавиши;
• Шаг с входом — режим пошагового отладочного выполнения программы с входом в вызываемые процедуры и функции;
• Шаг в обход — режим пошагового отладочного выполнения программы без входа в вызываемые процедуры и функции;
• Запуск до курсора - отладка и выполнение программы в этом режиме осуществляются до оператора, стоящего в строке помеченной
курсором;
• Останов — прерывание выполнения программы;
• Сброс отладчика - сброс всех ранее задействованных отладочных
средств и прекращение выполнения программы;
• Настройка сборки+запуска... - настройка параметров компоновки
и запуска;
• Вычислить\Изменить - возможность просмотреть значение переменной и/или найти значение выражения в процессе выполнения
программы, при необходимости можно изменить значения любой
переменной;
• Добавить наблюдения — в открывающемся окне можно указать
переменные и/или выражения, за изменением значений которых следует понаблюдать при отладке программы;
• Добавить точку останова - установка в текущей строке контрольной точки; после запуска программного кода отладчик прекратит его
выполнение перед оператором, помеченным точкой останова; в программе можно указать произвольное количество таких точек. Точку
останова также можно добавить щелчком мыши по номеру строки
программного кода.
Работа с компонентами15 организована при помощи команд
пункта меню Компоненты. Пункты меню Инструменты и Окружение применяют для настройки свойств среды программирования.


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

34

Работа с окнами в Lazarus выполняется при помощи пункта
меню Окна. Названия команд этого пункта совпадают с названиями
окон, и выбор любой команды приведет к активации соответствующего окна.
Пункт меню Справка это справочная информация о системе.
Здесь можно вызывать средства справочной системы и выполнять ее
настройку.
1.4.5 Окно формы
Окно формы (рис. 1.14) — это проект интерфейса будущего программного продукта.
Вначале это окно содержит только стандартные элементы – строку заголовка и кнопки развертывания, свертывания и закрытия. Рабочая область окна заполнена точками координатной сетки16.
Задача программиста – используя панель компонентов, заполнить
форму различными интерфейсными элементами, создавая тем самым
внешний вид своей программы.
Команды настройки окна формы находятся на вкладке Редактор
форм (рис. 1.17) в меню Окружение — Настройки окружения...
1.4.6 Окно редактора Lazarus
Окно редактора (рис. 1.15) тесно связано с окном формы
(рис. 1.18) и появляется вместе с ним при создании нового проекта.
Окно редактора по умолчанию находится на первом плане и закрывает окно формы. Переключаться между этими окнами можно командой Просмотр - Переключить модуль/форму, клавишей F12 или
просто щелчком мыши.
Окно редактора предназначено для создания и редактирования
текста программы, который создается по определенным правилам и
описывает некий алгоритм. Если окно формы определяет внешний
вид будущей программы, то программный код, записанный в окне редактора, отвечает за ее поведение.
Вначале окно редактора содержит текст, обеспечивающий работу
пустой формы. Этот программный код появляется в окне редактора
автоматически, а программист в ходе работы над проектом вносит в
него дополнения, соответствующие функциям программы.
16 Координатная сетка отображается только на этапе создания программы.

35

Рисунок 1.17: Настройка окна формы

Рисунок 1.18: Окно формы и окно редактора

36

Обратите внимание, что при загрузке Lazarus автоматически загружается последний проект, с которым работал пользователь. Происходит это благодаря установке Открывать последний проект при
запуске (рис. 1.19, 1.20), которая находится на вкладке Файлы меню
Окружение — Настройки окружения.... Если убрать метку рядом с
командой Открывать последний проект при запуске, то при загрузке Lazarus будет создавать новый проект.
Настроить окно редактора можно с помощью вкладки Общие
меню Окружение — Настройки редактора...(рис. 1.21). Для того
чтобы установить (отменить) ту или иную настройку, достаточно
установить (убрать) маркер рядом с ее названием и подтвердить изменения нажатием кнопки Ok.

Рисунок 1.19: Окно настройки файлов в среде Windows

37

Рисунок 1.20: Окно настройки файлов в Linux

Рисунок 1.21: Настройки окна редактора

38

На вкладке Дисплей меню Окружение — Настройки редактора...(рис. 1.22) можно изменить шрифт текста программного кода.

Рисунок 1.22: Окно настройки редактора программного кода, вкладка Дисплей
Для корректного отображения символов кириллицы в окне редактора кода под управлением Ubuntu Linux необходимо в окне настроек
редактора в поле Шрифт редактора установить тип шрифта — Fixed
Misc, после чего выбрать кодировку ISO 10646-1 (рис. 1.23).
Как и в большинстве текстовых редакторов, в редакторе программного кода Lazarus предусмотрена работа с шаблонами. Здесь
под шаблоном подразумевается автоматический ввод конструкций
языка программирования.
Например, пользователь вводит символ b, затем символ пробел, а
на экране появляется конструкция begin ... end. Настройку шаблонов можно выполнить в диалоговом окне (рис. 1.24, 1.25), которое
появится после выполнения команды Окружение — Шаблоны
кода.... Например, чтобы заработал рассмотренный шаблон, нужно

39

Рисунок 1.23: Настройка кириллицы в ОС Ubuntu

Рисунок 1.24: Окно настройки шаблонов редактора
программного кода в среде Windows

40

выбрать (щелкнуть по нему мышкой) в списке шаблонов строку b begin ... end и установить маркер рядом с командой Включить
макросы. Затем в группе команд Автозавершение при обнаружении... включить флажок возле слова пробела. Если среди команд автозавершения выбрать конец строки, то шаблон будет появляться в
тексте программы после ввода символа b и нажатия клавиши Enter.
Шаблоны можно добавлять, удалять и править. Для этого в окне
Шаблоны кода (рис. 1.25) предусмотрены специальные кнопки. В
нижней части окна, над кнопками Ok и Отмена, расположено поле
ввода и редактирования шаблонов с активным курсором.

Рисунок 1.25: Окно настройки шаблонов редактора
программного кода в среде Linux
Если выделить любой шаблон из списка, щелкнув по нему мышкой, то в поле ввода появится соответствующая конструкция. Если
воспользоваться кнопкой Добавить, то появится диалоговое окно
(рис. 1.26) для создания шаблона. Здесь в поле Элемент следует указать символ или группу символов, ввод которых будет связан с создаваемым шаблоном.

41

В поле Комментарий можно дать краткое описание шаблона и
нажать кнопку Добавить. Элемент и комментарий к нему будут добавлены в список шаблонов в окне Шаблоны кода. Теперь нужно создать сам шаблон, то есть указать, какая именно конструкция языка
появится при вводе элемента в текст программы.

Рисунок 1.26: Окно создания
шаблона
Для этого надо выделить вновь созданный шаблон и в поле ввода,
расположенном в нижней части окна Шаблоны кода, ввести соответствующий текст. Например, создадим шаблон для конструкции
repeat ... until, которая будет добавлена в текст, если пользователь введет символ r. Выполним следующие действия:
• щелкнем по кнопке Добавить в окне Шаблоны кода;
• в диалоговом окне Добавить шаблон кода (рис. 1.26) в поле
Элемент введем символ r, а в поле Комментарий фразу
repeat until и нажмем кнопку Добавить;
• в окне Шаблоны кода (рис. 1.27, 1.28) выделим в списке шаблонов строку r - repeat until;
• введем в поле ввода, расположенном в нижней части окна,
конструкцию языка repeat until;;
• нажмем кнопку Ok в окне Шаблоны кода.
Для изменения шаблона служит кнопка Правка. Шаблон, который нужно откорректировать, должен быть выделен. Дальнейшие
действия аналогичны тем, которые выполняются при создании шаблона.
Для того чтобы удалить шаблон из списка, его нужно выделить, а
затем нажать кнопку Удалить.

42

Рисунок 1.27: Создание шаблона в Windows

Рисунок 1.28: Создание шаблона в Linux

43

1.4.7 Панель компонентов
Панель компонентов расположена17 под главным меню (рис.
1.15). Она состоит из большого числа групп, в которых располагаются
соответствующие компоненты (рис. 1.29).

Рисунок 1.29: Панель компонентов
Компонент – это некий функциональный элемент интерфейса,
обладающий определенными свойствами. Размещая компоненты на
форме, программист создает внешний вид своей будущей программы
– окна, кнопки, переключатели, поля ввода и т.п.
Для внедрения нового компонента на форму нужно сделать два
щелчка мышкой:
• в панели компонентов, для выбора компонента;
• в рабочем пространстве формы, для указания положения левого
верхнего угла компонента.
Компоненты объединяются в группы по функциональному признаку. После создания проекта по умолчанию открывается список
группы Standard, содержащий основные элементы диалоговых окон.
Просмотреть другие группы можно, раскрывая их щелчком по соответствующей вкладке.
1.4.8 Инспектор объектов
Окно инспектора объектов располагается слева от окна редактирования. Как правило, оно содержит информацию о выделенном
объекте. На рис. 1.30 представлен инспектор объектов с информацией
о вновь созданной форме. Окно инспектора объектов имеет три
вкладки: Свойства, События, Избранное. Эти вкладки используются для редактирования свойств объекта и описания событий, на которые будет реагировать данный объект. Совокупность свойств отображает внешнюю сторону объекта, совокупность событий – его поведение.
Вкладки инспектора объектов представляют собой таблицу. В левой колонке расположены названия свойств или событий, в правой –
конкретные значения свойств или имена подпрограмм, обрабатывающих события. Чтобы выбрать свойство или событие, необходимо щелкнуть левой кнопкой мыши по соответствующей строке.
17 Включить (выключить) Панель компонентов можно, установив (убрав) маркер рядом с командой
Показать палитру компонентов меню Просмотр.

44

Свойства, отображенные в таблице, могут быть простыми или
сложными. Простые свойства определены единственным значением.
Например, свойство Caption (Заголовок) определяется строкой символов, свойства Height (Высота) и
Width (Ширина) – числом, свойство
Enabled (Доступность) – значениями
True (Истина) и False (Ложь). Сложные свойства определяются совокупностью значений. Например, свойство
Font (Шрифт). Слева от имени этого
свойства стоит знак «+». Это означает,
что свойство сложное, и при щелчке по
значку «+» откроется список его соРисунок 1.30: Окно
ставляющих.
инспектора объектов
Активизировать значение любого свойства можно обычным
щелчком мыши. При этом в конце строки может появиться либо кнопка с символом троеточия, либо кнопка со стрелкой, направленной
вниз. Щелчок по троеточию откроет диалоговое окно для установки
значений сложных свойств (например, Font). Обращение к стрелке
приведет к раскрытию списка возможных значений простого свойства
(например, Enabled).
1.4.9 Первая программа в Lazarus
Процесс создания программы в Lazarus состоит из двух этапов:
формирование внешнего вида программы, ее интерфейса и написание
программного кода на языке программирования Free Pascal, заставляющего работать элементы интерфейса.
Как мы уже выяснили, для создания интерфейса программы существует окно формы, а для написания программного кода – окно редактора. Эти окна тесно связаны между собой, и размещение компонентов на форме приводит к автоматическому изменению программного кода.
Начнем знакомство с визуальным программированием с создания
простой программы про кнопку, которая хочет, чтобы по ней щелкнули. После чего появляется сообщение о работе программы.
Начнем с создания нового проекта. Для этого выполним команду

45

главного меню Проект — Создать проект.... В появившемся диалоговом окне (рис. 1.31, 1.32) выберем из списка слово Приложение и
нажмем кнопку Создать. Результатом этих действий будет появление
окна формы и окна редактора программного кода.

Рисунок 1.31: Создание нового
проекта в Linux

Рисунок 1.32: Создание нового проекта в среде Windows

Сохраним созданный проект, воспользовавшись командой
Проект — Сохранить проект как…. Откроется окно сохранения
программного кода Сохранить Unit1 (рис. 1.33, 1.34). Создадим в
нем новую папку Primer_1 (можно воспользоваться кнопкой Создание новой папки (Создание каталога)), откроем ее и щелкнем по
кнопке Сохранить. Тем самым мы сохраним файл Unit1.pas, содержащий текст программы.
Сразу же откроется окно Сохранить проект (рис. 1.35, 1.36), в
котором также необходимо щелкнуть по кнопке Сохранить.
Теперь мы сохранили файл Project118, содержащий общие сведения о проекте.
На самом деле все наши манипуляции привели к сохранению более чем двух файлов. Теперь в каталоге Primer_1 (рис. 1.37, 1.38)
хранится файл с текстом программы Unit1.pas, файл Unit1.lfm19, со
сведениями о форме Form1, а также файлы Project1.lpn и
Project1.lpi, содержащие настройки системы программирования и параметры конфигурации проекта.
18 Имена Unit1 и Project1 могут быть любыми другими.
19 Имена файлов можно задать и отличные от стандартных Unit1.

46

Рисунок 1.33: Сохранение файла в Windows

Рисунок 1.34: Сохранение файла в Linux

47

Рисунок 1.35: Сохранение проекта в
Windows

Рисунок 1.36: Сохранение проекта в
Linux

48

Рисунок 1.37: Файлы проекта в Windows

Рисунок 1.38: Файлы проекта в Linux
Итак, проект сохранен. Все дальнейшие изменения будем сохранять командой Проект - Сохранить проект.
Теперь можно приступить к визуальному программированию. У
нас есть один объект – форма Form1. Изменим некоторые его свойства с помощью инспектора объектов. Перейдем в окно инспектора
объектов и найдем там свойство Caption (Заголовок). По умолчанию это свойство имеет значение Form1. Изменим его на слово ПРИ-

49

МЕР 1 (рис. 1.39). Это изменение сразу же отразится на форме – в
поле заголовка появится надпись – ПРИМЕР 1 (рис. 1.40). Аналогично можно изменить размеры формы, присвоив новые значения свойствам Height (Высота) и Width (Ширина), еще проще это сделать,
изменив положение границы формы с помощью кнопки мыши, как
это делается со всеми стандартными окнами.

Рисунок 1.39: Изменение свойства формы
Рисунок 1.40: Изменение
Caption
заголовка формы
Изменим еще одно свойство формы – Position (Положение
формы на экране). Значения этого свойства не вводятся вручную, а
выбираются из списка (рис. 1.41). Если выбрать свойство
poScreenCenter, то форма всегда будет появляться в центре
экрана.
Напомним, что мы пишем программу про кнопку. Пришло время
поместить ее на форму. Для этого обратимся к панели компонентов
(рис. 1.29) и найдем там компонент Tbutton. Чтобы разместить
компонент на форме, нужно сделать два щелчка мышкой: первый —
по компоненту, второй — по окну формы. В результате форма примет
вид, представленный на рис. 1.42.
Теперь у нас два объекта: форма Form1 и кнопка Button1. Напомним, что изменения значений свойств в окне инспектора объектов
относятся к выделенному объекту. Поэтому выделим объект
Button1 и изменим его заголовок Caption и размеры Height,
Width. В заголовке напишем фразу «Щелкни мышкой!», установим
ширину 135 пикселей, а высоту – 25 пикселей. Сохраним проект
(Проект — Сохранить проект).

50

Рисунок 1.41: Изменение свойства
формы Position

Рисунок 1.42: Размещение кнопки на форме

Для того чтобы посмотреть, как работает наша программа, ее
необходимо запустить на выполнение. Сделать это можно командой
Запуск — Запуск, функциональной клавишей F9 или кнопкой
Запуск в панели инструментов (рис. 1.43). Созданное окно с кнопкой
должно выглядеть, как на рис. 1.44.

Рисунок 1.43:
Кнопка Запуск в
панели инструментов Lazarus

Рисунок 1.44: Результат
работы программы

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

51

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms,
Controls,
Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
initialization
{$I unit1.lrs}
end.
О назначении всех перечисленных в листинге команд мы поговорим позже. Вернемся к программе и подумаем, что же мы хотим от
нашей кнопки. Скорее всего, это должна быть реакция на какое-то событие, например, на щелчок мыши. После запуска программы на
экране появилось окно, на котором расположена кнопка с надписью
«Щелкни мышкой!». Предположим, что если мы щелкнем по ней, она
«обрадуется» и сообщит: «УРА! ЗАРАБОТАЛО!».
Для воплощения этой идеи завершим работу программы, закрыв
окно с кнопкой обычным способом (щелчком по крестику в правом
верхнем углу) и перейдем в режим редактирования. Убедимся в том,
что объект кнопка Button1 выделен, и обратимся к вкладке События инспектора объектов. Напомним, что здесь расположены описания событий. Выберем событие OnClick – обработка щелчка мыши
и дважды щелкнем в поле справа от названия (рис. 1.45).
В результате описанных действий в окне редактора появиться
следующий текст:

52

procedure TForm1.Button1Click(Sender: TObject);
begin
end;
На данном этапе изложения материала данный текст – это фрагмент программного кода, именуемый подпрограммой. О назначении этой подпрограммы можно догадаться по ее имени
TForm1.Button1Click: на форме
Form1 для объекта кнопка Button1 обрабатывается событие «щелчок мыши»
Click. Все команды, написанные между словами begin и end, будут выполРисунок 1.45: Выбор со- няться при наступлении указанного события OnClick
бытия.
Теперь установим курсор между словами begin и end созданной подпрограммы и напишем:
Button1.Caption:='УРА! ЗАРАБОТАЛО!';
Эта запись означает изменение свойства кнопки. Только теперь
мы выполнили его не с помощью инспектора объектов, а записав оператор языка программирования. Прочитать его можно так: присвоить
(:=) свойству Caption объекта Button1 значение 'УРА! ЗАРАБОТАЛО!'. Поскольку присваиваемое значение – строка, оно заключено в одинарные кавычки. Теперь, текст подпрограммы в окне редактора имеет вид:
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Caption:='УРА! ЗАРАБОТАЛО!';
end;
Сохраним созданную программу, запустим ее на выполнение и убедимся, что кнопка реагирует на щелчок мыши (рис. 1.46).
Закрыть проект можно командой
Проект — Закрыть проект.
Рисунок 1.46: Окончательный результат работы программы

53

1.4.10 Полезная программа
Итак, первая программа написана. Она не несет особой смысловой нагрузки. Главная ее задача – показать, что же такое визуальное
программирование. Следующая программа также будет несложной,
но полезной. Мы автоматизируем процесс перевода старой русской
меры веса в современную. Эта задача формулируется так: выполнить
перевод пудов и фунтов в килограммы, если известно, что 1 пуд = 40
фунтам = 16.38 кг.
Итак, наша программа должна позволить пользователю ввести
два числа (пуды и фунты) и после щелчка по кнопке сообщить, каково
значение в килограммах.
Создадим новый проект, выполнив команду Проект — Создать
проект..., и сохраним его в папке Primer_2 командой Проект —
Сохранить проект как...
Воспользуемся вкладкой Standard панели компонентов и разместим на форме следующие компоненты. Четыре объекта типа надпись Label. Этот компонент используется для размещения в окне не
очень длинных однострочных надписей. Два поля ввода Edit. Это
редактируемое текстовое поле, предназначенное для ввода, отображения или редактирования одной текстовой строки. И одну кнопку
Button. Этот компонент обычно используют для реализации некоторой команды. Компоненты должны располагаться на форме примерно
так, как показано на рис. 1.47.

Рисунок 1.47: Конструирование
формы

54

В первой надписи будет храниться текст «Меры веса». Две надписи Label2 и Label3 нужны для пояснения того, какие именно данные должны вводиться, надпись Label4 понадобится для вывода результата.
В поля ввода Edit1 и Edit2 будут введены конкретные значения: вес в пудах и фунтах.
Вычисление веса в килограммах произойдет при щелчке по кнопке Button1 и будет выведено в Label4.
Изменим свойства формы и размещенных на ней компонентов в
соответствии с табл. 1.1-1.4.
Таблица 1.1 Значение свойств формы
Свойство
Значение
Caption
Перевод из старой русской меры
веса в современную
Height
230
Width
400
Font.Name Arial
Font.Size 10

Описание свойства
Заголовок формы
Высота формы
Ширина формы
Название шрифта
Размер шрифта

Таблица 1.2. Свойства компонентов типа надпись
Свойство Label1 Label2 Label3 Label4 Описание свойства
Caption Меры пуды
фунты В кило- Заголовок компоненвеса
грамта
мах:
Height 15
15
15
15
Высота компонента
Width
60
30
35
85
Ширина компонента
Top
20
50
105
25
Координата верхнего
края
Left
25
115
115
200
Координата
левого
края

55

Таблица 1.3. Свойства компонентов поле ввода
Свойство
Edit1
Edit2
Описание свойства
Text
пробел
пробел
Текст в поле ввода
Height
25
25
Высота компонента
Width
135
135
Ширина компонента
Top
40
95
Координата верхнего края
Left
175
175
Координата левого края
Таблица 1.4. Свойства компонента кнопка
Свойство
Значение
Описание свойства
Caption
ВЫЧИСЛИТЬ
Текст на кнопке
Height
25
Высота компонента
Left
200
Ширина компонента
Top20
150
Координата верхнего края
Width
80
Координата левого края
После всех изменений форма будет иметь вид, представленный на
рис. 1.48.

Рисунок 1.48: Изменение свойств
формы и ее компонентов
Интерфейс программы готов. Займемся вычислительной частью
задачи. Для этого создадим для кнопки Button1 обработчик событий OnClick, для чего дважды щелкнем по объекту Button1 левой
кнопкой мыши. Между словами begin и end созданной подпрограм20 Свойства Top и Left определяют расположение компонента относительно верхнего левого угла
формы.

56

мы запишем несколько команд, чтобы получился следующий программный код:
procedure TForm1.Button1Click(Sender: TObject);
var
pud, funt: integer; kg: real;
begin
pud:=StrToInt(Edit1.Text);
funt:=StrToInt(Edit2.Text);
kg:=pud*16.38+funt*16.38/40;
Label4.Caption:='В килограммах:
'+FloatToStr(kg);
end;
Рассмотрим программный код построчно.
Строка 1. Заголовок подпрограммы. Он состоит из ключевого слова procedure и имени подпрограммы TForm1.Button1Click, а
в скобках обычно указывают список параметров подпрограммы, если
таковые имеются.
Строка 2. Открывает блок описания переменных (var – от
variable переменная);
Строка 3. Описывает переменные pud и funt. Компьютер понимает эту запись как команду выделить в памяти место для хранения
двух целых чисел21.
Строка 4. Описывает одной вещественной переменной kg.
Строка 5. Начинает программный блок (begin – начало).
Строка 6. Команда, выполняющая следующие действия. Из свойства Text поля ввода Edit1 считывает введенную туда информацию. Эта информация воспринимается компилятором как строка текста (например, '360' – это строка из трех символов), а поскольку нам
для вычислений нужны числовые значения, то функция StrToInt
преобразовывает ее в целое число. Результат этих преобразований записывается в память компьютера под именем pud. Символы «:=»
обозначают оператор присваивания. Например, запись a:=3.14 читается так: переменной a присвоить значение 3.14. Выражение
3.14:=a не имеет смысла.
Строка 7. Информация из поля ввода Edit2 преобразовывается в
целое число и записывается в переменную funt. Фактически ко21 О переменных и их типах подробнее рассказывается в следующей главе.

57

манды, записанные в шестой и седьмой строках, осуществляют ввод
исходных данных.
Строка 8. Вычисляется значение выражения, результат которого
присваивается переменной kg. Обратите внимание, что умножение
здесь обозначается звездочкой, деление – наклонной чертой, сложение – знаком «+». Записывая математическое выражение на языке
программирования, нужно четко указывать все операции. Нельзя,
например, опустить знак умножения, как это принято в математике.
Строка 9. Изменяет свойство Caption объекта Label4. В него
будет помещен текст, состоящий из двух строк. Первая – 'В килограммах:', вторая значение переменной kg. Знак «+» в этом выражении применяют для конкатенации (слияния) строк. Кроме того, поскольку значение переменной kg – вещественное число, оно преобразовывается в строку функцией FloatToStr. Фактически в этой
строке был выполнен вывод результатов.
Строка 10. Конец программного блока (end – конец).
Теперь наша программа может быть откомпилирована и запущена
на выполнение. Процесс компиляции представляет собой перевод программы с языка программирования в машинные коды. Для компиляции нужно выполнить команду Запуск — Быстрая компиляция. Во
время компиляции проверяется наличие синтаксических ошибок. В
случае их обнаружения процесс компиляции прерывается. Мы специально допустили ошибку в восьмой строке программного кода (пропустили двоеточие в операторе присваивания). Результат компиляции
программы с синтаксической ошибкой показан на рис. 1.49. Строка с
ошибкой выделена красным цветом, а под окном редактора появилось
окно Сообщение22, в котором описана допущенная ошибка. Ошибку
нужно исправить, а программу еще раз откомпилировать.
После успешной компиляции всех файлов, входящих в проект,
необходимо собрать (скомпоновать) проект из объектных (откомпилированных) файлов (с расширением .о — для Linux, .obj — для
Windows). Для этого следует выполнить команду Запуск — Собрать
или воспользоваться комбинацией клавиш Ctrl+F9.
В результате компоновки будет сгенерирован выполнимый файл,
имя которого совпадает с именем проекта.
22 Если окно Сообщение отсутствует, его можно вывести на экран командой Просмотр — Сообщения.

58

Рисунок 1.49: Сообщение об ошибке в программе
Вообще говоря, если команду Запуск — Быстрая компиляция
опустить, а сразу выполнить команду Запуск — Собрать, то произойдет и компиляция всех файлов проекта и его компоновка.
После успешной компиляции и сборки программу нужно сохранить (Проект - Сохранить) и запустить.
Запуск осуществляется из среды разработки (Запуск - Запуск)
или выполнением файла, Linux — ./project1, в Windows —
projec1.exe. На рис. 1.50 показаны результаты работы нашей программы.
Обратите внимание, что
ошибки могут возникать и
после запуска программы.
Например, в нашем примере
исходные данные – целые
числа. Если ввести дробь,
появится аварийное сообщение. В подобной ситуации
следует прервать выполнеРисунок 1.50: Результат работы ние программы командой
Запуск—Останов (Ctrl+F2).
программы

59

Вернуться к созданному проекту, например с целью его усовершенствования, несложно. Нужно выполнить команду Проект —
Открыть проект… (Ctrl+F11), перейти к папке с проектом и выбрать из списка файл с расширением .lpi (в нашем случае — project1.lpi).
1.4.11 Консольное приложение среды Lazarus
В Lazarus можно создавать не только визуальные приложения с
графическим интерфейсом, но и писать программы на Free Pascal в
текстовом режиме. Для этого существует консольное приложение.
Чтобы создать новое консольное приложение, нужно выполнить команду Проект — Создать проект..., в появившемся диалоговом окне
(рис. 1.31, 1.32) выбрать фразу Программа пользователя и нажать
кнопку Создать.
На экране появится
окно редактора программного кода (рис. 1.51), в котором уже представлена
общая структура программы на языке Паскаль.
В общем виде программа на языке Free
Pascal состоит из заголовка программы, раздела
описаний и непосредРисунок 1.51: Окно редактора в кон- ственно тела программы.
сольном приложении
Заголовок программы состоит из ключевого слова program и
имени программы. В нашем случае (рис. 1.51) это Project1. Имя
было присвоено программе автоматически. При желании его можно
изменить.
Раздел описаний обычно включает в себя описание констант, типов, переменных, процедур и функций. На рис. 1.51 видно, что раздел
описаний начинается со слова uses. Это раздел подключения модулей. Модуль — это специальная программа, которая расширяет возможности языка программирования. В нашем случае происходит подключение модуля SysUtils, который позволяет работать с файлами
и каталогами, и модуля Classes, который работает с компонентами.

60

За разделом описаний следует исполняемая часть программы, или
тело программы. Оно начинается со служебного слова begin и заканчивается служебным словом end и точкой. Тело программы содержит операторы языка, предназначенные для реализации поставленной
задачи.
Кроме того в тексте программы могут встречаться комментарии.
Комментарий — это текст, заключенный в фигурные скобки или начинающийся с двух наклонных. Этот текст не является программным
кодом, а носит информационный характер. Например, в нашем случае
текст заключенный в фигурные скобки, сразу после описания модулей
сообщает пользователю о том, что остальные элементы языка он может добавить самостоятельно.
Рассмотрим пример. Пусть нужно решить задачу перевода градусной меры угла в радианную. Эта задача известна из школьного курса и формулируется так: чтобы найти радианную меру какого-нибудь
угла по данной градусной мере, нужно умножить число градусов на


180 , число минут на 180⋅60 и найденные произведения сложить.
Текст программы для решения поставленной задачи в консольном
приложении будет иметь вид:
program Project1;
{$mode objfpc}{$H+}
uses
Classes, SysUtils
{ you can add units after this };
var
gradus,minuta:integer; radian: real;
begin
write('gradus=');
readln(gradus);
write('minuta=');
readln(minuta);
radian:=gradus*pi/180+minuta*pi/(180*60);
writeln('radian=', radian);
end.
Сохранить, открыть, откомпилировать, скомпоновать и запустить на выполнение программу в консольном приложении можно
так же, как в визуальном проекте.

61

Результаты работы нашей программы будут иметь вид:
gradus=165
minuta=30
radian=2.8885199120506E+000
Нетрудно заметить, что к тексту, созданному автоматически, мы
добавили описание переменных (все используемые в программе переменные должны быть описаны):
Var
//Описаны две целочисленные переменные.
gradus,minuta:integer;
//Описана вещественная переменная.
radian: real;
и тело программы:
begin
//Начало тела программы.
//Вывод на экран строки символов gradus=
write('gradus=');
//Ввод переменной gradus.
readln(gradus);
//Вывод на экран символов minuta=.
write('minuta=');
//Ввод переменной minuta.
readln(minuta);
//Вычисление.
radian:=gradus*pi/180+minuta*pi/(180*60);
//Вывод результата вычислений.
writeln('radian=', radian);
end. //Конец программы.
Так как в этой программе графический интерфейс отсутствует,
мы разработали элементарный текстовый диалог компьютер — пользователь. Для этого были использованы операторы ввода (read) и
вывода (write) данных.
1.4.12 Операторы ввода - вывода данных
Ввод информации с клавиатуры осуществляется с помощью оператора read. Он может иметь один из следующих форматов:
read (x1, x2, …, xn); readln (x1, x2, …, xn);
где x1, x2, …, xn – список вводимых переменных. При вводе вещественных значений целую и дробную часть числа следует разделять
точкой.

62

Когда в программе встречается оператор read, ее действие приостанавливается до тех пор, пока не будут введены исходные данные.
При вводе числовых значений два числа считаются разделенными,
если между ними есть хотя бы один пробел, символ табуляции или
конца строки (Enter). После ввода последнего значения следует нажать Enter.
Оператор readln аналогичен оператору read, разница заключается в том, что после считывания последнего в списке значения для
одного оператора readln данные для следующего оператора
readln будут считываться с начала новой строки. Но следует помнить, что Enter переведет курсор на новую строку независимо от
того, как именно происходит считывание данных.
Для вывода информации на экран служат операторы write и
writeln. В общем случае эти операторы имеют вид:
write(x1, x2, …, xn); writeln(x1, x2, …, xn);
где x1, x2, …, xn представляют собой список выводимых переменных, констант, выражений. Если элемент списка — текстовая информация, ее необходимо взять в кавычки.
Операторы write и writeln последовательно выводят все
переменные. Если используется оператор writeln, то после вывода
информации курсор перемещается в новую строку.
Итак, в нашем примере оператор write('gradus='); выводит
на экран символы gradus=, которые подсказывают пользователю,
что он должен ввести значение переменной gradus, а оператор
readln(gradus); предназначен для ввода значения переменной
gradus. Оператор writeln('radian=', radian); выводит на
экран два значения: строку radian= и значение переменной
radian.
Как правило, вещественные данные выводятся в формате с плавающей точкой # . # # # # # # # # # # # E ± # # #, где # - любая десятичная цифра от 0 до 9. Для того чтобы перейти к формату с фиксированной точкой нужно, число, расположенное до символа E, умножить на 10, возведенное в степень, значение которой указано после
числа E. Например,
0.35469000000Е-01=0.35469000000*10-1=0.035469,
-5.43286710000Е+02=-5.43286710000*102=-543.28671.

63

Чтобы выводить числа в формате с фиксированной точкой, необходимо использовать форматированный вывод. Для этого оператор
write или writeln нужно задать следующим образом:
write(идентификатор:ширина_поля_вывода:дробная_часть);
где
идентификатор — это имя переменной, которая будет выводится на экран;
ширина_поля_вывода — количество позиций (целая часть,
точка, дробная часть), которое будет занимать значение переменной
при выводе;
дробная_часть — количество позиций, необходимых для
дробной части числа.
Например, пусть результат работы нашей программы имеет вид
gradus=165
minuta=30
radian=2.8885199120506E+000
Понятно, что оператор writeln('radian=', radian); вывел
на экран значение переменной radian в формате с плавающей точкой.
Если воспользоваться оператором
writeln('radian=', radian:5:3);
то результат работы программы будет таким:
gradus=165
minuta=30
radian=2.889
где значение переменной radian представлено в формате с фиксированной точкой (все число занимает пять позиций и три из них после
запятой).

64

2 Общие сведения о языке программирования

Free Pascal
В этой главе читатель познакомится со структурой проекта в среде Lazarus и основными элементами языка программирования Free
Pascal: переменными, константами, их типами, основными операциями и функциями языка.
2.1 Структура проекта Lazarus
Любой проект в Lazarus – это совокупность файлов, из которых
создается единый выполняемый файл. В простейшем случае список
файлов проекта имеет вид:
•файл описания проекта (.lpi);
•файл проекта (.lpr);
•файл ресурсов (.lrs);
•модуль формы (.lfm);
•программный модуль (.pas);
После компиляции программы из всех файлов проекта создается
единый выполняемый файл, имя этого файла совпадает с именем
проекта.
Программный модуль, или просто модуль, – это отдельно компилируемая программная единица, которая представляет собой набор
типов данных, констант, переменных, процедур и функций. Любой
модуль имеет следующую структуру:
unit имя_модуля;
//Заголовок модуля.
interface
//Раздел описаний.
implementation
//Раздел реализаций.
end.
//Конец модуля.
Заголовок модуля – это зарезервированное слово unit, за которым следует имя модуля и точка с запятой. В разделе описаний, который открывается служебным словом interface, описывают программные элементы – типы, классы, процедуры и функции:
interface
uses список_модулей;
type список_типов;

65

const список_констант;
var список_переменных;
procedure имя_процедуры;

function имя_функции;

Раздел implementation содержит программный код, реализующий механизм работы описанных программных элементов (тексты
процедур обработки событий, процедуры и функции, созданные программистом). Процедуры и функции в Lazarus также построены по модульному принципу23.
Наряду с визуальными приложениями, Lazarus позволяет разрабатывать и обычные консольные приложения, которые также могут
быть созданы в оболочке Free Pascal, и в текстовом редакторе Geany.
Авторы настоятельно рекомендуют начинать изучение программирования именно с создания консольных приложений. Поэтому рассмотрим подробно структуру консольного приложения.
2.2 Структура консольного приложения
Структура консольного приложения имеет вид:
заголовок программы;
uses modul1, modul2, …, moduln;
раздел описаний;
тело программы.
Заголовок программы состоит из служебного слова program, имени программы, образованного по правилам использования идентификаторов (см. п. 2.3 ), и точки с запятой, например:
program my_prog001;
Предложение uses modul1, modul2, …, moduln предназначено для подключения модулей. В модулях находятся функции и
процедуры языка. Для использования функций и процедур, находящихся в модуле, необходимо в тексте программы подключить их с помощью предложения uses.
Раздел описаний включает следующие подразделы:
раздел описания констант;
раздел описания типов;
раздел описания переменных;
23 Подробно о процедурах и функциях см. в главе 4.

66

раздел описания процедур и функций.
В языке Free Pascal должны быть описаны все переменные, типы,
константы, которые будут использоваться программой. В стандартном
языке Pascal порядок следования разделов в программе жестко установлен, во Free Pascal такого строгого требования нет. В программе
может быть несколько разделов описания констант, переменных и т.д.,
но все они должны быть до тела программы. Более подробно структуру консольной программы на языке Free Pascal можно представить
следующим образом:
program имя_программы;
uses modul1, modul2, …, moduln;
const описания_констант;
type описания_типов;
var описания_переменных;
begin
операторы_языка;
end.
Тело программы начинается со слова begin, затем следуют операторы языка Pascal, реализующие алгоритм решаемой задачи. Операторы в языке Pascal отделяются друг от друга точкой с запятой и могут располагаться в одну строчку или начинаться с новой строки (в
этом случае их также необходимо разделять точкой с запятой). Назначение символа « ; » - отделение операторов друг от друга. Тело программы заканчивается служебным словом end. Несмотря на то что
операторы могут располагаться в строке как угодно, рекомендуется
размещать их по одному в строке, а в случае сложных операторов отводить для каждого несколько строк. Рассмотрим более подробно
структуру программы:
program имя_программы;
uses modul1, modul2, …, moduln;
const описания_констант;
type описания_типов;
var описания_переменных;
begin
оператор_1;
оператор_2;
...
end.

67

Приведем пример текста программы на Free Pascal:
program one;
const a=7;
var b,c: real;
begin
c:=a+2; b:=c-a*sin(a)
end.
2.3 Элементы языка
Программа на языке Free Pascal может содержать следующие
символы:
•латинские буквы A, B, C…, x, y, z;
•цифры 0, 1, 2…, 9;
•специальные символы + ,–, /, =, , [, ], ., (, ), ;, :, {, }, $, #, _, @,
‘, ^.
Из символов алфавита формируют ключевые слова и идентификаторы. Ключевые слова – это зарезервированные слова, которые имеют
специальное значение для компилятора. Примером ключевых слов являются операторы языка, типы данных и т.п. Ключевые слова используются только так, как они определены при описании языка. Идентификатор – это имя программного объекта 24, представляющее собой
совокупность букв, цифр и символа подчеркивания. Первый символ
идентификатора – буква или знак подчеркивания, но не цифра. Идентификатор не может содержать пробел. Прописные и строчные буквы
в именах не различаются, например ABC, abc, Abc – одно и то же
имя. Каждое имя (идентификатор) должно быть уникальным и не совпадать с ключевыми словами.
В тексте программы можно использовать комментарии. Комментарий это текст, который компилятор игнорирует. Комментарии используют для пояснений программного кода или для временного отключения команд программного кода при отладке. Комментарии бывают однострочные и многострочные. Однострочный комментарий
начинается с двух символов «косая черта» // и заканчивается символом перехода на новую строку. Многострочный комментарий заключен в фигурные скобки {} или располагается между парами символов
(* и *). Понятно, что фигурные скобки {} или символы (* и*)
24 К программным объектам относятся константы, переменные, метки, процедуры, функции, модули и
программы.

68

можно использовать и для однострочного комментария.
Например:
{Комментарий может
выглядеть так!}
(*Или так.*)
//А если вы используете такой способ,
//то каждая строка должна начинаться
//с двух символов «косая черта».
2.4 Данные в языке Free Pascal
Для решения задачи в любой программе выполняется обработка
каких-либо данных. Они хранятся в памяти компьютера и могут быть
самых различных типов: целыми и вещественными числами, символами, строками, массивами. Типы данных определяют способ хранения чисел или символов в памяти компьютера. Они задают размер
ячейки, в которую будет записано то или иное значение, определяя
тем самым его максимальную величину или точность задания. Область памяти (ячейка), в которой хранится значение определенного
типа, называется переменной. У переменной есть имя (идентификатор), тип и значение. Имя служит для обращения к области памяти, в
которой хранится значение. Во время выполнения программы значение переменной можно изменить. Перед использованием любая переменная должна быть описана. Описание переменной в языке Free
Pascal осуществляется с помощью служебного слова var:
var имя_переменной: тип_переменной;
Если объявляется несколько переменных одного типа, то описание выглядит следующим образом:
var переменная_1,…,переменная_N: тип_переменных;
Например:
var
//Объявлена целочисленная переменная.
ha: integer;
//Объявлены две вещественные переменные.
hb, c: real;
Константа – это величина, которая не изменяет своего значения
в процессе выполнения программы. Тип константы определяется ее
значением. Описание константы имеет вид:
const имя_константы = значение;

69

Например:
const
h=3;
//Целочисленная константа.
bk=-7.521; //Вещественная константа.
c='abcde'; //Символьная константа.
Рассмотрим основные типы данных.
2.4.1 Символьный тип данных
Данные символьного типа в памяти компьютера всегда занимают
один байт. Это связано с тем, что обычно под величину символьного
типа отводят столько памяти, сколько необходимо для хранения одного символа.
Описывают символьный тип с помощью служебного слова char.
Например:
var
c: char;
В тексте программы значения переменных и константы символьного типа должны быть заключены в апострофы: 'а', 'b', '+'.
2.4.2 Целочисленный тип данных
Целочисленные типы данных могут занимать в памяти компьютера один, два, четыре или восемь байт. Диапазоны значений данных
целочисленного типа представлены в табл. 2.1.
Таблица 2.1 Целочисленные типы данных
Тип
Диапазон
Размер
Byte
0 .. 255
1 байт
Word
0 .. 65535
2 байта
LongWord
0 .. 4294967295
4 байта
ShortInt
-128 .. 127
1 байт
Integer
-2147483648 .. 2147483647
4 байта
LongInt
-2147483648 .. 2147483647
4 байта
Smallint
-32768 .. 32767
2 байта
Int64
–263 .. 263
8 байт
Cardinal
0 .. 4294967295
4 байта
Описание целочисленных переменных в программе может быть
таким:

70

var
b: byte;
i, j: integer;
W: word;
L_1, L_2: longint;
2.4.3 Вещественный тип данных
Внутреннее представление вещественного числа в памяти
компьютера отличается от представления целого числа. Оно представлено в экспоненциальной форме mE ± p, где m – мантисса (целое или
дробное число с десятичной точкой), p – порядок (целое число)25.
Чтобы перейти от экспоненциальной формы к обычному представлению числа26, необходимо мантиссу умножить на десять в степени порядок. Например:
–36.142Е + 2 = –36.142∙102 = –3614.2;
7.25E – 5 = 7.25∙10–5 = 0.0000725.
Вещественное число в Pascal может занимать от четырех до десяти байтов. Диапазоны значений вещественного типа представлены в
табл. 2.2.
Таблица 2.2 Вещественные типы данных
Тип
Диапазон
Количество
Размер
значащих
цифр
Single
1.5Е-45 .. 3.4E+38
7—8
4 байта
Real
2.9E-39 .. 1.7E+38
15 — 16
8 байтов
Double
5.0Е-324 .. 1.7E+308
15 — 16
8 байтов
Extended 3.4Е-4932 .. 3.4E+4932
19 — 20
10 байтов
Comp
-263 .. 263
19 — 20
8 байтов
Currency -922337203685477.5808 .. 19 — 20
8 байтов
922337203685477.5807
Примеры описания вещественных переменных:
var
r1, r2: real; D: double;
25 Действия над числами, представленными в экспоненциальной форме, называют арифметикой с плавающей точкой, так как положение десятичной точки меняется в зависимости от порядка числа.
26 Число в обычном его представлении называют числом с фиксированной точкой.

71

2.4.4 Тип дата-время
Тип данных дата-время TDateTime предназначен для одновременного хранения даты и времени. В памяти компьютера он занимает
восемь байтов и фактически представляет собой вещественное число,
где в целой части хранится дата, а в дробной – время.
2.4.5 Логический тип данных
Данные логического типа могут принимать только два значения:
истина (true) или ложь (false). В стандартном языке Pascal был
определен лишь один логический тип данных – boolean. Логические типы данных, определенные в среде Lazarus, представлены в
табл. 2.3.
Таблица 2.3 Логические типы данных
Тип
Размер
Boolean
1 байт
ByteBool
1 байт
WordBool
2 байтa
LongBool
4 байтa
Пример объявления логической переменной:
var
FL: boolean;
2.4.6 Создание новых типов данных
Несмотря на достаточно мощную структуру встроенных типов
данных, в среде Lazarus предусмотрен механизм создания новых типов. Для этого используют служебное слово type:
type новый_тип_данных = определение_типа;
Когда новый тип данных создан, можно объявлять соответствующие
ему переменные:
var список_переменных: новый_тип_данных;
Применение этого механизма мы рассмотрим в следующих параграфах.
2.4.7 Перечислимый тип данных
Перечислимый тип задается непосредственным перечислением
значений, которые он может принимать:
var имя_переменной:(знач_1,знач_2,…,знач_N);
Такой тип может быть полезен, если необходимо описать данное, которое принимает ограниченное число значений. Например:

72

var
animal: (fox, rabbit);
color: (yellow, blue, green);
Применение перечислимых типов делает программу нагляднее:
//Создание нового типа данных – времена года.
type
year_times = (winter, spring, summer, autumn);
//Описание соответствующей переменной.
var yt: year_times;
2.4.8 Интервальный тип
Интервальный тип задается границами своих значений внутри
базового типа:
var имя_переменной: мин_знач .. макс_знач;
Обратите внимание, что в данной записи два символа точки
рассматриваются как один, поэтому пробел между ними не допускается. Кроме того, границы диапазона могут быть только целого или
символьного типов и левая граница диапазона не должна превышать
правую. Например:
var
date: 1..31;
symb: ’a’..’h’;
Применим механизм создания нового типа данных:
type
//Создание перечислимого типа данных –
//дни недели.
Week_days = (Mo, Tu, We, Th, Fr, Sa, Su);
//Создание интервального типа данных –
//рабочие дни.
Working_days = Mo.. Fr
//Описание соответствующей переменной.
var
days: Working_days;
2.4.9 Структурированные типы
Структурированный тип данных характеризуется множественностью образующих его элементов. В языке Free Pascal это массивы,
строки, записи, множества и файлы.
Массив – совокупность данных одного и того же типа 27. Число
27 Подробно о массивах см. в главе 5.

73

элементов массива фиксируется при описании типа и в процессе выполнения программы не изменяется. Для описания массива используют ключевые слова array … of:
имя: array [список_индексов] of тип_данных;
где:
•имя – любой допустимый идентификатор;
•тип_данных – любой тип языка.
•список индексов – перечисление диапазонов изменения номеров элементов массива; количество диапазонов совпадает с количеством измерений массива; диапазоны отделяются друг от друга запятой, а границы диапазона, представляющие собой интервальный тип
данных, отделяют друг от друга двумя символами точки:
[индекс1_начальный..индекс1_конечный,
индекс2_начальный..индекс2_конечный, …, ]
Например:
var
//Одномерный массив из 10 целых чисел.
a:array [1..10] of byte;
//Двумерный массив вещественных чисел
//(3 строки, 3 столбца).
b:array [1..3, 1..3] of real;
Еще один способ описать массив – создать новый тип данных.
Например, так:
type
//Объявляется новый тип данных –
//трехмерный массив целых чисел.
massiv=array [0..4, 1..2, 3..5] of word;
//Описывается переменная соответствующего типа.
var
M: massiv;

Для доступа к элементу массива достаточно указать его порядковый номер, а если массив многомерный (например, таблица), то
несколько номеров:
имя_массива[номер_элемента]
Например: a[5], b[2, 1], M[3, 2, 4].
Строка – последовательность символов. В Lazarus строка трактуется как массив символов, то есть каждый символ строки пронумерован, начиная с единицы.

74

При использовании в выражениях строка заключается в апострофы. Описывают переменные строкового типа так:
имя_переменной: string;
или:
имя_переменной: string[длина_строки];
Например:
const S=’СТРОКА’;
var
Str1: string;
Str2: string[255];
Stroka: string[100];
Если при описании строковой переменной длина строки не указывается, это означает, что она составляет 255 символов. В приведенном примере строки Str1 и Str2 одинаковой длины.
Запись28 – это структура данных, состоящая из фиксированного
количества компонентов, называемых полями записи. В отличие от
массива поля записи могут быть разного типа. При объявлении типа
записи используют ключевые слова record … end:
имя_записи = record список_полей end;
здесь, имя_ записи – любой допустимый идентификатор, список_полей – описания полей записи. Например:
//Описана структура записи.
//Каждая запись содержит информацию
//о студенте и состоит из двух полей –
//имя и возраст.
type
student = record
name: string;
age: byte;
end;
var
//Объявлены соответствующие переменные –
//три объекта типа запись.
a, b, c: student;
Доступ к полям записи осуществляется с помощью составного
имени:
имя_записи.имя_поля
28 Подробно о структурах см. в главе .

75

Например:
a.name:=’Ivanov Ivan’;
a.age:=18;
b.name:=a.name;
Оператор присоединения with имя_записи do упрощает доступ к полям записи:
with a do
begin
name:=’Petrov Petr’;
age:=19;
end;
Множество – это набор логически связанных друг с другом
объектов. Количество элементов множества может изменяться от 0 до
255. Множество, не содержащее элементов, называется пустым. Для
описания множества используют ключевые слова set of:
имя_множества = set of базовый_тип_данных;
Например:
type TwoNumbers = set of 0..1;
var
Num1, Num2, Num3: TwoNumbers;
29
Файл – это именованная область внешней памяти компьютера.
Файл содержит компоненты одного типа (любого типа, кроме
файлов). Длина созданного файла не оговаривается при его объявлении и ограничивается только емкостью диска, на котором он хранится. В Lazarus можно объявить типизированный файл:
имя_файловой_переменной = file of тип_данных;
бестиповый файл:
имя_файловой_переменной = file;
и текстовый файл:
имя_файловой_переменной = TextFile;
Например:
var
f1: file of byte;
f2: file;
f3: TextFile;
2.4.10 Указатели
Как правило, при обработке оператора объявления переменной
имя_переменной: тип_переменной
29 Подробно о файлах см. в главе 7 .

76

компилятор автоматически выделяет память под переменную
имя_переменной в соответствии с указанным типом. Доступ к объявленной переменной осуществляется по ее имени. При этом все обращения к переменной заменяются адресом ячейки памяти, в которой
хранится ее значение. При завершении подпрограммы, в которой
была описана переменная, память автоматически освобождается.
Доступ к значению переменной можно получить иным способом – определить собственные переменные для хранения адресов памяти. Такие переменные называют указателями.
Указатель30 – это переменная, значением которой является адрес
памяти, где хранится объект определенного типа (другая переменная).
Как и любая переменная, указатель должен быть объявлен. При объявлении указателей всегда указывается тип объекта, который будет
храниться по данному адресу:
var имя_переменной: ^тип;
Такие указатели называют типизированными. Например:
var p: ^integer;
//По адресу, записанному в переменной p
//будет храниться переменная типа int
//или, другими словами p, указывает
//на тип данных integer.
В языке Free Pascal можно объявить указатель, не связанный с каким-либо конкретным типом данных. Для этого применяют служебное слово pointer:
var имя_переменной: pointer;
Например:
var x, y: pointer;
Подобные указатели называют нетипизированными и используют
для обработки данных, структура и тип которых меняется в процессе
выполнения программы, то есть динамически.
2.5 Операции и выражения
Выражение задает порядок выполнения действий над данными и
состоит из операндов (констант, переменных, обращений к
функциям), круглых скобок и знаков операций, например

a+b*sin(cos(x)).
30 Подробно об указателях см. 5.11

77

В табл. 2.4 представлены основные операции языка программирования Free Pascal.
Таблица 2.4. Основные операции языка Free Pascal
ОпеДействие
Тип операндов
Тип результата
рация
+
сложение
целый/веществен- целый/вещественный
ный
+
сцепление строк
строковый
строковый

вычитание
целый/веществен- целый/вещественный
ный
*
умножение
целый/веществен- целый/вещественный
ный
/
деление
целый/веществен- вещественный
ный
div целочисленное деление целый
целый
mod остаток от деления
целый
целый
not отрицание
целый/логический целый/логический
and логическое И
целый/логический целый/логический
or
логическое ИЛИ
целый/логический целый/логический
xor исключающее ИЛИ
целый/логический целый/логический
shl сдвиг влево
целый
целый
shr сдвиг вправо
целый
целый
in
вхождение в множество множество
логический
<
меньше
числовой/символь- логический
ный/логический
>
больше
числовой/символь- логический
ный/логический
=
больше или равно
числовой/символь- логический
ный/логический
=
равно
числовой/символь- логический
ный/логический

не равно
числовой/символь- логический
ный/логический

78

В сложных выражениях порядок, в котором выполняются операции, соответствует приоритету операций. В языке Free Pascal приняты
следующие приоритеты:
1.
not.
2.
*, /, div, mod, and, shl, shr.
3.
+, –, or, xor.
4.
=, , >, =, , >=, =, 0 then
begin
//Если N>0 и K=0, поступил 1-й
//положительный элемент, предположим,
//что он минимальный Min=N, соответственно
//количество минимумов равно 1.
if k=0 then
begin
k:=1;
min:=N;
end
//Если элемент не первый, сравниваем
//его с предполагаемым минимумом, если
//элемент меньше, записываем его в Min.
//Соответственно количество
//минимумов равно 1.
else if N 0 do
begin
cifra_kol:=cifra_kol+1;
M:=M div 10;
end;
end;
//Функция возвращает значение истина,
//если число M,
//состоящее из kol цифр палиндром,
//и значение ложь в противном случае.
function palindrom(M:longint;kol:byte):boolean;
var i:byte; j:longint;
begin
j:=1;
//Возведение числа 10 в степень kol-1
//(разрядность числа).
for i:=1 to kol-1 do
j:=j*10;
palindrom:=true; //Пусть число - палиндром.
for i:=1 to kol div 2 do
begin
//Выделение старшего разряда M div j
//(первая цифра).
//Выделение младшего разряда M mod 10
//(последняя цифра).
//Если первая и последняя цифры не совпадают,
if M div j M mod 10 then
begin
//то число не палиндром.
palindrom:=false;
break;
//выход из цикла.
end;
//Изменение числа
//Удаление 1-й цифры числа
M:=M-(M div j)*j;

176

//Удаление последней цифры числа.
M:=M div 10;
/Уменьшение разрядности.
j:=j div 100;
/
end;
end;
//Основная программа.
var X:longint; pr:boolean;
begin
//Ввод элемента последовательности.
write('X=');readln(X);
//Пусть в последовательности нет палиндромов.
pr:=false;
while X0 do //Пока не ноль,
begin
if palindrom(X,cifra_kol(X)) then
begin
pr:=true; //Найдено число палиндром,
break;
//досрочный выход из цикла.
End;
//Ввод следующего элемента последовательности.
write('X=');readln(X);
end;
if pr then writeln('Последовательность
содержит число-палиндром.')
else writeln('Последовательность не содержит
палиндромов.');
end.
4.5 Решение задач с использованием подпрограмм
В этом разделе мы рассмотрим задачи с несложными алгоритмами, но больше внимания уделим их интерфейсу в среде Lazarus.
ЗАДАЧА 4.5. Создать программу, которая автоматизирует процесс перевода градусной меры угла в радианную и наоборот, в зависимости от выбора пользователя. То есть пользователь должен выбрать, как он будет вводить угол, в радианах или в градусах. Введет в
радианах, ответ получит в градусах и, соответственно, введет в градусах, ответ получит в радианах.

177

С точки зрения математика задача не вызывает сложности:
•чтобы найти радианную меру какого-нибудь угла по данной градусной его мере, нужно умножить число градусов на
минут - на


, число секунд - на
180⋅60


180⋅60⋅60


, число
180

и найденные

произведения сложить;
•чтобы найти градусную меру угла по заданной радианной нужно
умножить число радиан на

180
; если из полученной дроби выде

лить целую часть, то получим градусы; если из числа полученного
умножением оставшейся дробной части на 60, выделить целую часть
получим минуты; секунды вычисляются аналогично из дробной части
минут.
Для перевода угла из градусной меры в радианную создадим
функцию
function gradus_radian(gradus,minuta,secunda:byte):real;

в которую будем передавать целочисленные значения градусов, минут
и секунд. Результат работы функции – вещественное число, величина
угла в радианах.
Задачу перевода из радианной меры в градусную решим, создав
процедуру
procedure radian_gradus(radian:real;
var gradus,minuta,secunda:byte);
у которой один входной параметр – радианная мера угла и три выходных – градусы, минуты и секунды.
Разработаем интерфейс будущей программы в среде Lazarus. Создадим новый проект, установим свойства формы так, как показано в
табл. 4.1, и разместим на ней компоненты в соответствии с рис. 4.2.
Таблица 4.1. Свойства формы
Свойство
Значение
Описание
свойства
Caption
Величина угла
Заголовок формы
Height
265
Высота формы
Width
325
Ширина формы
BorderIcons.BiMaximize false
Кнопка развертывания окна недоступна

178

Свойство

Значение

Описание
свойства
BorderStyle
bdDialog
Стиль рамки – диалоговое окно, не
изменяет размеры
Position
poScreenCenter Окно появится в
центре экрана
С компонентами Edit, Label
и Button мы уже хорошо знакомы.
Компонент RadioButton
– это переключатель. Его используют для выбора одного из
нескольких взаимоисключающих решений. Обычно на форму помещается, по меньшей
мере, два таких компонента.
Они могут иметь только два состояния, определяемых свойРисунок 4.1: Настройка форством Checked. Если у одного
мы к задаче 4.5
из компонентов это свойство
истинно true, то во всех остальных ложно false. В данной задаче
используется два компонента RadioButton1 и RadioButton2,
предоставляя пользователю выбор: включен первый компонент – будет осуществлен перевод из градусной меры в радианную, включен
второй – наоборот. Двойной щелчок по компоненту RadioButton1
приведет к созданию процедуры TForm1.RadioButton1Click
обработки события «Щелчок мыши по кнопке переключателя». В тексте процедуры следует указать команды, которые будут выполняться,
если пользователь включил или выключил компонент.
Нам уже известно, что свойства компонентов могут изменяться
как в окне конструирования формы, так и непосредственно в программе. Если дважды щелкнуть по форме, вне размещенных на ней
компонентов, то будет создана процедура TForm1.FormCreate обработки события открытия формы. На вкладке События инспектора

179

объектов это событие носит название OnCreate. В процедуре
TForm1.FormCreate можно задать свойства всех компонентов на
момент открытия формы.
Кнопки, расположенные на форме, несут следующую функциональную нагрузку:
•Button1 запускает процесс перевода в зависимости от установок переключателей;
•Button3 возвращает внешний вид формы в первоначальное состояние (до ввода и вывода данных);
•Button2 – завершает процесс выполнения программы.
Текст программы с необходимыми комментариями приведен
ниже. Результаты работы программы представлены на рис. 4.4 и рис.
4.5.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
Edit1: TEdit;
Button2: TButton;
Label2: TLabel;
Edit2: TEdit;
Edit3: TEdit;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Edit4: TEdit;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure RadioButton1Click(Sender: TObject);
procedure RadioButton2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);

180

procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке ВЫЧИСЛИТЬ.
procedure TForm1.Button1Click(Sender: TObject);
//Функция перевода данных из градусов
//в радианы.
function gradus_radian
(gradus,minuta,secunda:byte):real;
begin
gradus_radian:=
gradus*pi/180+minuta*pi/180/60+
secunda*pi/180/60/60;
end;
//Процедура перевода из радиан в градусы.
procedure radian_gradus(radian:real;
var gradus,minuta,secunda:byte);
begin
gradus:=trunc(radian*180/pi);
minuta:= trunc((radian*180/pi-gradus)*60);
secunda:=trunc(((radian*180/pigradus)*60-minuta)*60);
end;
var
grad,min,sec:byte;
rad:real;

//Описание переменных.
//Градусная мера угла.
//Радианная мера угла.

181

//Контроль ввода.
kod_g,kod_m,kod_s,kod_r:integer;
begin
//Если первый переключатель вкл.
if RadioButton1.Checked then
begin
Val(Edit1.Text,grad,kod_g);
//Ввод градусов.
Val(Edit2.Text,min,kod_m);
//Ввод минут.
Val(Edit3.Text,sec,kod_s);
//Ввод секунд.
//Если ошибки при вводе не было, то
if (kod_g=0) and (kod_m=0) and (kod_s=0) then
begin
//сделать видимым компонент Label2
Label2.Visible:=true;
//и вывести туда результат вычислений.
//Вызов функции gradus_radian
//перевода из градусов в радианы.
Label2.Caption:='Величина угла ' +chr(13)+
FloatToStrF(gradus_radian(grad,min,sec),
ffFixed,8,6)+' радиан';
end
else
//Иначе выдать сообщение об ошибке при вводе.
MessageDlg('Ошибка при вводе данных!',
MtWarning,[mbOk],0);
end;
//Если второй переключатель вкл.
if RadioButton2.Checked then
begin
//Ввод радианной меры угла.
Val(Edit4.Text,rad,kod_r);
//Если нет ошибок при вводе, то
if (kod_r=0)then
begin
//сделать видимым компонент Label2
Label2.Visible:=true;
//и вывести туда результат вычислений.
//Вызов процедуры перевода из радиан в градусы.

182

radian_gradus(rad,grad,min,sec);
Label2.Caption:='Величина угла' +chr(13)
+IntToStr(grad)+' г '+IntToStr(min)
+' м '+IntToStr(sec)+' с';
end
else
//Иначе выдать сообщение об ошибке при вводе.
MessageDlg('Ошибка при вводе данных!',
MtWarning,[mbOk],0);
end;
end;
//Щелчок по кнопке ВЫХОД.
procedure TForm1.Button2Click(Sender: TObject);
begin
close;
end;
//Щелчок по кнопке ОЧИСТИТЬ.
procedure TForm1.Button3Click(Sender: TObject);
begin
//Установка свойств компонентов
//в первоначальное состояние.
Edit1.Text:='00';
Edit2.Text:='00';
Edit3.Text:='00';
Edit4.Text:='00.000';
Label1.Caption:='Введите значение';
Label1.Font.Size:=10;
Label3.Caption:='Градусы';
Label4.Caption:='Минуты';
Label5.Caption:='Секунды';
Button1.Caption:='ВЫЧИСЛИТЬ';
Button2.Caption:='ВЫХОД';
Button3.Caption:='ОЧИСТИТЬ';
Edit4.Enabled:=false;
Label2.Visible:=false;
RadioButton1.Checked:=true;
RadioButton2.Checked:=false;
end;

183

//Обработка события открытие формы.
procedure TForm1.FormCreate(Sender: TObject);
begin
//Установка свойств компонентов.
Edit1.Text:='00';
Edit2.Text:='00';
Edit3.Text:='00';
Edit4.Text:='00.000';
Label1.Caption:='Введите значение';
Label1.Font.Size:=10;
Label3.Caption:='Градусы';
Label4.Caption:='Минуты';
Label5.Caption:='Секунды';
Button1.Caption:='ВЫЧИСЛИТЬ';
Button2.Caption:='ВЫХОД';
Button3.Caption:='ОЧИСТИТЬ';
Edit4.Enabled:=false;
Label2.Visible:=false;
RadioButton1.Checked:=true;
RadioButton2.Checked:=false;
end;
//Обработка события щелчок
//по переключателю RadioButton1.
procedure Tform1.RadioButton1Click(
Sender: TObject);
begin
if RadioButton1.Checked then
begin
Edit1.Enabled:=true;
Edit2.Enabled:=true;
Edit3.Enabled:=true;
Label5.Enabled:=true;
Label3.Enabled:=true;
Label4.Enabled:=true;
Edit4.Enabled:=false;
end;
end;

184

Рисунок 4.2: Перевод
Рисунок 4.3: Перевод
значений из градусной меры в
значений из радианной меры
радианную
в градусную
//Обработка события щелчок
//по переключателю RadioButton2.
procedure Tform1.RadioButton2Click(
Sender: TObject);
begin
if RadioButton2.Checked then
begin
Edit4.Enabled:=true;
Button1.Enabled:=true;
Edit1.Enabled:=false;
Edit2.Enabled:=false;
Edit3.Enabled:=false;
Label3.Enabled:=false;
Label4.Enabled:=false;
Label5.Enabled:=false;
end;
end;
end.
ЗАДАЧА 4.6. Создать программу для решения уравнений:
•линейное ax+b=0;
•квадратное ax2+bx+c=0;
•кубическое ax3+bx2+cx+d=0.

185

Решение линейного уравнения тривиально x=-b/a, алгоритмы решения квадратного и
кубического уравнений подробно рассмотрены в задачах
3.4 и 3.5.
Создадим новый проект
(рис. 4.4). Свойства формы настроим по табл. 4.1, за исключением свойства Caption,
которому присвоим значение
Решение уравнения.

Рисунок 4.4: Процесс создания
формы к задаче 4.6
Обратите внимание, что на форме появились не знакомые нам
компоненты. Это CheckBox – флажок и RadioGroup – группа
переключателей.
Компонент флажок CheckBox используется для того, чтобы
пользователь мог включить или выключить значение какого-либо параметра. Установлен флажок или нет, определяет свойство Checked
(true, false). В составе диалогового окна может быть несколько
таких компонентов, причем состояние любого из них не зависит от
состояния остальных.
Компонент группа переключателей RadioGroup объединяет в
себе несколько переключателей. Каждый размещенный в нем
переключатель помещается в специальный список Items и доступен
по номеру, установленному в свойстве ItemIndex. После размещения на форме компонент пуст. Чтобы создать в нем хотя бы один
переключатель, нужно выделить его, обратиться к инспектору объектов и выбрать свойство Items – редактор списка. Строки, набранные
в редакторе, используются как поясняющие надписи справа от
переключателей, а их количество определяет количество переключателей в группе. В нашем случае окно редактора списка будет иметь
вид, как на рис. 4.5.
После создания компонента группа переключателей его свойство
номер переключателя ItemIndex по умолчанию равно –1. Это означает, что ни один компонент в группе не установлен.

186

Рисунок 4.5: Окно редактора списка

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

С остальными компонентами, размещенными на форме, пользователь уже знаком. На рис. 4.6 - 4.8 видно, как работает программа.
Пользователю предоставляется возможность выбрать вид решаемого
уравнения, ввести его коэффициенты и указать, какие решения —
действительные или комплексные (если это возможно) — он хотел бы
получить. Далее приведен текст программного модуля с комментариями:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls,
ExtCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
Button1: TButton;

187

Button2: TButton;
RadioGroup1: TRadioGroup;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке НАЙТИ КОРНИ.
procedure TForm1.Button1Click(Sender: TObject);
//Решение линейного уравнения.
//Параметры процедуры korni_1:
//a,b — вещественные переменные,
//коэффициенты уравнения;
//x_ - строковая переменная,
//решение уравнения в символьном виде.
procedure korni_1(a,b:real;var x_:string);
//x - решение уравнения в численном виде
var x:real;
begin
x:=-b/a;
x_:=FloatToStrF(x,ffFixed,5,2);
end;
//Решение квадратного уравнения.
//Параметры процедуры korni_2:
//a,b,c — вещественные переменные,
//коэффициенты уравнения;
//x1_,x2_ - строковые переменные,
//решение уравнения в символьном виде;

188

//pr — целочисленная переменная,
//принимает значение, равное 1, если
//уравнение имеет действительные корни,
//и значение, равное 2, если корни мнимые.
procedure korni_2(a,b,c:real;
var x1_,x2_:string;var pr:byte);
//x1,x2 - решение уравнения в численном виде,
//d — дискриминант.
var d,x1,x2:real;
begin
d:=b*b-4*a*c;
if d4), то аварийно выходим из цикла (дальнейшая обработка массива бесполезна).
Блок-схема представлена на рис. 5.39.
Текст программы с комментариями приведен ниже.
const n=20;
var

258

X:array [1..n] of byte;
k,i,j:integer;
begin
for i:=1 to n do
readln(X[i]);
k:=0;
{Количество нулевых элементов.}
j:=1;
{Номер элемента в массиве Х.}
while j4 then
break
{Если k превышает 4, то выйти из цикла.}
{Иначе удаляем j-й элемент из массива.}
else
for i:=j to n-k do
X[i]:=X[i+1];
end
{ Если встретился ненулевой элемент,
то просто переходим к следующему.}
else
j:=j+1; {Если элемент ненулевой }
end;
{Вывод на печать измененного массива.}
{Количество элементов в массиве
уменьшилось на k.}
for i:=1 to n-k do
write(X[i],' ');
end.

259

n
i= 1 ,n

J4

i= 1 , n - k
i= j , n - k
Xi

X i= X

i+ 1

Конец

Рисунок 5.39: Алгоритм решения задачи 5.6
ЗАДАЧА 5.7. Найти сумму простых чисел целочисленного массива C(N).
Идея алгоритма состоит в следующем. Сначала сумма равна 0.
Последовательно перебираем все элементы, если очередной элемент
простой, то добавляем его к сумме. Для проверки, является ли число
простым, напишем функцию prostoe, которая проверяет, является
ли число простым.

260

Блок-схема этой функции представлена на рис.5.40.

Рисунок 5.40: Блок-схема функции prostoe
Заголовок функции Prostoe имеет вид:
function Prostoe(N:integer):boolean;
Функция возвращает значение true, если число N является простым. В противном случае результатом функции является значение
false. Блок–схема решения задачи 5.7 изображена на рис. 5.41.

261

Рисунок 5.41: Блок-схема решения
задачи 5.7
Далее приведен текст программы, реализующей этот алгоритм, с
комментариями.
function prostoe(N:integer):boolean;
var i:integer; pr:boolean;
begin
if N1, сейчас оборвалась серия из знакочередующихся
элементов, и количество таких серий (kol) надо увеличить на 1.
После выхода из цикла проверяем, не было ли в конце массива серии из знакочередующихся элементов. Если такая серия был (k>1), то
количество серий (kol) опять увеличиваем на 1. В завершение выводим количество серий из знакочередующихся элементов — переменную kol. Блок-схема решения задачи 5.8 представлена на рис. 5.43.
Ниже приведен текст консольного приложения на языке Free Pascal.
var
x:array[1..50] of real;
n,i,k,kol:integer;
begin
write('n=');
readln(n);
for i:=1 to n do
read(x[i]);
{Так как минимальная серия состоит
из двух элементов, }
{ k присвоим значение 1. }
k:=1; { Длина серии. }
65 Количество элементов в серии изначально равно нулю, так как после встречи в массиве первой
пары знакочередующихся элементов в серии станет сразу два элемента, а все последующие идущие подряд элементы разного знака в серии будут увеличивать длину серии на один.

264

Рисунок 5.43: Блок–схема решения задачи 5.8
kol:=0; { Количество серий в массиве. }
for i:=1 to n-1 do
{ Если при умножении двух соседних элементов

265

результат – отрицательное число,
то элементы имеют разный знак. }
if x[i]*x[i+1]1 then
kol:=kol+1;
{ Подготовить показатель продолжения серии }
{ к возможному появлению следующей серии. }
k:=1;
end;
{Проверка, не было ли серии в конце массива. }
if k>1 then
{ Если да, увеличить счетчик еще на единицу. }
kol:=kol+1;
if kol>0 then
write('Количество знакочередующихся
серий=',kol)
else
write('Знакочередующихся серий нет')
end.
ЗАДАЧА 5.9. В заданном массиве найти самую длинную серию
элементов, состоящую из единиц.
Для максимальной серии будем хранить ее длину (max), номер
последнего элемента (kon_max).
Эта задача похожа на предыдущую, отличие заключается в том,
что надо фиксировать не только тот факт, что серия кончилась, но и
саму серию. Серия может характеризоваться двумя из трех параметров: первый элемент серии, последний элемент серии, длина серии. В
связи с тем что мы фиксируем серию в момент ее окончания, в качестве параметров серии будем использовать последний элемент серии
(kon) и ее длину (k).
Алгоритм решения этой задачи следующий. Вначале количество
серий (kol) и ее длина (k) равны нулю. Перебираем последовательно

266

все элементы. Если текущий элемент равен 1, то количество элементов в серии66 увеличиваем на 1. Если текущий элемент не равен 1, то
возможны два варианта: либо сейчас оборвалась серия из единиц,
либо встретился очереной не равный единице элемент. Выбор из этих
двух вариантов можно осуществить, сравнив переменную k с единицей. Если k>1, сейчас оборвалась серия из единиц, и количество таких серий (kol) надо увеличить на 1, зафиксировать конец серии
(kon:=i-1), длину серии (dlina:=k). После этого необходимо проверить, какая по счету серия. Если это первая серия (kol=1), то объявляем ее максимальной, в переменную max записываем длину текущей серии k, в переменную kon_max — kon (последний элемент текущей серии). Если это не первая серия (kol>1), то длину текущей
серии (k) сравниваем с длиной серии максимальной длины (max). И
если k>max, то текущую серию объявляем серией максимальной длины (max:=k; kon_max:=kon;). Если встретился не равный единице элемент, надо количество элементов в серии положить равным
нулю (k:=0).
После выхода из цикла надо также проверить, не было ли в конце
серии, состоящей из единиц. Если серия была в конце, то следует обработать ее так же как и серию, которая встретилась в цикле.
Блок-схема решения задачи приведена на рис. 5.44.
Ниже приведен текст консольного приложения решения задачи.
var x:array[1..50] of integer;
n,i,k,kol,kon,max,kon_max,dlina:integer;
begin
{Ввод размера массива.}
write('n=');
readln(n);
{Ввод массива}
writeln('Массив Х');
for i:=1 to n do
read(x[i]);
{Начальное присваивание длины серии
и количества серий}
k:=0; { Длина серии. }
kol:=0; { Количество серий в массиве. }
66 Количество подряд идущих единиц.

267

Рисунок 5.44: Блок-схема решения задачи 5.9

268

{Перебираем все элементы в массиве}
for i:=1 to n do
{Если текущий элемент равен 1, то }
if x[i]=1 then
{количество подряд идущих единиц
увеличить на 1.}
k:=k+1
else
{ Если текущий элемент не равен 1, то}
begin
{ проверяем, была ли серия до этого, k>1?}
if k>1 then
{Если только что оборвалась серия, то}
begin
{увеличиваем количество серий.}
kol:=kol+1;
{Фиксируем тот факт, что на предыдущем
элементе серия закончилась,}
kon:=i-1;
{Длина серии равна k.}
dlina:=k;
{Если это первая серия,}
if kol=1 then
{объявляем ее максимальной.}
begin
{Длина максимальной серии единиц.}
max:=dlina;
{Конец максимальной серии, состоящей из
единиц, хранится в переменной kon_max.}
kon_max:=kon;
end
{Если это не первая серия,
состоящая из единиц,}
else
{то ее длину сравниваем с длиной серии
с максимальным количеством единиц.}
if k>max then
{Если длина текущей серии больше,}

269

begin
{то объявляем ее максимальной.}
max:=dlina; kon_max:=kon;
end;
end;
{Если текущий элемент массива не равен 1,
то количество подряд встречающихся единиц
начинаем считать сначала (k:=0).}
k:=0;
end;
{Проверка, не было ли серии в конце массива. }
if k>1 then
{ Если да, увеличить счетчик еще на единицу. }
begin
kol:=kol+1;
{Серия закончилась на последнем элементе}
kon:=n; dlina:=k;
{Обработка последней серии так,
как это происходило в цикле.}
if kol=1 then
begin
max:=dlina; kon_max:=kon;
end
else
if k>max then
begin
max:=dlina; kon_max:=kon;
end;
end;
{Если серии были, то}
if kol>0 then
{вывод информации о серии с максимальным
количеством единиц.}
begin
writeln('Количество серий, состоящих из
единиц=',kol);
writeln('Наибольшая серия начинается
с номера ',kon_max-max+1,', заканчивается

270

номером ', kon_max,', ее длина равна ', max)
end {Вывод информации об отсутствии серий.}
else writeln('Нет серий, состоящих из единиц')
end.
ЗАДАЧА 5.10. Задан массив вещественных чисел. Перевести все
элементы массива в p-ричную систему счисления.
Перед решением всей задачи давайте разберемся с алгоритмом
перевода вещественного числа из десятеричной в другую систему
счисления. Этот алгоритм можно разделить на следующие этапы:
1. Выделение целой и дробной частей числа.
2. Перевод целой части числа в другую систему счисления.
3. Перевод дробной части числа в другую систему счисления.
4. Объединение целой и дробной частей числа в новой системе
счисления.
Алгоритм перевода целого числа в другую систему счисления.
Разделить нацело число на основание новой системы счисления.
Получим остаток и частное. Остаток от деления будет младшим разрядом числа. Его необходимо будет умножить на 10 в нулевой степени. Если частное не равно нулю, то продолжим деление; новый остаток даст нам следующий разряд числа, который надо будет умножить
на десять в первой степени, и т. д. Деление будем продолжать до тех
пор, пока частное не станет равным 0. Особенностью алгоритма является то, что число формируется в обратном порядке от младшего
разряда к старшему, что позволит в один проход собрать число в новой системе счисления.
Алгоритм перевода дробной части числа в новую систему
счисления.
Умножить дробную часть числа на основание системы счисления.
В полученном произведении выделить целую часть числа, это будет
10−1 .
старший разряд числа, который необходимо умножить на
Дробную часть опять умножить на основание системы счисления. В
произведении целая часть будет очередным разрядом (его умножать
надо будет на 10−2 ), а дробную часть необходимо опять умножать на
основание системы счисления до получения необходимого количества
разрядов исходного числа.
Блок-схема функции перевода вещественного число N из 10-й системы счисления в другую систему представлена на рис. 5.45.

271

Рисунок 5.45: Блок-схема функции перевода вещественного числа в p-ричную систему счисления

272

Обратите внимание, как в блок-схеме и в функции реализовано
возведение в степень. В связи с тем что при переводе целой части
числа последовательно используются степени 10, начиная 0, для формирования степеней десяти, вводится переменная q, которая в начале
равна 1, а затем последовательно в цикле умножается на 10. При
переводе дробной части числа последовательно нужны отрицательные степени 10: 10−1 , 10−2 , . Поэтому при формировании дробной
части числа переменная q:=0.1, которая последовательно в цикле делится на 10.
Ниже приведен текст консольной программы решения задачи 5.10
с комментариями.
{ Функция перевода вещественного числа в p-ричную систему счисления, входные параметры функции:
вещественное число N, основание системы счисления
— целое число p, kvo — количество разрядов в дробной части формируемого числа.}
function perevod(N:real;P:word;kvo:word):real;
var i ,N1, ost: word;
s1, N2, r, s2:real;
q:real;
begin
{Если исходное число отрицательно, то для его
перевода рекурсивно обращаемся к функции perevod,
передавая в качестве параметра модуль числа.}
if N1 then {и текущий разряд меньше или
равен предыдущему, цифры в 8-м представлении числа
N
не
образуют
убывающую
последовательность
(pr:=false) и аварийно покидаем цикл.}
if tsifra1 then
{И текущий разряд меньше или равен предыдущему,
цифры в восьмеричном представлении числа N не образуют убывающую последовательность (pr:=false) и
аварийно покидаем цикл.}
if tsifraj), то элемент
находится ниже главной диагонали;
если номер столбца больше номера строки (i0 then k:=k+1;
end;
Так как при проверке диагональных элементов матрицы угловые
элементы были учтены, то при обработке элементов, расположенных
по периметру матрицы, угловые элементы учитывать не нужно.

305

Поэтому надо перебрать элементы со второго до предпоследнего в
первой и последней строках, в первом и последнем столбцах.
for i:=2 to N-1 do
begin
{ Если элемент находится в первой строке. }
if (a[1,i]>0) then
k:=k+1;
{ Если элемент находится в последней строке. }
if (a[N,i]>0) then
k:=k+1;
{ Если элемент находится в первом столбце. }
if (a[i,1]>0) then
k:=k+1;
{ Если элемент находится в последнем столбце. }
if (a[i,N]>0) then
k:=k+1;
end;
Затем надо проверить, не был ли элемент, находящийся на пересечении диагоналей, подсчитан дважды. Это могло произойти только в
том случае, если N – нечетно и элемент, расположенный на пересечении диагоналей70, положителен.
if (N mod 2 0) and (a[n div 2+1,n div 2+1]>0)
then k:=k-1;
Ниже приведен полный текст консольного приложения решения
задачи 6.4 с комментариями. На рис. 6.18 представлены результаты
работы программы решения задачи 6.4.
var
a:array [1..10,1..10] of integer;
i,j,N,k:integer;
begin
write('N=');
readln(N);
//Ввод исходной матрицы.
writeln('Введите матрицу A');
for i:=1 to N do
for j:=1 to N do
read(a[i,j]);
//Вывод исходной матрицы.
writeln('Была введена матрица A:');

70 На пересечении диагоналей находится элемент с индексами ( N div 2 +1, N div 2 +1)

306

Рисунок 6.18: Результаты решения задачи 6.4
for i:=1 to N do
begin
for j:=1 to N do
write(a[i,j],' ');
writeln;
end;
k:=0;
//Обработка элементов, расположенных
//на диагоналях матрицы.
for i:=1 to N do
begin
if (a[i,i]>0) then
k:=k+1;
if a[i,N-i+1]>0 then k:=k+1;
end;
//Обработка элементов, расположенных
//по периметру матрицы.
for i:=2 to N-1 do
begin
if (a[1,i]>0) then k:=k+1;
if (a[N,i]>0) then k:=k+1;
if (a[i,1]>0) then k:=k+1;

307

if (a[i,N]>0) then k:=k+1;
end;
{ Если элемент, находящийся на пересечении диагоналей, подсчитан дважды, то уменьшить вычисленное значение k на один. }
if (n mod 20) and (a[N div 2+1,N div 2+1]>0)
then
k:=k-1;
writeln('k=',k);
end.
ЗАДАЧА 6.5. Проверить, является ли заданная квадратная матрица единичной.
Единичной называют матрицу, у которой элементы главной диагонали – единицы, а все остальные – нули. Например,
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Решать задачу будем так. Предположим, что матрица единичная,
(pr:=true) и попытаемся доказать обратное. В двойном цикле по
строкам (i:=1,2,...,N) и по столбцам (j:=1,2,...,N) перебираем все элементы матрицы. Если диагональный элемент ( i= j ) не
равен единице или элемент, расположенный вне диагонали ( i≠ j ),
не равен нулю71, то в логическую переменную pr записываем значение false и прекращаем проверку (аварийно покидаем цикл). После
цикла проверяем значение pr, если переменная pr попрежнему равна
true, то матрица единична, иначе она такой не является.
var a:array[1..10,1..10] of real;
i,j,n:integer;
pr:boolean;
begin
writeln('Введите размер матрицы');
readln(n);
writeln('Введите матрицу');
for i:=1 to n do
71 Воспользовавшись логическими операциями and и or, это сложное условие можно записать так if
((i=j) and (a[i,j]1)) or ((ij) and (a[i,j]0)) then

308

for j:=1 to n do
read(a[i,j]);
{Предположим, что матрица единичная,
и присвоим логической переменной значение
истина. Если значение этой переменной при
выходе из цикла не изменится, это будет
означать, что матрица единичная.}
pr:=true;
for i:=1 to n do
for j:=1 to n do
if ((i=j) and (a[i,j]1)) or ((ij)
and (a[i,j]0)) then
{Если элемент лежит на главной диагонали и не
равен единице или элемент лежит вне главной диагонали и не равен нулю , то }
begin
{логической переменной присвоить значение ложь,
это будет означать, что матрица не единичная.}
pr:=false;
{ выйти из цикла. }
break;
end;
{Проверка значения логической переменной
и печать результата.}
if pr then
writeln('Матрица единичная')
else
writeln('Матрица не является единичной');
end.
ЗАДАЧА 6.6. Преобразовать исходную матрицу так, чтобы последний элемент каждого столбца был заменен разностью минимального и максимального элемента в этом же столбце.
Для решения данной задачи необходимо в каждом столбце найти
максимальный и минимальный элементы, после чего в последний
элемент столбца записать их разность. Блок-схема алгоритма решения
приведена на рис. 6.19.
Ниже приведен текст консольного приложения с комментариями.

309

Рисунок 6.19: Блок-схема алгоритма решения задачи 6.6

310

var a:array[1..25,1..25] of real;
i,j,n,m:integer;
max,min:real;
begin
{Ввод размеров матрицы.}
writeln('Введите размеры матрицы');
readln(n,m);
{Ввод исходной матрицы.}
writeln('Введите матрицу');
for i:=1 to ndo
for j:=1 to m do
read(a[i,j]);
{Последовательно перебираем все столбцы матрицы.}
for j:=1 to m do
begin
{Максимальным и минимальным объявляем первый
элемент текущего (j-го) столбца матрицы.}
max:=a[1,j];
min:=a[1,j];
{Последовательно перебираем все элементы в текущем (j-м) столбце матрицы.}
for i:=2 to n do
begin
{Если текущий элемент больше максимального, то
его и объявляем максимальным.}
if a[i,j]>max then max:=a[i,j];
{Если текущий элемент меньше минимального, то
его и объявляем минимальным.}
if a[i,j]0) and
(N0) and (M< 26) then
//то
begin
//визуализируется первая матрица,
StringGrid1.Visible:=true;
//соответствующая ей надпись,
Label4.Visible:=true;
//кнопки Очистить
Button2.Visible:=true;
//и преобразование матрицы.
Button3.Visible:=true;
with StringGrid1 do
begin
ColCount:=M+1;
RowCount:=N+1;

314

//и нумеруются строки и
for i:=1 to RowCount-1 do
Cells[0,i]:=IntToStr(i);
//столбцы первой таблицы.
for i:=1 to ColCount-1 do
Cells[i,0]:=IntToStr(i);
end;
StringGrid2.ColCount:=M+1;
StringGrid2.RowCount:=N+1;
end
else
begin
//При некорректном вводе выдается
//соответствующее сообщение.
MessageDlg('Размеры
матрицы
введены
не
верно!',MtInformation,[mbOk],0);
//Устанавливаются стартовые параметры
//в поля ввода.
Edit1.Text:='4';
Edit2.Text:='3';
end; end;
//Обработчик кнопки «Преобразование матрицы».
procedure TForm1.Button2Click(Sender: TObject);
var i,j:integer;
max,min:real;
begin
StringGrid2.Visible:=true;
label5.Visible:=true;
for i:=1 to N do
//Цикл по номерам строк.
for j:=1 to M do //Цикл по номерам столбцов.
//Считывание элементов матрицы A
//из компонента StringGrid1.
A[i,j]:=StrToFloat(StringGrid1.Cells[j,i]);
with StringGrid2 do
begin
for i:=1 to RowCount-1 do //Нумеруются
Cells[0,i]:=IntToStr(i); //строки и
//столбцы 2-й матрицы.

315

for i:=1 to ColCount-1 do
Cells[i,0]:=IntToStr(i);
end;
//Решение задачи 6.6.
for j:=1 to m do
begin
{Максимальным и минимальным объявляем первый
элемент текущего (j-го) столбца матрицы.}
max:=a[1,j];
min:=a[1,j];
{Последовательно перебираем все элементы в текущем (j-м) столбце матрицы.}
for i:=2 to n do
begin
{Если текущий элемент больше максимального, то
его и объявляем максимальным.}
if a[i,j]>max then max:=a[i,j];
{Если текущий элемент меньше минимального, то
его и объявляем минимальным.}
if a[i,j] max, то }
Begin
{ количество максимумов равно 1, т.к. встретился наибольший в данный момент элемент. }

339

k:=1;
{ в переменную max записываем A[i,j], }
max:=A[i,j];
{ в mas[k] записываем номер строки, где хранится число A[I,j]}
mas[k]:=i
end
else
{ Если A[i,j]=max (встретился элемент, равный
максимуму), то }
if A[i,j]=max then
begin
{ количество максимумов увеличиваем на 1. }
k:=k+1;
{ в mas[k] записываем номер строки, где хранится число A[I,j]}
mas[k]:=i
end
end;
{Если в pr осталось значение false,то выводим
сообщение, что в матрице нет простых чисел, }
if not Pr then writeln('В матрице A нет простых чисел')
else
begin
{ иначе удаляем из массива mas, номера строк,
где хранятся максимумы, повторяющиеся элементы. }
Udal(mas,k);
{Перебираем все строки матрицы. }
for i:=1 to N do
begin
L:=Nalichie(i,mas,k);
{Если номер строки присутствует в массиве mas,}
if L then
begin
{то переписываем строку в массив b}
for j:=1 to M do
b[j]:=A[i,j];

340

{упорядочиваем массив b по возрастанию. }
Vozr(b,M);
{ упорядоченный массив записываем на место i-й
строки матрицы A. }
for j:=1 to M do
A[i,j]:=b[j];
end
end;
writeln('Преобразованная матрица A');
for i:=1 to N do
begin
for j:=1 to M do write(A[i,j],' ');
writeln;
end
end
end.
Результаты работы программы приведены на рис. 6.34.

Рисунок 6.34: Результаты решения задачи 6.11
Авторы рекомендуют читателю по рассмотренным алгоритмам и
консольным приложениям задач 6.7-6.11 разработать визуальные приложения, аналогичные тем, которые были разработаны для задач 6.2,
6.6.

341

6.3 Динамические матрицы
Понятие динамического массива можно распространить и на матрицы. Динамическая матрица представляет собой массив указателей,
каждый из которых адресует одну строку (или один столбец).
Рассмотрим описание динамической матрицы. Пусть есть типы
данных massiv и указатель на него din_massiv.
type massiv=array [1..1000] of real;
din_massiv=^massiv;
Динамическая матрица X будет представлять собой массив указателей.
Var X: array[1..100] of din_massiv;
Работать с матрицей надо следующим образом.
1. Определить ее размеры (пусть N – число строк, M – число
столбцов).
2. Выделить память под матрицу.
for i:=1 to N do
getmem(X[i],M*sizeof(real));
Каждый элемент статического массива X[i] – указатель на динамический массив, состоящий из M элементов типа real. В статическом массиве Х находится N указателей.
3. Для обращения к элементу динамической матрицы, расположенному в i-й строке и j-м столбце, следует использовать конструкцию языка Турбо Паскаль X[i]^[j].
4. После завершения работы с матрицей необходимо освободить
память.
for i:=1 to N do
freemem(b[i],M*sizeof(real));
Рассмотрим работу с динамической матрицей на следующем примере.
ЗАДАЧА 6.12. В каждой строке матрицы вещественных чисел
B(N,M) упорядочить по возрастанию элементы, расположенные между максимальным и минимальным значением.
Алгоритмы упорядочивания рассматривались в пятой главе,
основные принципы работы с матрицами – в предыдущих параграфах
текущей главы, поэтому в комментариях к тексту программы основное внимание уделено особенностям работы с динамическими матрицами.

342

{ Описываем тип данных massiv как массив 1000
вещественных чисел. }
type massiv=array [1..1000] of real;
{ Указатель на массив. }
din_massiv=^massiv;
{ Тип данных matrica – статический массив указателей, каждые элемент которого является адресом
массива вещественных чисел.}
matrica=array [1..100] of din_massiv;
var
Nmax,Nmin,i,j,n,m,k:word;
{ Описана динамическая матрица b. }
b:matrica;
a,max,min:real;
begin
{ Вводим число строк N и число столбцов M. }
write('N=');readln(N);
write('M=');readln(M);
{ Выделяем память под матрицу вещественных чисел размером N на M.}
for i:=1 to N do
getmem(b[i],M*sizeof(real));
{ Вводим Матрицу B. }
writeln('Matrica B');
for i:=1 to N do
for j:=1 to M do
read(b[i]^[j]);
{В каждой строке находим максимальный, минимальный элементы и их номера, и элементы, расположенные
между
ними
упорядочиваем
методом
пузырька. }
for i:=1 to N do
begin
{ Поиск минимального, максимального элементов в
i-й строке матрицы и их номеров.}
max:=b[i]^[1];
Nmax:=1;
min:=b[i]^[1];

343

Nmin:=1;
for j:=2 to M do
begin
if b[i]^[j]>max then
begin
max:=b[i]^[j];
nmax:=j
end;
if b[i]^[j]b[i]^[k+1] then
begin
a:=b[i]^[k];
b[i]^[k]:=b[i]^[k+1];
b[i]^[k+1]:=a;
end;
j:=j+1;
end;
end;
{ Выводим преобразованную матрицу. }

344

writeln('Упорядоченная матрица B');
for i:=1 to N do
begin
for j:=1 to M do
write(b[i]^[j]:6:2, ' ');
writeln
end;
{ Освобождаем память. }
for i:=1 to N do
freemem(b[i],M*sizeof(real));
end.
Результаты работы программы представлены на рис. 6.35.

Рисунок 6.35: Результаты решения задачи 6.12
Динамическая матрица может быть достаточно большой, фактически ее размер ограничен только объемом свободной памяти.
6.4 Задачи для самостоятельного решения
1. Определить номера строки и столбца максимального простого
числа прямоугольной матрицы A(n,m). Подсчитать количество нулевых элементов матрицы и напечатать их индексы.
2. Найти среднее геометрическое значение элементов квадратной
матрицы X(n,n), находящихся по периметру этой матрицы и на ее
диагоналях, если это возможно. Если среднее геометрическое вычислить невозможно, то поменять местами максимальный и минимальный элементы матрицы.

345

3. Сформировать вектор D, каждый элемент которого представляет собой среднее арифметическое значение элементов строк матрицы C(k,m), и вектор G – любой его компонент должен быть равен
произведению элементов соответствующего столбца матрицы C.
4. Задана матрица А(n,m), в каждом столбце которой максимальный элемент необходимо заменить произведением отрицательных
элементов этого же столбца.
5. Задана матрица А(n,n). Определить максимальный элемент
среди элементов матрицы, расположенных выше главной диагонали,
и минимальный элемент среди тех, что находятся ниже побочной диагонали. После этого выполнить сортировку каждого столбца матрицы
по возрастанию.
6. Заменить строку матрицы Р(n,m) с минимальной суммой элементов на строку, где находится максимальный элемент матрицы.
7. Переместить максимальный элемент матрицы F(k,p) в правый верхний угол, а минимальный элемент – в левый нижний.
8. Проверить, является ли матрица A(n,n) диагональной (все
элементы нули, кроме главной диагонали), единичной (все элементы
нули, на главной диагонали только единицы) или нулевой (все элементы нули).
9. Сформировать из некоторой матрицы A(n,n) верхнетреугольную матрицу В(n,n) (все элементы ниже главной диагонали нулевые), нижнетреугольную матрицу С(n,n) (все элементы выше главной диагонали нулевые) и диагональную матрицу D(n,n) (все элементы нули, кроме главной диагонали) .
10. Заданы матрицы A(m,n) и B(n,m). Найти матрицу
C=(A·B)4.
11. Проверить, является ли матрица B(n,n) обратной к A(n,n).
Произведением матриц A и B в этом случае должна быть единичная
матрица.
12. Определить количество простых чисел, расположенных вне
диагоналей матрицы B(n,n).
13. Проверить, лежит ли на главной диагонали максимальный отрицательный элемент матрицы A(n,n).
14. Переписать простые числа из матрицы A в массив B. Массив
упорядочить по убыванию.

346

15. Переписать положительные числа из матрицы целых чисел A
в массив B. Из массива B удалить числа, в двоичном представлении
которых единиц больше, чем нулей.
16. Даны четыре квадратные матрицы A(n,n), B(n,n),
C(n,n), D(n,n), в которых хранятся целые числа. Найти матрицу, в
которой находится максимальное простое число.
17. Заданы четыре квадратные матрицы A(n,n), B(n,n),
C(n,n), D(n,n), в которых хранятся целые числа. Найти матрицы,
в которых на диагоналях есть простые числа.
18. Заданы три прямоугольные матрицы A(n,m), B(r,p),
C(k,q). Найти матрицы, в которых по периметру расположены только отрицательные числа.
19. Проверить, лежит ли на побочной диагонали минимальный
положительный элемент матрицы A(n,n).
20. Заданы матрицы D(n,n), A(m,n) и B(n,m). Найти матрицу C=(B·A). Проверить, является ли матрица C(n,n) обратной к
D(n,n). Произведением матриц С и D в этом случае должна быть
единичная матрица.
21. Заданы четыре квадратные матрицы A(n,n), B(n,n),
C(n,n), D(n,n), в которых хранятся целые числа. Найти, в какой из
матриц на побочной диагонали есть числа, состоящие из восьмерок.
22. Заменить столбец матрицы Р(n,m) с максимальной суммой
элементов на столбец, где находится максимальное число, состоящее
из единиц.
23. Заданы четыре квадратные матрицы A(n,n), B(n,n),
C(n,n), D(n,n), в которых хранятся целые числа. Определить, есть
ли среди них матрицы, в которых на побочной диагонали находятся
только числа, состоящие из единиц и двоек.
24. Переписать простые числа из матрицы целых чисел A в массив B. Из массива B удалить числа, расположенные между максимальным и минимальным элементами.
25. В матрице целых чисел A(n,n) упорядочить те строки, в которых диагональные элементы не содержат семерок.

347

7 Обработка файлов средствами Free Pascal
В данной главе будут рассмотрены возможности языка FreePascal
для работы с файлами. По ходу изложения материала читатель также
познакомится с компонентами Lazarus, предназначенными для выбора
файла.
Начнем со знакомства с типами файлов.
7.1 Типы файлов
Ввод данных с клавиатуры удобен при обработке небольших
объемов информации. В случае обработки массивов, состоящих из сотен элементов, использовать ввод данных с клавиатуры нерационально. В подобных случаях данные удобно хранить в файлах, программа
будет их считывать, обрабатывать, выводить результаты на экран или
в файл. Рассмотрим, как это можно сделать.
C точки зрения программиста, все файлы можно разделить на три
класса:

типизированные;

бестиповые;

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

348

Для работы с файлами в программе следует описать файловую
переменную. Для работы с текстовым файлом файловая переменная
(например, f) описывается с помощью служебного слова text.
var f:text;
Для описания типизированных75 файлов можно описать файловую переменную следующим образом:
var f:file of тип; 76
Бестиповый файл описывается с помощью служебного слова
file.
Рассмотрим несколько примеров описания файловых переменных.
type
massiv=array[1..25]of real;
ff=file of real;
var
a:text; {Файловая переменная a для работы с
текстовым файлом}
b:ff; {Файловая переменная f для работы с
файлом вещественных чисел}
c:file of integer; {Файловая переменная c для
работы с файлом целых чисел}
d:file of massiv; {Файловая переменная d предназначена для работы с типизированным файлом, элементами которого являются массивы из 25 вещественных чисел. }
Рассмотрим последовательно работу с файлами каждого типа.
7.2 Работа с типизированными файлами
Знакомство с методами обработки типизированных файлов
начнем с подпрограмм, которые являются общими для всех типов
файлов.
7.2.1 Процедура AssignFile
Для начала работы с файлом необходимо связать файловую переменную в программе с файлом на диске. Для этого используется про75 Типизированные файлы иногда называют компонентными.
76 Здесь f — имя файловой переменной, тип — тип компонентов файла, это могут быть как стандартные типы данных (например, real, integer и т.д.), так и типы, определенные пользователем.

349

цедура AssignFile(f,s), где f – имя файловой переменной, а s –
полное имя файла на диске (файл должен находиться в текущем каталоге при условии, что к нему специально не указывается путь).
Рассмотрим примеры использования AssignFile для различных операционных систем.
var
f:file of real;
begin
//Пример процедуры assign для ОС Windows.
AssignFile (f, 'd:\tp\tmp\abc.dat');
//Пример процедуры assign для ОС Linux.
AssignFile(f,'/home/pascal/6/pr1/abc.dat');
7.2.2 Процедуры reset, rewrite
После установления связи между файловой переменной и именем
файла на диске нужно открыть файл, воспользовавшись процедурами
reset или rewrite.
Процедура reset(f) (где f – имя файловой переменной)
открывает файл, связанный с файловой переменной f, после чего становится доступным для чтения первый элемент, хранящийся в файле.
Далее можно выполнять чтение и запись данных из файла.
Процедура rewrite(f) создает пустой файл (месторасположение файла на диске определяется процедурой AssignFile) для последующей записи в него данных.
Внимание!!! Если файл, связанный с файловой переменной f, существовал на диске, то вся информация в нем уничтожается.
7.2.3 Процедура СloseFile
Процедура CloseFile(f), где f – имя файловой переменной,
закрывает файл, который ранее был открыт процедурами rewrite,
reset.
Процедуру CloseFile(f) следует обязательно использовать
при закрытии файла, в который происходила запись данных.
Дело в том, что процедуры записи в файл не обращаются непосредственно к диску, они пишут информацию в специальный участок
памяти, называемый буфером файла. После того как буфер заполнится, вся информация из него переносится в файл. При выполнении

350

процедуры closefile сначала происходит запись буфера файла на
диск, и только потом файл закрывается. Если его не закрыть вручную,
то закрытие произойдет автоматически при завершении работы программы. Однако при автоматическом закрытии файла информация из
буфера файла не переносится на диск, и как следствие часть информации может пропасть.
Внимание!!! После записи информации в файл его обязательно закрывать с помощью процедуры CloseFile. Однако при чтении данных из файла нет необходимости в обязательном его закрытии.
7.2.4 Процедура rename
Переименование файла, связанного с файловой переменной f,
осуществляется в то время, когда он закрыт, при помощи процедуры
rename(f,s), где f – файловая переменная, s – новое имя файла
(строковая переменная).
7.2.5 Процедура erase
Удаление файла, связанного с переменной f, выполняется посредством процедуры erase(f), в которой f также является именем
файловой переменной. Для корректного выполнения этой операции
файл должен быть закрыт.
7.2.6 Функция eof
Функция eof(f) (end of file), где f – имя файловой переменной,
принимает значение «истина» (true), если достигнут конец файла,
иначе – «ложь» (false). С помощью этой функции можно проверять,
достигнут ли конец файла и можно ли считывать очередную порцию
данных.
7.2.7 Чтение и запись данных в файл
Для записи данных в файл можно использовать процедуру write:
write(f, x1, x2,..., xn);
write(f, x);
здесь
f — имя файловой переменной,
x, x1, x2, ..., xn — имена переменных, значения из которых записываются в файл.

351

Тип компонентов файла обязательно должен совпадать с типом
переменных. При выполнении процедуры write значения x1, x2, ...,
xn последовательно записываются в файл (начиная с текущей позиции), связанный с файловой переменной f.
Для чтения информации из файла, связанного с файловой переменной f, можно воспользоваться процедурой read:
read(f, x1, x2, x3,..., xn);
read(f, x);
здесь
f — имя файловой переменной,
x, x1, x2, ..., xn — имена переменных, в которые считываются
значения из файла.
Процедура read последовательно считывает компоненты из
файла, связанного с файловой переменной f, в переменные x1, x2, ...,
xn. При считывании очередного значения доступным становится следующее. Следует помнить, что процедура read не проверяет, достигнут ли конец файла. За этим нужно следить с помощью функции eof.
Для того чтобы записать данные в файл, необходимо выполнить
следующее:
1. Описать файловую переменную.
2. Связать ее с физическим файлом (процедура AssignFile).
3. Открыть файл для записи (процедура rewrite).
4. Записать данные в файл (процедура write).
5. Обязательно закрыть файл (процедура CloseFile).
Рассмотрим создание компонентного файла на примере решения
следующей несложной задачи.
ЗАДАЧА 7.1. Создать типизированный файл и записать туда n вещественных чисел.
Алгоритм решения задачи состоит из следующих этапов:
1. Открыть файл для записи с помощью оператора rewrite.
2. Ввести значение n.
3. В цикле (при i меняющемся от 1 до n) вводим очередное вещественное число a, которое сразу же записываем в файл с помощью процедуры write.
4. Закрываем файл с помощью процедуры closefile.
Текст консольного приложения, предназначенного для решения

352

данной задачи приведен ниже.
program pr1;
{$mode objfpc}{$H+}
uses
Classes, SysUtils
{ you can add units after this };
var f:file of real;
i,n:integer;
a:real;
begin
//Связываем файловую переменную с файлом
//на диске.
AssignFile(f,'/home/pascal/6/pr1/abc.dat');
//Открываем пустой файл для записи.
rewrite(f);
//Определяем количество элементов в файле.
write('n=');
readln(n);
//В цикле вводим очередной элемент и
//записываем его в файл.
for i:=1 to n do
begin
write('a=');
readln(a);
write(f,a);
end;
//Закрываем файл.
//При записи данных в файл это делать
//обязательно.
CloseFile(f)
end.
Рассмотрим следующую задачу
ЗАДАЧА 7.2. В папке /home/evgeniy/pascal/6/pr2/ находятся
файлы вещественных чисел с расширением dat. В выбранном пользователем файле удалить все числа, меньшие среднего арифметического, расположенные между максимальным и минимальным элементами.
В задаче предполагается выбор пользователем файла для обра-

353

ботки. Для этого понадобится специальный компонент для выбора
файла. Решение задачи 7.2 начнем со знакомства с компонентом
OpenDialog
. Это компонент предназначен для создания стандартного диалогового окна выбора файла и расположен первым на
странице Dialogs (см. рис. 7.1).

Рисунок 7.1: Компоненты страницы Dialogs
Среди основных свойств этого компонента можно выделить:
FileName: String — полное имя выбранного пользователем
файла;
Filter: String — строка, которая возвращает фильтры отбираемых
файлов; это свойство можно задать с помощью редактора фильтров
или с помощью специальной строки. Для вызова редактора необходимо щелкнуть по кнопке
, после чего появится окно редактора
фильтров (см. рис. 7.2).
Окно редактора фильтров
состоит из двух столбцов:
Filter name — имя фильтра
(например, все файлы, программы на Паскале); Filter —
соответствующая
имени
фильтра маска (фильтру «все
файлы» соответствует маска
«*.*», фильтру «программы на
Паскале» — маска «*.pas».
Рисунок 7.2: Редактор фильтров
Специальная строка состоит из последовательных имен фильтров
и соответствующих им масок, разделенных символом «|». Специальная строка, соответствующая фильтру, представленному на рис.7.2,
имеет вид.
OpenDialog1.Filter:=

'Программы на C|*.c|Программы на Паскале|*.pas|Все файлы|*.*';

Первый фильтр в списке является фильтром по умолчанию. В
примере на рис. 7.2 фильтр по умолчанию — «Программы на C».
InitialDialog — имя каталога по умолчанию для выбора файлов.

354

DefaultExt — расширение, добавляемое к имени файла по
умолчанию, если пользователь при ручном вводе имени файла не указал расширение.
Основным методом для компонента OpenDialog — является логическая функция Execute, которая приводит к открытию диалогового окна в соответствии со свойствами компонента. Функция
Execute возвращает true, если пользователь выбрал файл каким-либо методом. Если пользователь нажал в диалоговом окне Отмена (Cancel), то метод Execute возвращает false. Имя выбранного файла возвращается в свойстве FileName.
Таким образом, вызов диалогового окна можно записать так.
Var
s:String;
begin
if OpenDialog1.Execute then
s:=OPenDialog1.FileName;
{Имя файла, выбранного пользователем, хранится
в переменной s}.
end;
Разобравшись с компонентом для выбора файла, вернемся к задаче 7.2. Можно выделить следующие этапы ее решения.
1. Выбор файла.
2. Чтение данных из файла в массив вещественных чисел.
3. В массиве вещественных чисел удалить все числа, меньшие
среднего арифметического, расположенные между максимальным и минимальным элементами.
4. Запись преобразованного массива в файл.
Разработку программы начнем с создания графического приложения (Проект — Создать Проект — Приложение).
На форме расположим следующие компоненты:
1. Две метки Label1 и Label2 для подписи.
2. Memo1 — компонент, в котором будем хранить содержимое
исходного файла.
3. Memo2 — компонент, в котором хранится преобразованный
файл.
4. OpenDialog1 — компонент для выбора имени обрабатываемого файла.

355

5. Buttom1 — кнопка для запуска программы.
6. Buttom2 — кнопка для завершения программы.
Установим следующие свойства формы и компонентов (см. табл.
7.1 — 7.8).
Таблица 7.1: Свойства формы
Caption
Name
Свойство
Преобразование файла
Form_File
Значение
Таблица 7.2: Свойства метки label1
Caption
Visible
Свойство
Файл до преобразования
False
Значение
Таблица 7.3: Свойства метки label2
Caption
Visible
Свойство
Файл после преобразования False
Значение
Таблица 7.4: Свойства компонента Memo1
Lines
Visible
Свойство
''
False
Значение
Таблица 7.5: Свойства компонента Memo2
Lines
Visible
Свойство
''
False
Значение
Таблица 7.6: Свойства компонента OpenDialog1
DefaultExt
Свойство InitDialog
dat
Значение /home/evgeniy/pascal/6/pr2/
Таблица 7.7: Свойства кнопки Button1
Name
Visible
Свойство Caption
Button_File
True
Значение Преобразовать файл
Таблица 7.8: Свойства кнопки Button2
Visible
Свойство Caption Name
False
Значение Закрыть Button_Close
Расположим компоненты на форме подобно показанному на рис.
7.3. При запуске программы на выполнение все компоненты, кроме
кнопки «Преобразовать файл», будут невидимыми, свойство
Visible установлено в False. Окно приложения при запуске пока-

356

зано на рис. 7.4.

Рисунок 7.3: Форма с расположенными на ней компонентами

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

357

При создании формы установим свойство Filter компонента
OpenDialog1. Поэтому подпрограмма FormCreate будет такой.
procedure TForm_File.FormCreate(Sender: TObject);
begin
OpenDialog1.Filter:=
'Файлы вещественных чисел|*.dat|Все файлы|*.*';
end;
При щелчке по кнопке «Преобразовать файл» должно происходить следующее:
1. Выбор файла из диалогового окна.
2. Считывание данных из файла в массив вещественных чисел.
3. Установка свойства Visible в True у компонентов
label1 и Memo1.
4. Вывод содержимого массива в Memo1.
5. Преобразование массива.
6. Запись преобразованного массива в файл.
7. Установка свойства Visible в True у компонентов
label2 и Memo2.
8. Вывод преобразованного массива в Memo2.
9. Установка свойства Visible в True у компонента
Button_Close.
Ниже приведен текст обработки события Button_FileClick с
подробными комментариями.
procedure Tform_File.Button_FileClick(
Sender: TObject);
var
f:file of real;
s:string;
a:array[1..100] of real;
nmax,nmin,i,j,n:integer;
sum,max,min:real;
begin
//Открываем диалоговое окно для выбора файла.
if opendialog1.execute then
begin
//Имя выбранного файла считываем в s.
s:=OpenDialog1.FileName;

358

//Связываем файловую переменную
//с файлом на диске.
AssignFile(f,s);
//Открываем файл для чтения.
Reset(f);
//Обнуляем счетчик элементов массива.
n:=0;
//Делаем видимыми первую
//метку и компонент Memo1.
label1.Visible:=true;
Memo1.Visible:=true;
//Переменная sum служит для
//нахождения суммы компонентов файла.
Sum:=0;
//Пока не встретится конец файла,
//будем считывать очередной компонент.
while not eof(f) do
begin
//Индекс массива увеличиваем на 1.
n:=n+1;
//Считываем очередной элемент из
//файла в массив.
read(f,a[n]);
//Накапливаем сумму элементов массива.
sum:=sum+a[n];
//Выводим очередной элемент в Memo1.
Memo1.Lines.Add(FloatToStr(a[n]));
end;
//Закрываем файл.
CloseFile(f);
//Находим среднее арифметическое
//элементов массива.
sum:=sum/n;
//Поиск максимального, минимального
//элементов в массиве и их индексов.
max:=a[1];min:=max;nmin:=1;nmax:=1;
for i:=2 to n do
begin

359

if a[i]>max then
begin
max:=a[i]; nmax:=i;
end;
if a[i]0 then

407

begin
//Вычисление и вывод площади.
s:=sqrt(p*(p-x.a)*(p-x.b)*(p-x.c));
writeln('Площадь S=', s:7:2);
end
else
writeln('Треугольник с заданными
сторонами не существует.');

end.
Элементами записей могут быть как простые, так и структурированные типы. Никаких ограничений на вложение одной структуры в
другую не существует.
Например, создадим запись Student, которая будет состоять из полей: фамилия, имя, группа, оценки по пяти дисциплинам и адрес. В
свою очередь поле «Адрес» также сделаем записью, состоящей из полей: город, улица, дом, квартира.
type
adress = record
//Запись «Адрес».
//поля:
city,
//город,
street: string;
//улица,
house,
//дом,
apartment: integer;
//квартира.
end;
student = record
//Запись «Студент».
//поля:
surname,
//фамилия,
name: string;
//имя,
group: string;
//группа,
//оценки,
estimation: array [1..5] of integer;
residence: adress;
//адрес.
end;
После объявления такой записи обращение к полям осуществляется так:
var Ivanov: student;
x: array [1..100] of student;
begin

408

Ivanov.group:='Ф08';
Ivanov.residense.city:='Киев';
//у первого студента 5-я оценка =3
x[1].estimation[5]:=3;
...
C использованием ключевого слова With к полям записи можно
обращаться без указания префикса каждый раз с названием поля:
with do
Например:
with stud do
begin
with residence do
begin
city:='Донецк';
street :='Артема';
house:=145;
apartment:=31;
end;
surname:='Иванов';
name:='Андрей';
birthday :='01.11.1990';
group :='Ф07';
estimation[1]:=3; estimation[2]:=5;
estimation[3]:=4;
estimation[4]:=3; estimation[5]:=5;
end;
ЗАДАЧА 8.3. Создать базу данных «Сведения о студентах». В
программе предусмотреть расчет среднего балла студента, сортировку по алфавиту, вывод результатов в диалоговое окно и в текстовый
файл.
Создадим новый проект. На форму (рис. 8.3) поместим двенадцать объектов типа TEdit для ввода исходных данных, объект типа
StringGrid (ColCount=8, RowCount=1) для вывода результатов
и три кнопки типа Tbutton:

Button1 — для чтения данных из полей ввода и их последующей очистки;

409



Button2 — для сортировки данных по алфавиту;
Button3 — для вывода результатов в таблицу StringGrid1
и записи их в текстовый файл.
Текст программы с комментариями приведен далее.

Рисунок 8.3: Пример формы для задачи 8.3
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms,
Controls, Graphics, Dialogs, StdCtrls, Grids;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Edit1: TEdit;
Edit10: TEdit;
Edit11: TEdit;
Edit12: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;

410

Edit6: TEdit;
Edit7: TEdit;
Edit8: TEdit;
Edit9: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
StringGrid1: TStringGrid;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Описание записи «Адрес студента».
adress = record
city, street : string;
//город, улица,
house, apartment: integer;//дом, квартира.
end;
//Описание записи «Сведения о студенте».
student = record
surname , name : string; //фамилия, имя,
group : string;
//группа,
//оценки,
estimation: array [1..5] of integer;
residence : adress;
//адрес,
s_ball: real;
//средний балл.
end;
var

411

Form1: TForm1;
//Массив переменных типа student.
x: array [0..100] of student;
//Локальная переменная для подсчета
//количества студентов.
i: integer;
implementation
{ TForm1 }
//Процедура инициализации формы.
procedure TForm1.FormCreate(Sender: TObject);
begin
i:=0;//количество студентов равно 0.
end;
//Процедура работы кнопки «Запомнить данные».
procedure TForm1.Button1Click(Sender: TObject);
var sum, j:integer;
begin
//Чтение данных из полей ввода.
x[i].surname:= Edit1.Text;
x[i].name:= Edit2.Text;
x[i].group:= Edit3.Text;
x[i].residence.city:=Edit5.Text ;
x[i].residence.street:= Edit6.Text;
x[i].residence.house:=
StrToInt(Edit7.Text);
x[i].residence.apartment:=
StrToInt(Edit8.Text);
x[i].estimation[1]:=strToInt(Edit4.Text);
x[i].estimation[2]:=strToInt(Edit9.Text);
x[i].estimation[3]:=strToInt(Edit10.Text);
x[i].estimation[4]:=strToInt(Edit11.Text);
x[i].estimation[5]:=
strToInt(Edit12.Text) ;
//Вычисление среднего балла студента.
sum:=0;
for j:=1 to 5
do
sum:=sum+x[i].estimation[j];
x[i].s_ball:=sum/5; inc(i);

412

//Очищение полей ввода для следующих данных.
Edit1.Text:= ''; Edit2.Text:= '';
Edit3.Text:= ''; Edit4.Text:= '';
Edit5.Text:= ''; Edit6.Text:= '';
Edit7.Text:= ''; Edit8.Text:= '';
Еdit9.Text:= ''; Edit10.Text:= '';
Edit11.Text:= ''; Edit12.Text:= '';
end;
//Процедура работы кнопки «Вывести данные».
procedure TForm1.Button2Click(Sender: TObject);
var f:textfile; j: integer; s: string;
begin
//Количество строк в таблице StringGrid
//на один больше, чем количество студентов,
//одна строка для шапки таблицы.
StringGrid1.RowCount:= i+1;
//Вывод шапки таблицы.
StringGrid1.Cells[1,0]:='Фамилия' ;
StringGrid1.Cells[2,0]:='Имя' ;
StringGrid1.Cells[3,0]:='Группа' ;
StringGrid1.Cells[4,0]:='Город' ;
StringGrid1.Cells[5,0]:='Улица' ;
StringGrid1.Cells[6,0]:='Дом/кв.' ;
StringGrid1.Cells[7,0]:='Средний балл' ;
//Вывод сведений о студентах в j-ю строку.
for j:=1 to i do
begin
StringGrid1.Cells[1,j]:=
x[j-1].surname ;
StringGrid1.Cells[2,j]:=x[j-1].name;
StringGrid1.Cells[3,j]:=x[j-1].group;
StringGrid1.Cells[4,j]:=
x[j-1].residence.city;
StringGrid1.Cells[5,j]:=
x[j-1].residence.street;
s:=inttostr(x[j-1].residence.house)+
'/'+inttostr(x[j-1].residence.apartment);
StringGrid1.Cells[6,j]:=s ;

413

StringGrid1.Cells[7,j]:=
floattostr(x[j-1].s_ball);

end
//Вывод результатов в текстовый файл.
assignfile(f,'g:\student.txt');
rewrite(f);
for j:=1 to i do
begin
writeln(f,x[j-1].surname:20,
x[j-1].name:15,
x[j-1].residence.city:15,',',
x[j-1].residence.street:15,
x[j-1].residence.house:4,'/',
x[j-1].residence.apartment,
' Sr_ball=',x[j-1].s_ball:4:1);
end;
closefile(f);
end;
//Процедура работы кнопки
//«Сортировать по алфавиту».
procedure TForm1.Button3Click(Sender: TObject);
var j, k :integer;
temp: student; //Переменная для сортировки.
f:textfile;
Begin
//Сортировка по полю surname методом пузырька.
for j:= 0 to i-1 do
for k:=j+1 to i-1 do
if x[j].surname > x[k].surname then
begin
//Строки меняются местами.
temp:=x[j]; x[j]:=x[k];x[k]:=temp;
end;
end;
initialization
{$I unit1.lrs}
end.
Результаты работы программы представлены на рис. 8.5 — 8.7.

414

Рисунок 8.5: Окно формы ввода сведений о студенте

Рисунок 8.6: Окно формы вывода сведений о студентах

415

При запуске программы и вводе сведений окно формы выглядит
так, как показано на рис 8.5. Когда запись введена, следует щелкнуть
по кнопке «Запомнить данные», при этом поля ввода очищаются для
ввода следующей записи. После щелчка по кнопке «Вывести данные»
таблица заполняется введенными сведениями (рис.8.6). После щелчка
по кнопке «Сортировать по алфавиту» нужно повторно щелкнуть по
кнопке «Вывести данные», чтобы увидеть отсортированный список
(рис.8.7).

Рисунок 8.7: Окно формы после сортировки записей по полю «Фамилия»
8.3 Задачи для самостоятельного решения по теме
«Строки»
Дана строка текста. Выполнить с ней следующие действия:
1. Посчитать количество запятых в строке.
2. Заменить в строке все цифры на пробел. Вывести количество
замен.
3. Посчитать в строке количество цифр.
4. Удалить из строки все запятые.
5. Посчитать в строке количество слов.
6. Удалить из строки все слова, начинающиеся на букву «о».
7. После каждого пробела вставить символ *.

416

8. Найти в строке самое длинное слово.
9. Перед каждым пробелом вставить пробел и символ +.
10. Посчитать сумму всех чисел, которые встречаются в строке.
11. Посчитать в строке количество слов, начинающихся на «Ав».
12. Заменить в строке двойные пробелы на одинарный пробел.
Вывести количество замен.
13. Вставить после каждого слова запятую.
14. После каждого слова вставить символ «;».
15. Посчитать в строке количество символов «:» и «;».
16. Удалить из строки все цифры.
17. Посчитать в строке количество слов, заканчивающихся символами «ая».
18. Найти в строке самое короткое слово.
19. Вставить после каждого слова, заканчивающегося на букву
«о», слово «Ого».
20. Удалить из строки все слова, состоящие из пяти букв.
21. Найти в строке количество слов, начинающихся на букву «а»
и заканчивающихся буквой «т».
22. Удалить из строки второе, третье и пятое слова.
23. Перед каждой цифрой вставить символ №.
24. Посчитать в строке количество гласных букв.
25. Удалить из строки все слова, начинающиеся и заканчивающиеся на «о».
8.4 Задачи для самостоятельного решения по теме
«Записи»
1. Создать структуру с данными по таблице 8.1:
Таблица 8.1. Прирост населения в городах
Город
Прирост населения, тыс. чел.
1999
2000
2001
2002
Макеевка

2,5

1,3

-0,2

-0,1

2003
0,6

...

Добавить и вычислить в структуре поле «Средний прирост».
Определить количество городов с отрицательным приростом в 2003
году. Упорядочить записи по возрастанию среднего прироста.
2. Создать структуру с данными по таблице 8.1. Добавить и вычислить в структуре поле «Минимальный прирост». Определить ко-

417

личество городов с приростом в 2003 году более 2 тыс. чел. Выполнить сортировку записей по полю «Город». Названия городов упорядочить по алфавиту.
3. Создать структуру с данными по таблице 8.2:
Таблица 8.2. Сведения о товаре
Название
Паровозик

Фабрика
Игрушка

Цена
125,00

Дата выпуска

Количество

01.02.2007

...

Добавить и вычислить в структуре поле «Цена со скидкой», вводя
процент скидки с формы. Найти общее количество игрушек с фабрики «Игрушка». Упорядочить записи по убыванию поля «Цена».
4. Создать структуру с данными по таблице 8.2. Добавить и вычислить в структуре поле «Сумма продажи». Найти количество названий игрушек, у которых цена меньше общей средней цены всех игрушек. Упорядочить записи по названию игрушек.
5. Создать структуру с данными по таблице 8.5:
Таблица 8.5. Сведения о школьнике
Фамилия
Имя
Дата рождения
Школа
Класс
Сергеев

Сергей

05.05.1994

112

9-А

...

Добавить и вычислить в структуре поле «Возраст», вводя текущую дату с формы. Определить количество школьников с именем
Сергей. Упорядочить записи по номеру школы.
6. Создать структуру с данными по таблице 8.5. Добавить и вычислить в структуре поле «Год обучения», убрав из названия класса
букву. Найти количество учеников 9-х классов. Выполнить сортировку записей по полю «Фамилия». Фамилии упорядочить по алфавиту.
7. Создать структуру с данными по таблице 8.6:
Таблица 8.6. Сведения о продажах
Принтер
Количество, шт.
Цена, $
Январь Февраль
Март
Samsung CLP-310

25

20

26

550

...

Добавить и вычислить в структуре поле «Выручка». Найти среднюю
цену принтеров. Упорядочить записи по возрастанию поля «Цена».

418

8. Создать структуру с данными по таблице 8.6. Добавить и вычислить в структуре поле «Среднее количество». Найти среднее количество принтеров в каждом месяце. Упорядочить записи по названию
принтера.
9. Создать структуру с данными по таблице 8.6. Добавить и вычислить в структуре поле «Общее количество». Найти общее количество проданных принтеров в каждом месяце. Упорядочить записи по
возрастанию поля «Общее количество».
10. Создать структуру с данными по таблице 8.6. Добавить и вычислить в структуре поле «Цена со скидкой», вводя процент скидки с
формы. Найти количество принтеров с ценой более 500$. Упорядочить записи по убыванию цены.
11. Создать структуру с данными по таблице 8.7:
Таблица 8.7. Сведения о сотруднике
ФИО
Дата рождения Должность Стаж
Оклад
Сергеев С. И.

12.03.1966

Менеджер

2

1250

...

Добавить и вычислить в структуре поле «Премия», рассчитав ее
по следующему принципу: 20% от оклада, если стаж более 10 лет, в
противном случае 10%. Найти количество сотрудников со стажем более 10 лет. Упорядочить записи по должности.
12. Создать структуру с данными по таблице 8.8. Добавить и вычислить в структуре поле «Возраст», текущую дату вводить с формы.
Найти средний оклад всех сотрудников. Упорядочить записи по ФИО.
13. Создать структуру с данными по таблице 8.8. Добавить и вычислить в структуре поле «Возраст», текущую дату вводить с формы.
Определить количество молодых специалистов (моложе 25 лет). Упорядочить записи по возрастанию оклада.
14. Создать структуру с данными по таблице 8.8:
Таблица 8.8. Сведения о продажах путевок
Место отдыха
Количество, шт.
Цена, $
Июль
Август Сентябрь
Геленджик

255

203

198

510

...

Добавить и вычислить в структуре поле «Среднее количество».
Найти общее количество путевок в каждом месяце. Упорядочить за-

419

писи по месту отдыха.
15. Создать структуру с данными по таблице 8.8. Добавить и вычислить в структуре поле «Доход от путевок». Найти среднюю цену
путевки. Упорядочить записи по возрастанию цены.
16. Создать структуру с данными по таблице 8.9:
Таблица 8.9. Сведения о сотруднике
ФИО
Дата рождения
Должность
Пол
Оклад
Сергеев С. И. 12.03.1966
Менеджер
Муж.
1250
...
Добавить и вычислить в структуре поле «Зарплата», рассчитав ее
по следующему принципу: к окладу добавить премию в размере 15%
от оклада. Упорядочить записи по ФИО.
17. Создать структуру с данными по таблице 8.9. Добавить и вычислить в структуре поле «Возраст», текущую дату вводить с формы.
Определить количество мужчин и женщин. Упорядочить записи по
должности.
18. Создать структуру с данными по таблице 8.10:
Таблица 8.10. Сведения о научных сотрудниках
Фамилия
Сергеев

Инициалы
С. А.

Ученая степень Год рождения Количество статей
Доцент

1971

25

...

Добавить и вычислить в структуре поле «Активность» по следующему принципу: если количество статей более 10, то в поле записать
пробел, в противном случае – фразу «Работать лучше». Упорядочить
записи по фамилии.
19. Создать структуру с данными по таблице 8.10. Удалить сотрудника с фамилией, которая вводится с формы. Определить количество доцентов. Упорядочить записи по должности.
20. Создать структуру с данными по таблице 8.11:
Таблица 8.11. Сведения о тираже книг
Название
Вий

Автор

Издательство

Гоголь Н. В. Правда

Год издания
1971

Цена, $
6,5

Тираж
15000

...

Добавить и вычислить в структуре поле «Стоимость тиража».
Найти общий тираж книг 2005 года. Упорядочить записи по автору.

420

21. Создать структуру с данными по таблице 8.11. Удалить все записи книг тиража 2000 года. Найти среднюю цену книг типографии
«Правда». Упорядочить записи по году издания.
22. Создать структуру с данными по таблице 8.12:
Таблица 8.12. Сведения о телефонных звонках
ФИО абонента
Моль Р. Ю.

Номер

Дата
звонка

Город Стоимость 1 ми- Количество
нуты разговора
минут

956-25-78 12.05.2003 Казань

3,65

2

...

Добавить и вычислить в структуре поле «Стоимость звонка».
Найти общую стоимость звонков в город, вводимый по запросу. Упорядочить записи по ФИО абонента.
23. Создать структуру с данными по таблице 8.12. Удалить все записи звонков с номерами, начинающимися с цифры 3. Упорядочить
записи по названию города.
24. Создать структуру с данными по таблице 8.14:
Таблица 8.14. Сведения о приборах
Название
прибора

Шифр прибора

Дата
выпуска

Количество

Гарантийный
срок, мес.

Микроскоп

М12-08

12.06.2006

200

24

...

Добавить и вычислить в структуре поле «Гарантийное обслуживание» по следующему принципу: записать фразу «1 год», если гарантийный срок более 3 лет, в противном случае – фразу «нет обслуживания». Найти общее количество всех приборов. Упорядочить записи по
названию прибора.
25. Создать структуру с данными по таблице 8.14. Удалить все записи с гарантийным сроком менее 6 месяцев. Упорядочить записи по
дате выпуска.

421

9 Объектно-ориентированное программирова-

ние
Эта глава посвящена изучению объектно-ориентированного программирования (ООП). ООП – это методика разработки программы, в
основе которой лежит понятие объекта как некоторой структуры, описывающей объект реального мира, его поведение и взаимодействие с
другими объектами.
9.1 Основные понятия
Основой объектно-ориентированного программирования является
объект. Он состоит из трех основных частей:
1. Имя (например, автомобиль);
2. Состояние или переменные состояния (например, марка автомобиля, цвет, масса, число мест и т. д.);
3. Методы, или операции, которые выполняют некоторые действия над объектами и определяют, как объект взаимодействует с
окружающим миром.
Для работы с объектами во FreePascal введено понятие класса.
Класс – сложная структура, включающая в себя описание данных,
процедуры и функции, которые могут быть выполнены над объектом.
Классом называется составной тип данных, членами (элементами) которого являются функции и переменные (поля). В основу понятия «класс» положен тот факт, что "над объектами можно совершать различные операции". Свойства объектов описываются с помощью переменных (полей) классов, а действия над объектами описываются с помощью подпрограмм, которые называются «методами класса». Объекты называются экземплярами класса.
Объектно-ориентированное программирование (ООП) – представляет собой технологию разработки программ с использованием
объектов.
В объектно-ориентированных языках есть три основных понятия:
инкапсуляция, наследование и полиморфизм. Инкапсуляцией называется объединение в классе данных и подпрограмм для их обработки.
Наследование – это когда любой класс может быть порождён другим
классом. Порождённый класс (наследник) автоматически наследует
все поля, методы, свойства и события. Полиморфизм позволяет ис-

422

пользовать одинаковые имена для методов, входящих в различные
классы.
Дляобъявления класса используется конструкция:
type
= class()

private

protected

public

published

end;
В качестве имени класса можно использовать любой допустимый
в FreePascal идентификатор. Имя класса родителя — имя класса, наследником которого является данный класс, это необязательный параметр, если он не указывается, то это означает, что данный класс является наследником общего из предопределенного класса TObject.
Структуры отличаются от классов тем, что поля структуры доступны всегда. При использовании классов могут быть члены, доступные везде — публичные (описатель public), и приватные (описатель private), доступ к которым возможен только с помощью публичных методов. Это также относится и к методам класса.
Поля, свойства и методы секции public не имеют ограничений на
видимость. Они доступны из других функций и методов объектов как
в данном модуле, так и во всех прочих, ссылающихся на него. При обращении к публичным полям вне класса используется оператор . (точка).
Поля, свойства и методы, находящиеся в секции private, доступны
только в методах класса и в функциях, содержащихся в том же модуле, что и описываемый класс. Это позволяет полностью скрыть детали внутренней реализации класса. Вызов приватных методов осуществляется из публичных.
Публикуемый (published) — это раздел, содержащий свойства, ко-

423

торые пользователь может устанавливать на этапе проектирования и
они доступны в любом модуле.
Защищенный (protected) — это раздел, содержащий поля и методы, которые доступны внутри класса, а также любым его классам-потомкам, в том числе и в других модулях.
При программировании с использованием классов программист
должен решить, какие члены и методы должны быть объявлены публичными, а какие приватными. Общим принципом является следующее: "Чем меньше публичных данных о классе используется в программе, тем лучше". Уменьшение количества публичных членов и
методов позволит минимизировать количество ошибок.
Поля могут быть любого типа, в том числе и классами. Объявление полей осуществляется так же, как и объявление обычных переменных:
поле1: тип_данных;
поле2: тип_данных;
...
Методы в классе объявляются так же, как и обычные подпрограммы:
function метод1 (список параметров): тип результата;
procedure метод2 (список параметров);
Описание процедур и функций, реализующих методы, помещается после слова implementation того модуля, где объявлен класс, и
выглядит так:
function имя_класса.метод1(список параметров):
тип результата;
begin
тело функции;
end;
procedure имя_класса.метод2(список параметров);
begin
тело процедуры;
end;
Объявление переменной типа class называется созданием (инициализацией) объекта (экземпляра класса). Экземпляр класса объявляется в блоке описания переменных:
var имя_переменной : имя_класса;

424

После описания переменной в программе можно обращаться к
полям и методам класса аналогично обращению к полям структуры,
используя оператор «.». Например:
имя_переменной.поле1:=выражение;
имя_переменной.метод1(список параметров);
...
Также можно использовать оператор With:
With имя_переменной do
begin
поле1:=выражение;
метод1(список параметров);
...
end;
В FreePascal имеется большое количество классов, с помощью которых описывается форма приложения и ее компоненты (кнопки,
поля, флажки и т.п.). В процессе конструирования формы в текст программы автоматически добавляются программные объекты. Например, при добавлении на форму компонента формируется описание
класса для этого компонента, а при создании подпрограмм обработки
событий в описание класса добавляется объявление методов.
Рассмотрим это на примере проекта с формой, на которой есть кнопка
Button1.
unit Unit1;
interface
uses
Classes, SysUtils, LResources, Forms, Controls,
Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
//объявление класса формы TForm1
TForm1 = class(TForm)
//объявление компонента кнопки Button1
Button1: TButton;
//объявление метода обработки события —
//щелчка по кнопке Button1
procedure Button1Click(Sender: TObject);
private
{ private declarations }

425

public
{ public declarations }
end;
var
//описание переменной класса формы TForm1
Form1: TForm1;
implementation
{ TForm1 }
//описание метода обработки события — щелчка по
кнопке Button1
procedure TForm1.Button1Click(Sender: TObject);
begin
//Текст процедуры обработки события
end;
initialization
{$I unit1.lrs}
end.
Во Free Pascal класс (объект) –это динамическая структура. В отличие от статической она содержит не сами данные, а ссылку на них.
Поэтому программист должен сам позаботиться о выделении памяти
для этих данных.
Конструктор — это специальный метод, создающий и инициализирующий объект. Объявление конструктора имеет вид:
constructor Create;
Описывают конструктор так же, как и другие методы, после ключевого слова implemention того модуля, в котором объявлен класс.
constructor имя_класса.Create;
begin
поле1:=выражение1;
поле2:=выражение2;
...
inherited Create;
end;
В результате работы конструктора инициализируются все поля
класса, при этом порядковым типам в качестве начальных значений
задается 0, а строки задаются пустыми.
Деструктор – это специальный метод, уничтожающий объект и
освобождающий занимаемую им память. Объявляется деструктор

426

следующим образом:
destructor Destroy;
Если в программе какой-либо объект больше не используется, то
оператор
имя_переменной_типа_класс.free;
с помощью метода free вызывает деструктор и освобождает память,
занимаемую полями объекта имя_переменной_типа_класс.
Рассмотрим все описанное на примере класса — комплексное
число78. Назовем класс – Tcomplex, в классе будут члены класса: x –
действительная часть комплексного числа, y – мнимая часть
комплексного числа. Также в классе будут методы:
• конструктор Create, который будет записывать в действительную и мнимую части значение 0;
• Modul() – функция вычисления модуля комплексного числа;
• Argument() – функция вычисления аргумента комплексного
числа;
• ComplexToStr()
- функция, представляющая комплексное
число в виде строки для вывода.
Создадим новый проект, на форму поместим кнопку Button1,
два поля Edit1 и Edit2 для ввода действительной и мнимой частей,
для вывода результатов разместим компонент Memo1. При щелчке по
кнопке будет создаваться экземпляр класса «Комплексное число», затем будут вычисляться его модуль и аргумент. В компонент Memo1
выведем результаты: число в алгебраической форме, его аргумент и
модуль. Ниже приведем текст модуля с комментариями, который демонстрирует работу с этим классом. Результат работы программы
приведен на рис. 9.1.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
78 Про комплексные числа можно прочитать на странице
http://kvant.mccme.ru./1982/03/komplesnye_chisla.htm

427

TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
type
//Описание класса – комплексное число.
TComplex = class
private
x: real;
//Действительная часть.
y: real;
//Мнимая часть
public
constructor Create;
//Конструктор.
//Метод вычисления модуля.
function Modul():real;
//Метод вычисления аргумента.
function Argument():real;
//Метод записи комплексного
//числа в виде строки.
function ComplexToStr(): String;
end;
var
Form1: TForm1;
//Объявление переменной
//типа класс «комплексное число».
chislo: TComplex;
implementation
//описание конструктора
constructor TComplex.Create;

428

begin
x:=0; y:=0;
inherited Create;
end;
//Описание метода вычисления
//модуля комплексного числа.
function TComplex.Modul(): real;
begin
modul:=sqrt(x*x+y*y);
end;
//Описание метода вычисления
//аргумента комплексного числа.
function TComplex.Argument(): real;
begin
argument:=arctan(y/x)*180/pi;
end;
//Описание метода записи комплексного
//числа в виде строки.
function TComplex.ComplexToStr(): String;
begin
if y>=0 then
ComplexToStr:=FloatToStrF(x,ffFixed,5,2)+
'+' + FloatTostrF(y,ffFixed,5,2)+ 'i'
else
ComplexToStr:=FloatTostrF(x,ffFixed,5,2)+
FloatTostrF(y,ffFixed,5,2)+ 'i'
end;
//Обработчик кнопки: создание экземпляра класса
//«Комплексное число», вычисление его модуля и
//аргумента, вывод числа в алгебраической
//форме, его аргумента и модуля.
procedure TForm1.Button1Click(Sender: TObject);
Var Str1: String;
begin
//Создание объекта (экземпляра класса)
//типа «комплексное число».
chislo:=TComplex.Create;
//Ввод действительной и мнимой частей

429

//комплексного числа.
chislo.x:=StrToFloat(Edit1.Text);
chislo.y:=StrToFloat(Edit2.Text);
Str1:='Kompleksnoe chislo '+
chislo.ComplexToStr();
//Вывод на форму в поле Memo
//построчно комплексного числа,
Memo1.Lines.Add(Str1) ;
//его модуля
Str1:='Modul chisla '+
FloatToStrF(chislo.Modul(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
//и аргумента.
Str1:='Argument chisla '+
FloatToStrF(chislo.Argument(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
//Уничтожение объекта.
chislo.Free;
end;
initialization
{$I unit1.lrs}
end.

Рисунок 9.1: Результаты программы
работы с классом «Комплексное число»
В этом примере был написан конструктор для класса «комплексное число» без параметров. В Free Pascal можно написать конструктор с параметрами, который принимает входные значения и инициализирует поля класса этими значениями. Перепишем предыдущий

430

пример следующим образом. Действительную и мнимую части будем
считывать из полей ввода формы и передавать в конструктор для инициализации объекта типа комплексное число. Листинг программы
приведен ниже.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Memo1Change(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
type
TComplex = class
private x, y: real;
public
//Объявление конструктора.
constructor Create(a,b:real);
function Modul():real;
function Argument():real;
function ComplexToStr(): String;
end;
var

431

Form1: TForm1;
chislo: TComplex;
implementation
//Конструктор, который получает
//в качестве входных параметров
//два вещественных числа и записывает
//их в действительную и мнимую части
//комплексного числа.
constructor TComplex.Create(a,b:real);
begin
x:=a; y:=b;
inherited Create;
end;
function TComplex.Modul(): real;
begin
modul:=sqrt(x*x+y*y);
end;
function TComplex.Argument(): real;
begin
argument:=arctan(y/x)*180/pi;
end;
function TComplex.ComplexToStr(): String;
begin
if y>=0 then
ComplexToStr:=FloatToStrF(x,ffFixed,5,2)+
'+' + FloatTostrF(y,ffFixed,5,2)+ 'i'
else
ComplexToStr:=FloatTostrF(x,ffFixed,5,2)+
FloatTostrF(y,ffFixed,5,2)+ 'i'
end;
procedure TForm1.Button1Click(Sender: TObject);
Var Str1 : String;
x1, x2 : real;
begin
x1:=StrToFloat(Edit1.Text);
x2:=StrToFloat(Edit2.Text);
chislo:=TComplex.Create(x1,x2);
chislo.x:=StrToFloat(Edit1.Text);

432

chislo.y:=StrToFloat(Edit2.Text);
Str1:='Kompleksnoe chislo '+
chislo.ComplexToStr() ;
Memo1.Lines.Add(Str1) ;
Str1:='Modul chisla '+
FloatToStrF(chislo.Modul(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
Str1:='Argument chisla '+
FloatToStrF(chislo.Argument(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
chislo.Free;
end;
initialization
{$I unit1.lrs}
end.
9.2 Инкапсуляция
Инкапсуляция — один из важнейших механизмов объектно-ориентированного программирования (наряду с наследованием и полиформизмом). Класс представляет собой единство трех сущностей –
полей, свойств и методов, что и является инкапсуляцией. Инкапсуляция позволяет создавать класс как нечто целостное, имеющее определённую функциональность. Например, класс TForm содержит в
себе (инкапсулирует) все необходимое, чтобы создать диалоговое
окно.
Основная идея инкапсуляции – защитить поля от несанкционированного доступа. Поэтому целесообразно поля объявлять в разделе
private. Прямой доступ к полям объекта: чтение и обновление их
содержимого должно производиться посредством вызова соответствующих методов. В FreePascal для этого служат свойства класса.
Свойства - это специальный механизм классов, регулирующий
доступ к полям. Свойства объявляются с помощью зарезервированных слов property, read и write. Обычно свойство связано с некоторым полем и указывает те методы класса, которые должны использоваться при записи в это поле или при чтении из него. Синтаксис объявления свойств следующий:
propety имя_1: тип read имя_чтения write имя_2

433

Зарезервированное слово read описывает метод чтения свойств
объекта, а слово write описывает метод записи свойств объекта.
Имя_1 и имя_2 – соответственно имена методов, обеспечивающих
чтение или запись свойства.
Если необходимо, чтобы свойство было доступно только для чтения или только для записи, следует опустить соответственно часть
write или read.
Рассмотрим следующий пример. Создадим класс – многоугольник, имя класса TPolygon. Полями класса будут:
• K – количество сторон многоугольника;
• p – массив, в котором будут храниться длины сторон многоугольника.
Методами класса будут:
• конструктор Create, обнуляющий элементы массива p;
• Perimetr() - функция вычисления периметра фигуры;
• Show() - функция формирования сведений о фигуре (количество сторон и периметр);
• Set_Input() - функция проверки исходных данных.
Расположим на форме кнопку и метку. При щелчке по кнопке появляется окно ввода количества сторон многоугольника. Если количество сторон введено корректно, то инициализируется объект «Многоугольник» с количеством сторон, равным введенному, в противном
случае количество сторон многоугольника принимается равным по
умолчанию 50. После этого вычисляется периметр фигуры и результаты выводятся на форму в метке Label1.
Ниже приведен листинг программы с комментариями, результаты
работы программы можно увидеть на рис. 9.2.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;

434

Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
type
//Объявление класса многоугольник Tpolygon.
TPolygon = class
//Закрытые поля.
Private
K : integer;
p : array of real;
//Открытые методы.
Public
constructor Create;
//Конструктор.
//Метод вычисления периметра.
function Perimetr():real;
//Метод формирования сведений.
function Show():String;
Protected
//Защищенные методы.
//Процедура проверки данных.
procedure Set_Input(m:integer);
Published
//Объявление свойства n.
//Свойство n оперирует полем K.
//В описании свойства после слова read
//стоит имя поля — K. Это значит, что
//функция чтения отсутствует и пользователь
//может читать непосредственно значение поля.
//Ссылка на функцию Set_Input после
//зарезервированного слова write означает,
//что с помощью этой функции в поле K будут
//записываться новые значения.
Property n: integer read K write Set_Input;
end;
var

435

Form1: TForm1;
//Объявление переменной типа
//класс многоугольник.
Figure: TPolygon;
implementation
//Описание конструктора.
constructor TPolygon.Create;
var i:integer;
begin
K:=50;//Присваивание начальных значений полям.
//Выделение памяти под массив p.
SetLength(p,K);
for i:=0 to K-1 do p[i]:=0;
inherited Create;
end;
//Функция вычисления периметра.
function TPolygon.Perimetr():real;
var Sum:real; i:integer;
begin
Sum:=0;
for i:=0 to K-1 do Sum:=Sum+p[i];
Perimetr:=Sum;
end;
//Метод формирования сведений о фигуре.
function TPolygon.Show():String;
begin
Show:='Многоугольник с количеством сторон '+
IntToStr(K)+chr(13)+'Периметр = '+
FloatToStr(Perimetr())
end;
//Метод записи данных в поле K.
procedure TPolygon.Set_Input(m:integer);
begin
//Если введенное значение положительное число,
//то записать его в поле K,
//иначе вернуться к начальному значению.
if m>1 then K:=m else K:=50;
end;

436

{TForm1 }
//Обработка события.
procedure TForm1.Button1Click(Sender: TObject);
var i, m:integer;
s:string;
begin
//Ввод количества сторон многоугольника.
s:=InputBox('Ввод','Введите количество сторон
многоугольника','6');
Val(s,m);
//Инициализация объекта.
Figure:=TPolygon.Create;
with Figure do
begin
//Метод проверки исходных данных.
Set_Input(m);
//Формирование массива случайных чисел.
for i:=0 to K-1 do p[i]:=random(50);
//Обращение к методу вычисления периметра.
s:=Show();
end;
//Вывод результатов в окно формы.
Label1.Caption:= s;
end;
initialization
{$I unit1.lrs}
end.

Рисунок 9.2: Результат работы
программы с классом многоугольник

437

9.3 Наследование и полиформизм
Второй основополагающей составляющей объектно-ориентированного программирования является наследование. Смысл наследования заключается в следующем: если нужно создать новый класс,
лишь немного отличающийся от старого, то нет необходимости в
переписывании заново уже существующих полей и методов. В этом
случае объявляется новый класс, который является наследником уже
имеющегося, и добавляются к нему новые поля, методы и свойства.
При создании новый класс является наследником членов ранее определенного базового класса (родителя). Класс-наследник является
производным от базового, причем он сам может выступать в качестве
базового класса для вновь создаваемых классов.
В Object Pascal все классы являются потомками класса TObject.
Поэтому если вы создаете дочерний класс прямо от класса TObject,
то в определении его можно не упоминать.
Производный класс наследует от класса-предка поля и методы;
если имеет место совпадение имен методов, то говорят, что они перегружаются. В зависимости от того, какие действия происходят при
вызове, методы делятся на следующие группы:
• статические методы;
• виртуальные методы;
• динамические методы.
По умолчанию все методы статические. Эти методы полностью
перегружаются в классах-потомках при их переопределении. При
этом можно полностью изменить объявление метода. Если обращаться к такому методу у объекта базового класса, то будет работать метод
класса-родителя. Если обращаться к методу у производного класса, то
будет работать новый метод.
Виртуальные и динамические методы имеют в базовом и производном классах те же имена и типы. В классах-наследниках эти методы перегружены. В зависимости от того, с каким классом работают,
соответственно и вызывается метод этого класса.
Основная разница между виртуальными и динамическими методами — в способе их вызова. Информация о виртуальных методах
хранится в таблице виртуальных методов VMT. В VMT хранятся виртуальные методы данного класса и всех его предков. При создании
потомка класса вся VMT предка переносится в потомок и там к ней

438

добавляются новые методы. Поиск нужного метода занимает мало
времени, так как класс имеет всю информацию о своих виртуальных
методах. Динамические методы не дублируются в таблице динамических методов DMT потомка. DMT класса содержит только методы,
объявленные в этом классе. При вызове динамического метода сначала осуществляется поиск в DMT данного класса, и если метод не
найден – то в DMT предка класса и т.д. Таким образом использование
виртуальных методов требует большего расхода памяти из-за необходимости хранения массивных VMT всех классов, зато они вызываются быстрее.
Изменяя алгоритм того или иного метода в производных классах,
программист может придавать этим потомкам отсутствующие у родителя специфические свойства. Для изменения метода необходимо
перегрузить его в потомке, т. е. объявить в наследнике одноименный
метод и реализовать в нем нужные действия. В результате в объекте-родителе и объекте-потомке будут действовать два одноименных
метода, имеющие разную алгоритмическую основу. Это называется
полиморфизмом объектов.
Виртуальные и динамические методы объявляются так же, как и
статические, только в конце описания метода добавляются служебные
слова virtual или dynamic:
type
имя_родителя =class
...
метод; virtual;
...
end;
Чтобы перегрузить в классе-наследнике виртуальный метод, нужно после его объявления написать ключевое слово override:
type
имя_наследника=class (имя_родителя)
...
метод; override;
...
end;
Рассмотрим наследование в классах на следующем примере. Создадим базовый класс Ttriangle (треугольник) с полями класса –

439

координаты вершин треугольника. В классе будут следующие методы:
• Proverka() – метод проверки существования треугольника
(если 3 точки лежат на одной прямой, то треугольник не существует);
• Perimetr() – метод вычисления периметра треугольника;
• Square() – - метод вычисления площади;
• Методы вычисления длин сторон a(), b(), c();
• Set_Tr() – метод получения координат;
• Show() – метод формирования сведений о треугольнике.
На основе этого класса создадим производный класс
R_TTriangle (равносторонний треугольник), который наследует
все поля и методы базового класса, но методы проверки и формирования сведений о фигуре перегружаются по другому алгоритму.
На форме поместим метку, кнопку и по 6 компонентов типа
TEdit для ввода координат вершин для двух треугольников. После
щелчка по кнопке создаются два объекта типа «Треугольник» и «Равносторонний треугольник», вычисляются периметр и площадь каждого треугольника, и результаты выводятся ниже в компоненты Label1
Label2. Далее приведен листинг программы с комментариями.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: Tbutton; //кнопка Расчет
//массивы x1, y1 – координаты вершин
//1-го треугольника частный случай)
//массивы x1, y1 – координаты вершин
//2-го треугольника (равностороннего)
Edit1: Tedit; //для ввода координаты x1[1]
Edit10: TEdit; //для ввода координаты y2[2]
Edit11: TEdit; //для ввода координаты x2[3]

440

Edit12: TEdit; //для ввода координаты y2[3]
Edit2: TEdit; //для ввода координаты y1[1]
Edit3: TEdit; //для ввода координаты x2[2]
Edit4: TEdit; //для ввода координаты y1[2]
Edit5: TEdit; //для ввода координаты x1[3]
Edit6: TEdit; //для ввода координаты y1[3]
Edit7: TEdit; //для ввода координаты x2[1]
Edit8: TEdit; //для ввода координаты y2[1]
Edit9: TEdit; //для ввода координаты x2[2]
Label1: TLabel;
Label10: TLabel;
Label11: TLabel;
Label12: TLabel;
Label13: TLabel;
Label14: TLabel;
Label15: TLabel;
Label16: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Объявление базового класса «треугольник».
type
TTriangle=class
Private
//Массивы, в которых хранятся координаты
//вершин треугольника.
x, y:array[0..2] of real;

441

Public
constructor Create; //конструктор
//Метод получения исходных данных.
procedure Set_Tr(a,b:array of real);
//Методы вычисления сторон треугольника.
function a():real;
function b():real;
function c():real;
//Виртуальный метод проверки существования
//треугольника, который будет перегружен
//в производном классе.
function Proverka():boolean;
virtual;
//Метод вычисления периметра.
function Perimetr():real;
//Метод вычисления площади.
function Square():real;
//Виртуальный метод формирования
//сведений о треугольнике.
function Show():string;
virtual;
end;
//Объявление производного
//класса «равносторонний треугольник».
type
R_TTriangle=class(TTriangle)
public
//Перегружаемые методы проверки, что
//треугольник является равносторонним,
//и формирования сведений о треугольнике.
function Proverka():boolean; override;
function Show():string;
override;
end;
var
Form1: TForm1;
//Объявление переменной типа
//класс «треугольник».
Figura1: Ttriangle;
//Объявление переменной типа
//класс «равносторонний треугольник».

442

Figura2: R_TTriangle;
implementation
//Конструктор, который обнуляет
//массивы координат.
constructor TTriangle.Create;
var i:integer;
begin
for i:=0 to 2 do
begin
x[i]:=0; y[i]:=0;
end;
end;
//Метод получения координат вершин.
procedure TTriangle.Set_Tr(a,b:array of real);
var i:integer;
begin
for i:=0 to 2 do
begin
x[i]:=a[i]; y[i]:=b[i];
end;
end;
//Методы вычисления сторон треугольника a, b, c
function TTriangle.a():real;
begin
a:=sqrt(sqr(x[1]-x[0])+sqr(y[1]-y[0]));
end;
function TTriangle.b():real;
begin
b:=sqrt(sqr(x[2]-x[1])+sqr(y[2]-y[1]));
end;
function TTriangle.c():real;
begin
c:=sqrt(sqr(x[0]-x[2])+sqr(y[0]-y[2]));
end;
//Методы вычисления периметра треугольника.
function TTriangle.Perimetr():real;
begin
Perimetr:=a()+b()+c();

443

end;
//Функции вычисления площади треугольника.
function TTriangle.Square():real;
var p:real;
begin
p:=Perimetr()/2; //полупериметр
Squire:=sqrt((p-a())*(p-b())*(p-c()));
end;
//Метод проверки существования треугольника:
//если в уравнение прямой, проходящей через
//две точки, подставить координаты 3-й точки
//и при этом получится равенство, значит, три
//точки лежат на одной прямой и построение
//треугольника невозможно.
function TTriangle.Proverka():boolean;
begin
if (x[0]-x[1])/(x[0]-x[2])=
(y[0]-y[1])/(y[0]-y[2]) then
Proverka:=false
else Proverka:=true
end;
//Метод формирования строки –
//сведений о треугольнике.
function TTriangle.Show():string;
begin
//Если треугольник существует,
//то формируем строку сведений о треугольнике.
if Proverka() then
Show:='Tr'+chr(13)+'a='+
FloatToStrF(a(),ffFixed,5,2)+
chr(13)+'b='+FloatToStrF(b(),ffFixed,5,2)+
chr(13)+'c='+FloatToStrF(c(),ffFixed,5,2)+
chr(13)+'P='+FloatToStrF(Perimetr(),ffFixed,5,2)+
chr(13)+'S='+FloatToStrF(Square(),ffFixed,5,2)
else
Show:='Not Triangle';
end;

444

//Метод проверки существования
//равностороннего треугольника.
function R_TTriangle.Proverka():boolean;
begin
if (a()=b()) and(b()=c()) then
Proverka:=true
else
Proverka:=false
end;
//Метод формирования сведений
//о равностороннем треугольнике.
function R_TTriangle.Show():string;
begin
//Если треугольник равносторонний,
//то формируем строку сведений.
if Proverka()=true then
Show:='Tr'+chr(13)+'a='+
FloatToStrF(a(),ffFixed,5,2)+
chr(13)+'P='+
FloatToStrF(Perimetr(),ffFixed,5,2)+chr(13)
+'S='+FloatToStrF(Square(),ffFixed,5,2)
else
Show:='Not R_Triangle';
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: Tobject);
//Массивы x1, y1 – координаты треугольника.
//Массивы x2, y2 – координаты
//равностороннего треугольника
var x1, y1, x2, y2 :array[1..3] of real;
s:string;
begin
//Чтение координат треугольников
//из полей ввода диалогового окна.
x1[1]:=StrToFloat(Edit1.Text);
y1[1]:=StrToFloat(Edit2.Text);
x1[2]:=StrToFloat(Edit3.Text);
y1[2]:=StrToFloat(Edit4.Text);

445

x1[3]:=StrToFloat(Edit5.Text);
y1[3]:=StrToFloat(Edit6.Text);
x2[1]:=StrToFloat(Edit7.Text);
y2[1]:=StrToFloat(Edit8.Text);
x2[2]:=StrToFloat(Edit9.Text);
y2[2]:=StrToFloat(Edit10.Text);
x2[3]:=StrToFloat(Edit11.Text);
y2[3]:=StrToFloat(Edit12.Text);
//Инициализация объекта класса треугольник.
Figura1:=TTriangle.Create;
//Инициализация объекта класса
//равносторонний треугольник.
Figura2:=R_TTriangle.Create;
Figura1.Set_Tr(x1,y1);
Figura2.Set_Tr(x2,y2);
//Вызов методов формирования
//сведений и вывод строки на форму.
s:=Figura1.Show();
Label15.Caption:= S;
s:=Figura2.Show();
Label16.Caption:= S;
//уничтожение объектов
Figura1.Free;
Figura2.Free;
end;
initialization
{$I unit1.lrs}
end.
Результаты работы программы представлены на рис. 9.3.
Абстрактный метод – это виртуальный или динамический метод,
реализация которого не определена в том классе, где он объявлен.
Предполагается, что этот метод будет перегружен в классе-наследнике. Вызывают метод только в тех классах, где он перезагружен. Объявляется абстрактный метод при помощи служебного слова
abstract после слов virtual или dynamic, например:
метод1;
virtual;
abstract;

446

Рисунок 9.3: Результаты работы программы расчета параметров треугольников
Рассмотрим следующий пример. Создадим базовый класс
TFigure (фигура). На основании этого класса можно построить
производные классы для реальных фигур (окружность, четырехугольник и т.д.). В нашем примере рассмотрим два класса-наследника
TCircle (окружность) и TRectangle (прямоугольник). На форму
поместим кнопку. При щелчке по кнопке специализируются 2 объекта
типа «Окружность» и «Прямоугольник», рассчитываются параметры
фигур : периметр (длина окружности), площадь, результаты выводятся в компоненты Label1 и label2. Ниже приведен листинг программы.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;

447

Label1: TLabel;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Объявление базового класса «фигура».
type
TFigure=class
private
n:integer; //Количество сторон фигуры.
p:array of real; //Массив длин сторон фигуры.
public
//Абстрактный конструктор
//в каждом производном классе будет
//перегружаться.
constructor Create;
virtual; abstract;
//Метод вычисления периметра
function Perimetr():real;
//Абстрактный метод вычисления площади,в каждом
//производном классе будет перегружаться
//реальным методом.
function Square():real;virtual; abstract;
//Абстрактный метод формирования
//сведений о фигуре
//в каждом производном классе
//будет перегружаться.
function Show():string;virtual; abstract;
end;
//Объявление производного класса «окружность».
type
TCircle=class(TFigure)
public
constructor Create;
override;
function Perimetr():real;
function Square():real;
override;

448

function Show():string;
override;
end;
//Объявление производного
//класса «прямоугольник».
type
TRectangle=class(TFigure)
public
constructor Create;
override;
function Square():real;
override;
function Show():string;
override;
end;
var
Form1: Tform1;
//Объект типа класса окружность.
Figura1: Tcircle;
//Объект типа класса прямоугольник.
Figura2:TRectangle;
implementation
//Описание метода вычисления
//периметра для базового класса.
function TFigure.Perimetr():real;
var
i:integer;
s:real;
begin
s:=0;
for i:=0 to n-1 do
s:=s+p[i];
Perimetr:=s;
end;
//Описание конструктора в классе окружность
//перезагрузка абстрактного
//родительского конструктора.
constructor TCircle.Create;
begin
//Количество сторон для окружности 1.
n:=1;
//Выделяем память под 1 элемент массива.
SetLength(p,n);

449

p[0]:=5;
//Сторона - радиус окружности.
end;
//Перезагрузка метода вычисления периметра.
function TCircle.Perimetr():real;
begin
//Вычисление длины окружности.
Perimetr:=2*Pi*p[0];
end;
//Перезагрузка метода вычисления площади
function TCircle.Square():real;
begin
Square:=Pi*sqr(p[0]);
end;
//Описание метода формирования
//строки сведений об окружности.
//Перезагрузка родительского
//абстрактного метода.
function TCircle.Show():string;
begin
Show:='Circle'+chr(13)+'r='+
FloatToStr(p[0])+chr(13)+'P='+
FloatToStr(Perimetr())+
chr(13)+'S='+FloatToStr(Square());
end;
//Описание конструктора в классе прямоугольник.
//перезагрузка абстрактного
//родительского конструктора.
constructor TRectangle.Create;
begin
n:=2; //Количество сторон — две.
//Выделение памяти под два элемента.
SetLength(p,n);
p[0]:=4; p[1]:=2; //Длины сторон.
End;
//Перезагрузка абстрактного
//родительского метода,
//вычисления площади фигуры.

450

function TRectangle.Square():real;
begin
Square:=p[0]*p[1];
end;
//Описание метода формирования
//сведений о прямоугольнике.
//Перезагрузка родительского
//абстрактного метода.
function TRectangle.Show():string;
begin
Show:='Rectangle'+chr(13)+'a='+
FloatToStr(p[0])+' b='+
FloatToStr(p[1])+
chr(13)+'P='+FloatToStr(Perimetr())+
chr(13)+'S='+FloatToStr(Square());
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var s:string;
begin
//Инициализация объекта типа окружность.
Figura1:=TCircle.Create;
//Инициализация объекта типа прямоугольник.
Figura2:=TRectangle.Create;
//Формирование сведений о фигурах
//и вывод результатов на форму.
s:=Figura1.Show() ;
label1.Caption:= s ;
s:=Figura2.Show() ;
label2.Caption:= s ;
Figura1.Free;
Figura2.Free;
end;
initialization
{$I unit1.lrs}
end.

451

9.4 Перегрузка операций
Во Free Pascal можно перегрузить не только функции, но и операции, например, можно запрограммировать, чтобы операция * при работе с матрицами осуществляла умножение матриц, а при работе с
комплексными числами – умножение комплексных чисел.
Для этого в программе нужно написать специальную функцию –
метод. Объявление метода перегрузки записывается после объявления
класса и выглядит так:
operator symbols(параметры:тип)имя_результата:тип;
где operator – служебное слово;
symbols – символ перегружаемой операции;
параметры – имена переменных, участвующих в перегрузке оператора;
Описывают метод перегрузки так же, как и другие методы, после
ключевого слова implemention того модуля, в котором объявлен
класс.
Рассмотрим несколько примеров.
Задача 9.1. Создать класс работы с комплексными числами, в котором перегрузить операции сложения и вычитания.
На форме разместим четыре компонента типа TEdit для ввода
действительной и мнимой частей двух комплексных чисел. Также создадим компонент типа TMemo для вывода результатов и кнопку. При
щелчке по кнопке создаются четыре объекта типа «комплексное число». Первое и второе числа инициализируются введенными данными.
Третье формируется как результат сложения первых двух, а четвертое
— как разность этих же чисел. Текст программы с комментариями
приведен ниже, на рис. 9.4 показано окно работы программы.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: Tbutton;

452

//Для ввода действительной части первого числа.
Edit1: Tedit;
//Для ввода мнимой части первого числа.
Edit2: TEdit;
//Для ввода действительной части второго числа.
Edit3: TEdit;
//Для ввода мнимой части второго числа.
Edit4: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Memo1: Tmemo; //Поле для вывода результатов.
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Объявление класса – комплексное число.
type
TComplex = class
private
x: real;
//Действительная часть.
y: real;
//Мнимая часть.
public
constructor Create;
//Конструктор.
//Функция вычисления модуля комплексного числа.
function Modul():real;
//Функция вычисления аргумента
//комплексного числа;
function Argument():real;
//Функция, представляющая комплексное число
//в виде строки для вывода.
function ComplexToStr(): String;
end;

453

//Методы перегрузки оператора «+»
//с комплексными числами.
operator +(const a, b: TComplex)r: TComplex;
//Методы перегрузки оператора «-»
//с комплексными числами.
operator -(const a, b: TComplex)r: TComplex;
var
Form1: TForm1;
//Объявление переменных типа комплексное число.
chislo1: Tcomplex;
chislo2: TComplex;
chislo3: TComplex;
chislo4: TComplex;
implementation
//Описание конструктора.
constructor TComplex.Create;
begin
x:=0; y:=0;
inherited Create;
end;
function TComplex.Modul(): real;
begin
modul:=sqrt(x*x+y*y);
end;
function TComplex.Argument(): real;
begin
argument:=arctan(y/x)*180/pi;
end;
//Методы перегрузки оператора «+».
//переменные a и b – комплексные числа,
//которые складываются,
//r – результирующее комплексное число
operator +(const a, b: TComplex)r: TComplex;
begin
r:=TComplex.Create; //Инициализация объекта.
//Действительная часть нового комплексного
//числа формируется как результат сложения
//действительных частей первого и второго

454

//операндов. Мнимая часть нового комплексного
//числа формируется как результат сложения
//мнимых частей первого и второго операндов.
//Операнды - переменные типа комплексное
//число, передаваемые в метод.
r.x:=a.x+b.x;
r.y:=a.y+b.y;
end;
//Методы перегрузки оператора «-».
operator -(const a, b: TComplex)r: TComplex;
begin
r:=TComplex.Create; //Инициализация объекта.
//Действительная часть нового комплексного
//числа формируется как разность действительных
//частей первого и второго операндов. Мнимая
//часть нового комплексного числа формируется
//как разность мнимых частей первого и второго
//операндов. Операнды - переменные типа
//комплексное число, передаваемые в метод.
r.x:=a.x-b.x;
r.y:=a.y-b.y;
end;
function TComplex.ComplexToStr(): String;
begin
if y>=0 then
ComplexToStr:=FloatToStrF(x,ffFixed,5,2)+'+'+
FloatTostrF(y,ffFixed,5,2)+ 'i'
else
ComplexToStr:=FloatTostrF(x,ffFixed,5,2)+
FloatTostrF(y,ffFixed,5,2)+ 'i'
end;
procedure TForm1.Button1Click(Sender: TObject);
Var Str1 : String;
begin
//Инициализация объектов.
//chislo1, chislo2 – исходные комплексные
//числа, вводимые с формы.
//chislo3 – Комплексное число,

455

//получаемое сложением двух исходных чисел.
//chislo4 – Комплексное число, получаемое
//вычитанием второго числа из первого.
chislo1:=TComplex.Create;
chislo2:=TComplex.Create;
chislo3:=TComplex.Create;
chislo4:=TComplex.Create;
//Чтение действительной и мнимой частей
//двух исходных комплексных чисел
//из полей ввода формы.
chislo1.x:=StrToFloat(Edit1.Text);
chislo1.y:=StrToFloat(Edit2.Text);
chislo2.x:=StrToFloat(Edit3.Text);
chislo3.y:=StrToFloat(Edit4.Text);
//Для сложения двух комплексных чисел можно
//использовать операцию +,так как она
//перегружена для этого класса.
chislo3:=chislo1+chislo2;
//Для вычитания двух комплексных чисел
//можно использовать операцию -,так как она
//перегружена для этого класса.
chislo4:=chislo1-chislo2;
//Результат сложения двух чисел преобразуется
//в строку для вывода в поле Memo1.
Str1:='chislo1+chislo2 '+
chislo3.ComplexToStr() ;
Memo1.Lines.Add(Str1) ;
//Значение модуля преобразуется
//в строку для вывода в поле Memo1.
Str1:='Modul chisla '+
FloatToStrF(chislo3.Modul(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1);
//Значение аргумента преобразуется в строку
//для вывода в поле Memo1.
Str1:='Argument chisla '+
FloatToStrF(chislo3.Argument(), ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
//Результат разности двух чисел преобразуется

456

//в строку для вывода в поле Memo1.
Str1:='chislo1-chislo2 '+
chislo4.ComplexToStr() ;
Memo1.Lines.Add(Str1) ;
Str1:='Modul chisla '+
FloatToStrF(chislo4.Modul(),ffFixed, 5, 2);
Memo1.Lines.Add(Str1) ;
Str1:='Argument chisla '+
FloatToStrF(chislo4.Argument(), ffFixed,5,2);
Memo1.Lines.Add(Str1) ;
end;
initialization
{$I unit1.lrs}end.

Рисунок 9.4: Пример работы программы
к задаче 9.1
Задача 9.2. Создать класс работы с квадратными матрицами, в котором перегрузить операции сложения и умножения. В классе создать метод проверки, что матрица является единичной.
В классе созданы два метода перегрузки операции сложения и два
метода перегрузки операции умножения. Это методы сложения и
умножения матриц, а также методы добавления к матрице числа и
умножения матрицы на число.
На форму поместим кнопку и 8 компонентов типа TLabel для
вывода результатов. При щелчке по кнопке создаются 6 объектов типа
«матрица», все они заполняются случайными числами. Третья матрица затем рассчитывается как сумма первых двух. Четвертая матрица

457

— результат умножения первой матрицы на вторую. Пятая матрица
получается из первой путем добавления к ней числа 10, а шестая —
умножением первой матрицы на число 5. Также первая и вторая матрицы проверяются, не являются ли они единичными. Текст программы с комментариями приведен далее.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
procedure Button1Click(Sender: TObject);
procedure Memo1Change(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Объявление класса матрица.
type
TMatrix = class
private
//элементы матрицы
x: array [0..5,0..5]of real;
public
constructor Create;
//Конструктор.
//Метод формирования строки,
//выводящей элементы матрицы.

458

function MatrixToStr(): String;
//Функция проверки, является ли
//матрица единичной.
function Pr_Edin(): boolean;
end;
//Методы перегрузки операции «+» //сложение двух матриц.
operator +(const a, b: TMatrix)r: Tmatrix;
//Методы перегрузки операции «+» //добавление к матрице вещественного числа.
operator+(const a:TMatrix;b:real)r:TMatrix;
//Метоы перегрузки операции «*» //умножение двух матриц.
operator *(const a, b: TMatrix)r: Tmatrix;
//Методы перегрузки операции «*» //умножение матрицы на вещественное число.
operator *(const a:TMatrix;b:real)r: TMatrix;
var
Form1: TForm1;
matr1: TMatrix;
matr2: TMatrix;
matr3: TMatrix;
matr4: TMatrix;
matr5: TMatrix;
matr6: TMatrix;
implementation
//Конструктор в классе матрица, который
//заполняет матрицу случайными целыми числами.
constructor TMatrix.Create;
var i, j : integer;
begin
for i:=0 to 4 do
for j:=0 to 4 do
x[i,j]:=Random(10);
inherited Create;
end;
//Функция, проверяющая,
//является ли матрица единичной.

459

function TMatrix.Pr_Edin():boolean;
var i, j : integer;
begin
//Предполагаем, что матрица единичная.
Result:=true;
for i:=0 to 4 do
for j:=0 to 4 do
//Если на главной диагонали элемент не 1
//или вне главной диагонали элемент не 0,
if ((i=j)and(x[i,j]1))or((ij)and(x[i,j]0))
then
begin
//то матрица не является единичной.
Result:=false;
break; //выход из цикла
end;
end;
//Метод перегрузки оператора «+» //сложение двух матриц
operator +(const a, b: TMatrix)r: TMatrix;
var i, j: integer;
begin
r:=TMatrix.Create;
for i:=0 to 4 do
for j:=0 to 4 do
r.x[i,j]:=a.x[i,i]+b.x[i,j];
end;
//Методы перегрузки оператора «*» //перемножение двух матриц.
operator *(const a, b: TMatrix)r: TMatrix;
var i, j, k: integer;
s: real;
begin
r:=TMatrix.Create;
for i:=0 to 4 do
for j:=0 to 4 do
begin
r.x[i,j]:=0;

460

for k:=0 to 4 do
r.x[i,j]:=
r.x[i,j]+a.x[i,k]*b.x[k,j];
end;

end;
//Методы перегрузки оператора «+» //сложение матрицы и вещественного числа.
operator +(const a: TMatrix;b:real)r: TMatrix;
var i, j: integer;
begin
r:=TMatrix.Create;
for i:=0 to 4 do
for j:=0 to 4 do
r.x[i,j]:=a.x[i,j]+b;
end;
//Методы перегрузки оператора «*» //умножение матрицы на вещественное число
operator *(const a: TMatrix;b:real)r: TMatrix;
var i, j: integer;
begin
r:=TMatrix.Create;
for i:=0 to 4 do
for j:=0 to 4 do
r.x[i,j]:=a.x[i,j]*b;
end;
//Методы формирования строки
//с элементами матрицы.
function TMatrix.MatrixToStr(): String;
var s:string;
i, j :integer;
begin
s:='';//Вначале строка пустая
for i:=0 to 4 do
begin
for j:=0 to 4 do
//Добавление к s строки, которая представляет
//собой элемент матрицы и пробел.
s:=s+FloatTostrF(x[i,j],ffFixed,5,2)+' ';

461

//Формирование новой строки матрицы.
s:=s+chr(13);
end;
MatrixToStr:=s;
end;
//Обработка кнопки Пуск:
//создание экземпляров класса Матрица,
//вычисление результирующих матриц путем
//сложения, умножения исходных матриц,
//умножение матрицы на число
procedure TForm1.Button1Click(Sender: TObject);
Var Str1 : String;
begin
//Инициализация объектов:
//matr1, matr2 – исходные матрицы,
//заполняемые случайными числами;
//matr3 – матрица, получаемая
//сложением двух исходных матриц;
//matr4 – матрица, получаемая умножением
//двух исходных матриц;
//matr5 – матрица, получаемая добавлением
//к первой матрице числа 10;
//matr6 – матрица, получаемая умножением
//первой матрицы на число 5.
matr1:=TMatrix.Create;
matr2:=TMatrix.Create;
matr3:=TMatrix.Create;
matr4:=TMatrix.Create;
matr5:=TMatrix.Create;
matr6:=TMatrix.Create;
//Вычисление матриц matr3, matr4, matr5, matr6
//с помощью перегрузки операторов.
matr3:=matr1+matr2;
matr4:=matr1*matr2;
matr5:=matr1+10;
matr6:=matr1*5;
//Формирование строки вывода и ее вывод
//в метку Label1 матрицы matr1.

462

Str1:='Matrix1 '+chr(13)+matr1.MatrixToStr() ;
Label1.Caption:= Str1;
//Проверка, является ли матрица matr1
//единичной,и вывод соответствующего сообщения.
if matr1.Pr_Edin()=true then
Str1:='Matrix1 edinichnaya'
else
Str1:='Matrix1 ne edinichnaya';
Label5.Caption:= Str1 ;
//Проверка, является ли матрица matr2
//единичной,и вывод соответствующего сообщения.
if matr2.Pr_Edin()=true then
Str1:='Matrix2 edinichnaya'
else
Str1:='Matrix2 ne edinichnaya';
Label6.Caption:= Str1 ;
Str1:='Matrix2 '+chr(13)+matr2.MatrixToStr() ;
Label2.Caption:= Str1 ;
//Вывод элементов матрицы matr3=matr1+matr2.
Str1:='Matrix1+Matrix2 '+
chr(13)+matr3.MatrixToStr() ;
Label3.Caption:= Str1 ;
//Вывод элементов матрицы matr4=matr1*matr2.
Str1:='Matrix1*Matrix2 '+
chr(13)+matr4.MatrixToStr() ;
Label4.Caption:= Str1 ;
//Вывод элементов матрицы matr5=matr1+10.
Str1:='Matrix1+10 '+
chr(13)+matr5.MatrixToStr() ;
Label7.Caption:= Str1 ;
//Вывод элементов матрицы matr5=matr1*5.
Str1:='Matrix1*5 '+chr(13)+
matr6.MatrixToStr() ;
Label8.Caption:= Str1 ;
end;
initialization
{$I unit1.lrs}
end.

463

Результат работы программы показан на рис. 9.5 .

Рисунок 9.5: Результаты работы программы задачи 9.2
ЗАДАЧА 9.3. Создать класс – обыкновенная дробь, в котором
перегрузить операции < и >.
На форму поместим четыре компонента TEdit для ввода числителей и знаменателей двух обыкновенных дробей и компонент Memo1
для вывода результатов. Также разместим кнопку, при щелчке по которой инициализируются два объекта типа «обыкновенная дробь», затем они сравниваются и результаты выводятся в Memo1. Ниже приведен листинг программы с комментариями, на рис. 9.6 показаны результаты работы программы.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: Tbutton;

464

//Поле для ввода числителя первой дроби.
Edit1: Tedit;
//Поле для ввода знаменателя первой дроби.
Edit2: Tedit;
//Поле для ввода числителя второй дроби.
Edit3: Tedit;
//Поле для ввода знаменателя второй дроби.
Edit4: Tedit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Memo1: Tmemo; //Поле для вывода результатов.
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
//Объявление класса – обыкновенная дробь.
type
TOb_Drob = class
private
Ch: integer;
//Числитель.
Zn: integer;
//Знаменатель.
public
//Конструктор.
constructor Create(a, b:integer);
//Метод формирования строки для вывода дроби.
function DrobToStr(): String;
end;
//Метод перегрузки оператора «(const a, b: TOb_Drob)r: boolean;
var
Form1: Tform1;
//Объявление переменных типа класс

465

//обыкновенная дробь.
d1, d2: TOb_Drob;
implementation
//Конструктор.
constructor TOb_drob.Create(a, b:integer);
begin
Ch:=a; Zn:=b;
inherited Create;
end;
//Метод перегрузки оператора « b.Ch * a.Zn then
r:=true
else r:=false ;
end;
//Метод формирования строки
//для вывода дроби на форму.
function TOb_Drob.DrobToStr(): String;
begin
if Zn0 then
if Ch*Zn>0 then
DrobToStr:=IntToStr(Ch)+'/'+
IntToStr(Zn)
else
DrobToStr:='-'+IntToStr(abs(Ch))+'/'+
IntTostr(abs(Zn))
else
DrobToStr:='Dividing by a zero'

466

end;
procedure TForm1.Button1Click(Sender: TObject);
Var Str1 : String;
a, b: integer;
begin
//Чтение данных из полей ввода формы:
a:=StrToInt(Edit1.Text); //числитель,
b:=StrToInt(Edit2.Text); //знаменатель.
//Инициализация первой дроби.
d1:=TOb_Drob.Create(a,b);
//Чтение данных из полей ввода формы.
a:=StrToInt(Edit3.Text);
b:=StrToInt(Edit4.Text);
//Инициализация второй дроби.
d2:=TOb_Drob.Create(a,b);
//Формирование строки вывода
//и добавление ее в поле Memo1.
//Вывод исходной дроби d1.
Str1:='Drob 1 '+d1.DrobToStr() ;
Memo1.Lines.Add(Str1) ;
//Выводисходной дроби d2.
Str1:='Drob2 '+d2.DrobToStr() ;
Memo1.Lines.Add(Str1) ;
//сравнение дробей с помощью перегрузки
//операторов < и > и вывод сообщения.
if d1d2
then
Str1:='Drob1 > Drob2'
else
Str1:='Drob1 = Drob2';
Memo1.Lines.Add(Str1) ;
end;
initialization
{$I unit1.lrs}
end.

467

Рисунок 9.6: Результаты работы
программы задачи 9.3
9.5 Задачи для самостоятельного решения
1. Создать класс комплексное число в алгебраической форме z=x+
y ⋅i , поля класса – действительная (x) и мнимая (y) части числа.
Методы класса: вычисление корня комплексного числа, вывод
комплексного числа. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление и умножение комплексных чисел.
2. Создать класс квадратная матрица, поля класса – размерность
и элементы матрицы. Метод класса: вывод матрицы. В классе предусмотреть методы перегрузки операций: сложение, вычитание, умножение матриц, проверку, является ли одна матрица обратной другой
( A⋅A−1=E ).
3. Создать класс вектор на плоскости, поля класса – координаты
вектора. Методы класса: вычисление направляющих косинусов вектора, вывод всех характеристик вектора. В классе предусмотреть методы перегрузки операций: сложение, скалярное и векторное произведения векторов.
4. Создать класс обыкновенная дробь, поля класса – числитель и
знаменатель. Методы класса: сокращение дроби, вывод дроби. В классе предусмотреть методы перегрузки операций: сложение, вычитание,

468

деление и умножение дробей.
5. Создать класс квадрат, член класса – длина стороны. Предусмотреть в классе методы вычисления и вывода сведений о фигуре –
периметр, площадь, диагональ. Создать производный класс – куб, добавить в класс метод определения объема фигуры, перегрузить методы расчета площади и вывода сведений о фигуре.
6. Создать класс квадратная матрица, поля класса – размерность
и элементы матрицы. Методы класса: вычисление суммы всех элементов матрицы, вывод матрицы. В классе предусмотреть методы
перегрузки операций: сложение, вычитание, умножение матриц,
умножение матрицы на число.
7. Создать класс прямая, поля класса – координаты двух точек
(x1, y1) и (x2, y2). Метод класса: вывод уравнения прямой вида
y= ax + b. В классе предусмотреть методы перегрузки операций:
проверка параллельности двух прямых, определение угла между двумя прямыми.
8. Создать класс комплексное число в тригонометрической форме
a=cos i sin  , поля класса – модуль (ρ) и аргумент (ϕ) числа.
Методы класса: возведение числа в степень, вывод комплексного числа в алгебраической и тригонометрической формах. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление
и умножение комплексных чисел.
9. Создать класс вектор на плоскости, поля класса – координаты
вектора. Методы класса: вычисление длины вектора, вывод характеристик вектора. В классе предусмотреть методы перегрузки операций: сложение, скалярное и векторное произведения векторов.
10. Создать класс обыкновенная дробь, поля класса – числитель и
знаменатель. Методы класса: определение обратной дроби, вывод
дроби. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление и умножение дробей.
11. Создать класс квадратная матрица, поля класса – размерность и элементы матрицы. Методы класса: проверка, является ли
матрица верхнетреугольной или нижнетреугольной, вывод матрицы.
В классе предусмотреть методы перегрузки операций: сложение, вычитание, умножение матриц, умножение матрицы на число.
12. Создать класс треугольник, члены класса – длины 3-х сторон.
Предусмотреть в классе методы проверки существования треугольни-

469

ка, вычисления и вывода сведений о фигуре – длины сторон, углы, периметр, площадь. Создать производный класс – равнобедренный треугольник, предусмотреть в классе проверку, является ли треугольник
равнобедренным.
13. Создать класс комплексное число в показательной форме
i
a= e , поля класса – модуль (ρ) и аргумент (ϕ) числа. Методы
класса: вывод комплексного числа в алгебраической, тригонометрической и показательной формах. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление и умножение
комплексных чисел.
14. Создать класс прямая, поля класса – коэффициенты уравнения
y= ax + b. Методы класса: вывод уравнения прямой, определение
точек пересечения с осями. В классе предусмотреть методы перегрузки операций: проверка перпендикулярности двух прямых, определение угла между двумя прямыми.
15. Создать класс квадратная матрица, поля класса – размерность и элементы матрицы. Методы класса: проверки, является ли
матрица диагональной или нулевой, вывод матрицы. В классе предусмотреть методы перегрузки операций: сложение, вычитание, умножение матриц, добавление к матрице числа.
16. Создать класс треугольник, члены класса – координаты 3-х точек. Предусмотреть в классе методы проверки существования треугольника, вычисления и вывода сведений о фигуре – длины сторон,
углы, периметр, площадь. Создать производный класс – прямоугольный треугольник, предусмотреть в классе проверку, является ли треугольник прямоугольным.
17. Создать класс комплексное число в тригонометрической форме
a =cos i sin  , поля класса – модуль (ρ) и аргумент (ϕ) числа.
Методы класса: извлечение корня из числа, вывод комплексного числа
в алгебраической и тригонометрической формах. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление и
умножение комплексных чисел.
18. Создать класс обыкновенная дробь, поля класса – числитель и
знаменатель. Методы класса: возведение дроби в степень, вывод дроби. В классе предусмотреть методы перегрузки операций: сложение,
вычитание, деление и умножение дробей.
19. Создать класс треугольник, члены класса – длины 3-х сторон.

470

Предусмотреть в классе методы проверки существования треугольника, вычисления и вывода сведений о фигуре – длины сторон, углы, периметр, площадь. Создать производный класс – равносторонний треугольник, предусмотреть в классе перегрузку метода проверки существования равностороннего треугольника.
20. Создать класс комплексное число в алгебраической форме
z=x+ y ⋅i, поля класса – действительная (x) и мнимая (y) части
числа. Методы класса: вычисление модуля и аргумента комплексного
числа, вывод комплексного числа. В классе предусмотреть методы
перегрузки операций: сложение, вычитание комплексных чисел, проверки сопряженности двух комплексных чисел.
21. Создать класс окружность, член класса – радиус R. Предусмотреть в классе методы вычисления и вывода сведений о фигуре –
площадь, длина окружности. Создать производный класс – круглый
прямой цилиндр с высотой h, добавить в класс метод определения
объема фигуры, перегрузить методы расчета площади и вывода сведений о фигуре.
22. Создать класс вектор на плоскости, поля класса – координаты
вектора. Методы класса: вычисление длины вектора, вывод характеристик вектора. В классе предусмотреть методы перегрузки операций: сложение, скалярное и векторное произведения векторов, вычисление угла между векторами.
23. Создать класс квадратная матрица, поля класса – размерность и элементы матрицы. Методы класса: проверка, является ли
матрица симметричной ( A= AT ), вывод матрицы. В классе предусмотреть методы перегрузки операций: сложение, вычитание, умножение матриц, добавление к матрице числа.
24. Создать класс обыкновенная дробь, поля класса – числитель и
знаменатель. Метод класса: вывод дроби. В классе предусмотреть методы перегрузки операций: сложение, вычитание, деление и умножение дробей, сравнение дробей.
25. Создать класс квадрат, члены класса - длина стороны. Предусмотреть в классе методы вычисления и вывода сведений о фигуре –
диагональ, периметр, площадь. Создать производный класс – правильная квадратная призма с высотой H, добавить в класс метод
определения объема фигуры, перегрузить методы расчета площади и
вывода сведений о фигуре.

471

10 Графика во Free Pascal
Данная глава посвящена графическим средствам Free Pascal.
Рассмотрены основные процедуры и функции работы с графикой.
Приведен пример построения графика математической зависимости.
10.1 Средства рисования в Lazarus
При разработке оконного приложения Lazarus есть форма, на которой можно рисовать. В распоряжении программиста находится полотно (холст) — свойство Canvas, карандаш — свойство Pen, и
кисть — свойство Brush.
Свойством Canvas обладают следующие компоненты:
• форма (класс Tform);
• таблица (класс TSringGrid);
• растровая картинка (класс Timage);
• принтер (класс TPrinter).
При рисовании компонента, обладающего свойством Canvas,
сам компонент рассматривается как прямоугольная сетка, состоящая
из отдельных точек, называемых пикселями.
Положение пикселя характеризуется его вертикальной (X) и горизонтальной (Y) координатами. Левый верхний пиксель имеет координаты (0,0). Вертикальная координата возрастает сверху вниз, горизонтальная — слева направо. Общее количество пикселей по вертикали определяется свойством Height, а по горизонтали — свойством
Weight. Каждый пиксель может иметь свой цвет. Для доступа к любой точке полотна используется свойство
Pixels[X,Y]:TColor.
Это свойство определяет цвет пикселя
с координатами
X(integer), Y(integer).
Изменить цвета любого пикселя полотна можно с помощью следующего оператора присваивания
Компонент.Canvas. Pixels[X,Y]:=Color;
где Color — переменная или константа типа Tcolor. Определены следующие константы цветов (тал. 10.1):

472

Таблица 10.1. Значение свойств Color
Константа
Цвет
Константа
Цвет
clBlack
clSilve
Черный
Серебристый
clMaroon
clRed
Каштановый
Красный
clGreen
clLime
Зеленый
Салатовый
clOlive
clBlue
Оливковый
Синий
clNavy
clFuchsia
Темно-синий
Ярко-розовый
clPurple
clAqua
Розовый
Бирюзовый
clTeal
clWhite
Лазурный
Белый
clGray
Серый
Цвет любого пикселя можно получить с помощью следующего
оператора присваивания:
Color:=Компонент.Canvas. Pixels[X,Y];
где Color — переменная типа Tcolor.
Класс цвета точки Tcolor определяется как длинное целое
longint. Переменные этого типа занимают в памяти четыре байта.
Четыре байта переменных этого типа содержат информацию о долях
синего (B), зеленого (G) и красного(R) цветов и устроены следующим
образом: $00BBGGRR.
Для рисования используются методы класса TСanvas, позволяющие изобразить фигуру (линию, прямоугольник и т.д.) или вывести
текст в графическом режиме, и три класса, определяющие инструменты вывода фигур и текстов:
• TFont (шрифты);
• TPen (карандаш, перо);
• TBrush (кисть).
Класс TFONT
Можно выделить следующие свойства объекта Canvas.TFont:
• Name (тип string) — имя используемого шрифта.
• Size (тип integer) — размер шрифта в пунктах (points).
Пункт — это единица измерения шрифта, равная 0,353 мм, или 1/72
дюйма.
• Style — стиль начертания символов, который может быть
обычным, полужирным (fsBold), курсивным (fsItalic), под-

473

черкнутым (fsUnderline) и перечеркнутым (fsStrikeOut). В
программе можно комбинировать необходимые стили, например,
чтобы установить стиль «полужирный курсив», необходимо написать следующий оператор:
Объект.Canvas. Font. Style:=[fsItalic,fsBold]
• Color (тип Tcolor) — цвет символов.
• Charset (тип 0..255) — набор символов шрифта. Каждый вид
шрифта, определяемый его именем, поддерживает один или более
наборов символов. В табл. 10.2 приведены некоторые значения
Charset.
Таблица 10.2. Значения свойства Charset
Константа
Значение
Описание
ANSI_CHARSET
0
Символы ANSI
DEFAULT_CHARSET
1
Задается
по
умолчанию.
Шрифт выбирается только по
его имени Name и размеру
Size. Если описанный шрифт
недоступен в системе, будет
заменен другим
SYMBOL_CHARSET
2
Стандартный набор символов
MAC_CHARSET
77
Символы Macintosh
GREEK_CHARSET
161
Греческие символы
RUSSIAN_CHARSET
204
Символы кириллицы
EASTEUROPE_CHARSET 238
Включает
диалектические
знаки (знаки, добавляемые к
буквам и характеризующие их
произношение) для восточноевропейских языков
Класс TPEN
Карандаш (перо) используется как инструмент для рисования точек, линий, контуров геометрических фигур. Основные свойства
объекта Canvas.TPen:
• Color (тип Tcolor) – определяет цвет линии;
• Width (тип Integer) – задает толщину линии в пикселях;

474

Style – дает возможность выбрать вид линии. Это свойство
может принимать значение, указанное в таблице 10.3.
Таблица 10.3. Виды линий
Значение
Описание
psSolid
Сплошная линия
psDash
Штриховая линия
psDot
Пунктирная линия
psDashDot
Штрих-пунктирная линия
psDashDodDot
Линия, чередующая шрих и два пунктира
psClear
Нет линии
• Mode – определяет, каким образом взаимодействуют цвета пера
и полотна. Выбор значения этого свойства позволяет получать различные эффекты, возможные значения Mode приведены в табл.
10.4. По умолчанию вся линия вычерчивается цветом, определяемым значением Pen.Color, но можно определять инверсный цвет
линии по отношению к цвету фона. В этом случае независимо от
цвета фона, даже если цвет линии и фона одинаков, линия будет
видна.
Таблица 10.4. Возможные значения свойства Mode
Режим
Операция
Цвет пикселя
pmBlack
Black
Всегда черный
pmWhite
White
Всегда белый
pmNop
Неизменный
pmNot
Not Screen
Инверсный цвет по
отношению к цвету
фона
pmCopy
Pen
Цвет, указанный в
свойствах
Color
пера Pen (это значение принято по
умолчанию)
pmNotCopy
Not Pen
Инверсия
цвета
пера


475

Режим
Операция
pmMergePenNot Pen or Not Pen

pmMaskPenNot Pen

pmMergeNotPen Not

PmMaskNotPen Not

pmMerge

Pen

pmNotMerge

Not

pmMask

Pen

pmNotMask

Not

pmXor

Pen

pmNotXor

Not

Цвет пикселя
Дизъюнкция цвета
пера и инверсного
цвета фона
and Not Screen
Конъюнкция цвета
пера и инверсного
цвета фона
Pen or Screen
Дизъюнкция цвета
фона и инверсного
цвета пера
Pen and Screen
Конъюнкция цвета
фона и инверсного
цвета пера
or Screen
Дизъюнкция цвета
пера и цвета фона
(Pen or Screen) Инверсия режима
pmMerge
and Screen
Конъюнкция цвета
пера и цвета фона
(Pen and Screen) Инверсия режима
pmMask
xor Screen
Операция xor над
цветом пера и цветом фона
(Pen xor Screen) Инверсия режима
pmXor

Класс TBRUSH
Кисть (Canvas.Brush) используется методами, обеспечивающими вычерчивание замкнутых фигур для заливки. Кисть обладает
двумя основными свойствами:
• Color (тип Tcolor) – цвет закрашивания замкнутой области;
• Style – стиль заполнения области.
Класс TCANVAS
Это класс является основным инструментом для рисования гра-

476

фики. Рассмотрим наиболее часто используемые методы этого класса.
Procedure MoveTo(X, Y : Integer);
Метод MoveTo изменяет текущую позицию пера на позицию, заданную точкой (X, Y). Текущая позиция хранится в переменной
PenPos типа Tpoint. Определение типа TPoint следующее:
type TPoint =record
X: Longint;
Y: Longint;
end;
Текущую позицию пера можно считывать с помощью свойства
PenPos следующим образом:
X:=PenPos.X;
Y:=PenPos.Y;
Procedure LineTo(X, Y :Integer);
Метод LineTo соединяет прямой линией текущую позицию пера
и точку с координатами (X, Y). При этом текущая позиция пера
перемещается в точку с координатами (X, Y).
Рассмотрим работу процедуры на примере. Расположим на форме
кнопку
и
рассмотрим
процедуру
обработки
события
TForm1.Button1Click, которая рисует прямые линии:
Procedure TfForm1.Button1Click(Sender: TObject)
begin
Form1.Canvas.LineTo(30,50);
end;
В результате щелчка по кнопке на форме возникнет прямая линия, соединяющая точку с координатами (0,0) и точку с координатами
(30,50). Теперь перепишем процедуру обработки события следующим
образом:
Procedure TForm1.Button1Click(Sender: TObject)
begin
Form1.Canvas.LineTo(Canvas.PenPos.x+30,
Canvas.PenPos.y+50);
end;
При первом щелчке по кнопке на экране прорисуется аналогичная линия. Но при повторном щелчке первая процедура продолжает
рисовать линию, соединяющую точки (0,0) и (30,50). Вторая процедура рисует линию, которая соединяет текущую точку с точкой, полу-

477

чившейся из текущей добавлением к координате X числа 30, а к координате Y – числа 50. Т.е. при повторном щелчке по кнопке процедура
соединяет прямой линией точки (30,50) и (60,100). При третьем щелчке по кнопке будут соединяться прямой линией точки (60,100) и
(90,150) и т.д.
Procedure PolyLine(const Points array of TPoint);
Метод PolyLine рисует ломаную линию, координаты вершин
которой определяются массивом Points.
Рассмотрим работу процедуры на примере. Расположим на форме
кнопки Рисовать и Выход и запишем следующие операторы процедур обработки события:
procedure TForm1.Button1Click(Sender: TObject);
var temp :array [1..25] of TPoint;
i : byte;
j: integer;
begin
j:=1;
for i:=1 to 25 do
begin
//вычисление координат вершин ломаной линии
temp[i].x:=25+(i-1)*10;
temp[i].y:=150-j*(i-1)*5;
j:=-j;
end;
Form1.Canvas.Polyline (temp);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Form1.Close;
end;
После запуска программы и щелчка по кнопке «Рисовать» окно
формы будет выглядеть, как на рисунке 10.1.
Procedure Ellipse (X1, Y1, X2, Y2 :Integer);
Метод Ellipse вычерчивает на холсте эллипс или окружность.
X1, Y1, X2, Y2 — это координаты прямоугольника, внутри которого вычерчивается эллипс. Если прямоугольник является квадратом,
то вычерчивается окружность.

478

Рисунок 10.1: Пример использования процедуры
PolyLine
Метод
Procedure Arc (X1,Y1,X2,Y2,X3,Y3,X4,Y4:Integer);
вычерчивает дугу эллипса. X1, Y1, X2, Y2 — это координаты,
определяющие эллипс, частью которого является дуга. X3, Y3 —
координаты, определяющие начальную точку дуги, X4, Y4 — координаты, определяющие конечную точку дуги. Дуга рисуется против
часовой стрелки.
Метод
Procedure Rectangle (X1, Y1, X2, Y2 :Integer);
рисует прямоугольник. X1, Y1, X2, Y2 — координаты верхнего
левого и нижнего правого углов прямоугольника.
Метод
Procedure RoundRect (X1,Y1,X2,Y2,X3,Y3:Integer);
вычерчивает прямоугольник со скругленными углами. X1, Y1, X2,
Y2 — координаты верхнего левого и нижнего правого углов прямоугольника, а X3, Y3 — размер эллипса, одна четверть которого используется для вычерчивания скругленного угла.

479

Метод
Procedure PolyGon(const Points array of TPoint);
рисует замкнутую фигуру (многоугольник) по множеству угловых точек, заданному массивом Points. При этом первая точка соединяется прямой линией с последней. Этим метод PolyGon отличается от
метода Poliline, который не замыкает конечные точки. Рисование
осуществляется текущим пером Pen, а внутренняя область фигуры
закрашивается текущей кистью Brush.
Метод
Procedure Pie (X1,Y1,X2,Y2,X3,Y3,X4,Y4 :Integer);
рисует замкнутую фигуру — сектор окружности или эллипса с помощью текущих параметров пера Pen, внутренняя область закрашивается текущей кистью Brush. Точки (X1, Y1) и (X2, Y2) задают
прямоугольник, описывающий эллипс. Начальная точка дуги определяется пересечением эллипса с прямой, проходящей через его его
центр и точку (X3, Y3). Конечная точка дуги определяется пересечением эллипса с прямой, проходящей через его центр и точку (X4,
Y4). Дуга рисуется против часовой стрелки от начальной до конечной точки. Рисуются прямые, ограничивающие сегмент и проходящие
через центр эллипса и точки (X3, Y3) и (X4, Y4).
Создадим форму, установим ей размеры Heigth — 500, Width
— 500. Внизу разместим кнопку, зададим ей свойство Caption —
«Рисовать». При запуске программы и щелчке по этой кнопке на
форме прорисуются различные фигуры (см. рис. 10.2). Ниже приведен листинг программы, демонстрирующий работу перечисленных
методов. Результат работы программы приведен на рис. 10.2.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: Tbutton;

480

Рисунок 10.2: Пример использования
методов рисования фигур
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var t: array [1..5] of TPoint;
begin
Form1.Canvas.LineTo(500,500);//Рисование линии
//Изменение цвета и толщины линии.
Form1.Canvas.Pen.Color:= clMaroon;
Form1.Canvas.Pen.Width:= 5;
//Рисование прямоугольника.
Form1.Canvas.Rectangle(50,50,200,200);
Form1.Canvas.Pen.Color:= clolive;

481

//Рисование эллипса.
Form1.Canvas.Ellipse(50,50,100,200);
//Рисование прямоугольника с скругленными углами.
Form1.Canvas.RoundRect(250,250,400,400,30,30);
//Рисование сектора окружности.
Form1.Canvas.Pie(300,300,400,400,350,350,500,500);
//Массив координат вершин пятиугольника.
t[1].x:=250; t[1].y:=10;
t[2].x:=350; t[2].y:=15;
t[3].x:=400; t[3].y:=50;
t[4].x:=300; t[4].y:=150;
t[5].x:=250; t[5].y:=100;
Form1.Canvas.Polygon (t) ;
Form1.Canvas.TextOut(10,10,'это вывели текст');
end;
initialization
{$I unit1.lrs}
end.
Функция
procedure TextOut(X,Y:Integer;const Text:String);
пишет строку текста Text, начиная с позиции с координатами (X,
Y). Текущая позиция PenPos пера Pen перемещается на конец выведенного текста. Надпись выводится в соответствии с текущими установками шрифта Font, фон надписи определяется установками текущей кисти. Для выравнивания позиции текста на канве можно использовать методы, позволяющие определить высоту и длину текста в
пикселях — TextExtent, TextHeight и TextWidth. Рассмотрим
эти функции.
Функция
function TextExtent (const Text : String): Tsize;
возвращает структуру типа Tsize, содержащую длину и высоту в
пикселях текста Text, который предполагается написать на канве текущим шрифтом.
type Tsize = record
cx:Longint; cy:Longint;
end;
Функция

482

function TextHeight(const Text:String):Integer;
возвращает высоту в пикселях текста Text, который предполагается
написать на канве текущим шрифтом.
Функция
function TextWidth(const Text:String):Integer;
возвращает длину в пикселях текста Text, который предполагается
написать на канве текущим шрифтом. Это позволяет перед выводом
текста на канву определить размер надписи и расположить ее и другие элементы изображения наилучшим образом.
Если цвет кисти в момент вывода текста отличается от того, которым закрашена канва, то текст будет выведен в цветной прямоугольной рамке, но ее размеры будут точно равны размерам надписи.
Мы рассмотрели основные функции рисования. Прежде чем
перейти непосредственно к рисованию, обратите внимание на то, что
если вы свернете окно с графикой, а затем его восстановите, то картинка на форме исчезнет. Изменение размеров окна также может испортить графическое изображение в окне. Для решения этой проблемы существуют процедуры обработки событий Объект.FormPaint
и Объект.FormResize.
Процедура Объект.FormPaint выполняется после появления
формы на экране.
Процедура Объект.FormResize выполняется после изменения
размера формы.
Следовательно, для того чтобы не пропадала картинка, все операторы рисования нужно помещать внутрь Объект.FormPaint и дублировать в процедуре Объект.FormResize.
10.2 Построение графиков
Алгоритм построения графика непрерывной функции y=f(x) на
отрезке [a;b] состоит в следующем: необходимо построить точки (xi,
f(xi)) в декартовой системе координат и соединить их прямым линиями. Координаты точек определяются по следующим формулам:
hx=(b-a)/N,
где
N — количество отрезков на отрезке [a;b].
xi=a+(i-1)hx;
yi=f(xi), где i =0,N
Чем больше точек будет изображено, тем более плавным будет
построенный график.

483

При переносе этого алгоритма на форму или другой компонент
Lazarus учитывает размеры и особенности компонента (ось ОX
направлена слева направо, ее координаты лежат в пределах от 0 до
Width; ось OY направлена вниз, ее координаты находятся в пределах
от 0 до Height). Значения координат X и Y должны быть целыми.
Необходимо пересчитать все точки из «бумажной» системы координат (X изменяется в пределах от а до b, Y изменяется от минимального до максимального значения функции) в «компонентную79» (в
этой системе координат ось абсцисс обозначим буквой U, 0 ≤ U ≤
Wigth, а ось ординат — буквой V, 0 ≤ V ≤ Height).
Для преобразования координаты X в координату U построим линейную функцию cX+d, которая переведет точки из интервала (a;b) в
точки интервала (X0,Width-Xk)80. Поскольку точка a «бумажной»
системы координат перейдет в точку X0 «экранной», а точка b — в
точку Width-Xk, то система линейных уравнений для нахождения
коэффициентов c и d имеет вид:
с⋅ad = X0
c⋅bd =Width− Xk
Решив ее, найдем коэффициенты c, d:
d =X0−c⋅a
Width− Xk − X0
c=
b−a
Для преобразования координаты Y в координату V построим линейную функцию V=gY+h. Точка min «бумажной» системы координат перейдет в точку Height-YK «компонентную», а точка max – в
точку Y0. Для нахождения коэффициентов g и h решим систему линейных алгебраических уравнений:
g⋅minh=Heignt−Yk
g⋅maxh=Y0
Ее решение позволит найти нам коэффициенты g и h
h=Y0−g⋅max
Heigth−Yk−Y0
g=
min−max
Перед описанием алгоритма построения графика давайте

{

{
{

{

79 Система координат, связанная с конкретным компонентом класса Tform, Timage, Tprinter и т.д.
80 X0, XK, Y0, YK — Отступы от левой, правой, нижней и верхней границы компонента.

484

уточним формулы для расчета коэффициентов c, d, g и h. Дело в том,
что Width – это ширина компонента с учетом рамок слева и справа, а
Height – полная высота компонента с учетом рамки, а если в качестве компонента будет использоваться форма, то необходимо учесть
заголовок окна. Однако, для изображения графика нам нужны вертикальные и горизонтальные размеры компонента без учета рамок и заголовка. Эти размеры хранятся в свойствах ClientWidth (ширина
клиентской области компонента без учета ширины рамки) и
ClientHeight (высота клиентской области компонента без учета
ширины рамки и ширины заголовка) компонента. Поэтому для расчета коэффициентов c, d, g и h логичнее использовать следующие формулы:
d =X0−c⋅a
ClientWidth− Xk − X0
(10.1)
c=
b−a
h=Y0−g⋅max
ClientHeigth−Yk −Y0
(10.2)
c=
min−max
Алгоритм построения графика на экране дисплея можно разделить на следующие этапы:
1. Определить число отрезков N, шаг изменения переменной X.
2. Сформировать массивы X, Y, вычислить максимальное
(max) и минимальное (min) значения Y.
3. Найти коэффициенты c, d, g и h по формулам (10.1), (10.2).
4. Создать массивы Ui=cXi+d, Vi=gYi+h.
5. Последовательно соединить соседние точки прямыми линиями с помощью функции LineTo.
6. Изобразить систему координат, линий сетки и подписи.
При построении графиков нескольких непрерывных функций
вместо массивов Y и V рационально использовать матрицы размером
k×n, где k – количество функций. Элементы каждой строки матриц
являются координатами соответствующего графика в «бумажной» (Y)
и «компонентной» (V) системе координат.
Блок-схема алгоритма изображения графика показана на рис.10.3.
Блок-схема построения графиков k непрерывных функций представлена на рис. 10.4.

{
{

485

Рисунок 10.3: Блок-схема алгоритма построения графика функции

486

Рассмотрим поэтапно каждую блок-схему.
Для рис. 10.3 первый этап алгоритма представлен в блоках 2 и 3.
Второй этап реализуется в блоках 4 – 13. Коэффициенты третьего этапа рассчитываются в блоке 14. В блоках 15 – 16 формируются массивы значений U и V «компонентной системы координат (этап 4). Блоки
17 – 19 – это вывод графиков на экран. И блок 20 предназначен для
шестого этапа.
Для второй схемы рис. 10.4 реализация второго этапа представлена в блоках 4 – 15. В блоке 16 рассчитываются коэффициенты c, d, g и
h. В блоках 17 – 20 формируются массивы четвертого этапа. Блоки 21
– 24 предназначены для вывода графиков, а блок 25 – для построения
осей.
ЗАДАЧА 10.1. Построить график функции f(x) на интервале
[a, b]. Функция задана следующим образом:
x
sin , если x0
2
f  x=
1x
, если x0
3
Создадим новый проект, изменим высоту и ширину формы до
размеров, достаточных для отображения на ней графика. Например,
можно установить следующие свойства: Width – 800, Height – 700.
Разместим на форме кнопку и компонент класса TImage. Объект
TImage1 – это растровая картинка, которая будет использоваться для
отображения графика после щелчка по кнопке Button1. Размеры растровой картинки сделаем чуть меньше размеров формы.
Установим в качестве свойства Caption формы сроку «График
функции». Чтобы избавиться от проблемы перерисовки будущего графика при изменении размера формы, запретим изменение формы и
уберем кнопки минимизации и максимизации окна. Свойство формы
BorderStyle определяет внешний види поведение рамки вокруг
окна формы. Для запрета изменения формы установим значение свойства BorderStyle в bsSingle, это значение определяет стандартную рамку вокруг формы и запрещает изменение размера формы.
Чтобы убрать кнопки минимизации и максимизации формы, установим
ее
свойства
BolderIcons.BiMaximize
и
BolderIcons.BiMinimize в False.

{

487

Рисунок 10.4: Блок-схема алгоритма построения графиков нескольких функций

488

Для кнопки установим свойство Caption – фразу «График».
После установки всех описанных свойств окно формы должно
стать подобным представленному на рис.10.5.

Рисунок 10.5: Окно формы после установки свойств
Ввод интервала a и b сделаем с помощью запроса в момент создания формы (в методе инициализации формы FormCreate). Ниже
приведен листинг модуля проекта рисования графика с комментариями:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
LResources,
Forms,
Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;
//Функция, которая аналитически определяет график.
function f(x:real):real;
//Функция, которая изображает график.
procedure Graphika(a, b: real);
type
{ TForm1 }
TForm1 = class(TForm)

489

Button1: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var

Form1: TForm1;
//Объявление переменных:
//x0, xk, y0, yk - отступы от границ
//компонента слева, справа, сверху и снизу;
//x, y - массивы, определяющие координаты
//точек графика в "бумажной"
//системе координат;
//u, v - массивы, определяющие координаты
//точек графика в "компонентной"
//системе координат;
//N - количество точек.
x0, y0, xk, yk, a, b :real;
x, y : array [0..1000] of real;
u, v : array [0..1000] of integer;
N : integer;
implementation
// функция, которая будет изображена
//на компоненте Image1
function f (x : real) : real;
begin
if xmax then max:=y[i];
if y[i]yk) and
(trunc(h)x0) and
(trunc(d)x0) and
(trunc(d)yk) and (trunc(h)<
Form1.Image1.ClientHeight-y0) then
Form1.Image1.Canvas.TextOut(tempx+10,
runc(h)-5,'0');
tempx:=trunc(x0+i*(Form1.Image1.ClientWidth x0-xk)/2);
Form1.Image1.Canvas.TextOut(tempx,10,
'График функции');
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var s : string; kod : integer;

494

begin
N:=100;
x0:=40;
xk:=40;
y0:=40;
yk:=40;
repeat
s:=InputBox('График непрерывной функции',
'Введите левую границу','-10');
Val(s,a,kod);
until kod=0;
repeat
s:=InputBox('График непрерывной функции',
'Введите правую границу','10');
Val(s,b,kod);
until kod=0;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Graphika(a, b);
end;
initialization
{$I unit1.lrs}
end.
При запуске проекта появится запрос ввода левой (рис. 10.6) и
правой (рис. 10.7) границ интервала. После этого появится окно формы с кнопкой График. После щелчка по кнопке на форме прорисуется график функции (рис. 10.8).

Рисунок 10.6: Окно ввода
левой границы

Рисунок 10.7: Окно ввода
правой границы интервала

495

Рисунок 10.8: График функции
10.3 Задачи для самостоятельного решения
Построить график функции f(x) на интервале [a;b]. Функции заданы в табл. 10.5.
Таблица 10.5. Варианты заданий
№ ва№ ваf(x)
f(x)
рианта
рианта

{

1

2

{

x 32
sin
, если x5
3
5
 1 x , если x5
3

tan x ,если x−1
3 ex1 , если x−1

9

{

x 2− x2
, если x≥1
x3

5

10

{

x

e
 x 2 , если x1
2

x3,6
, если x0
x3
3 1 x , если x≥0
sin

496

№ варианта

{

3

{

4

1x
 , если x2
3
3 1 x3 , если x≤2
log 

2 cos x23 , если x2
3,5
sin  x22 , если x≤2

{

5

{

6

№ варианта

f(x)

x−6
, если x5
x−3
 1 x4 , если x≤5
cos

3

f(x)

{

11

x 33x 2
, если x−2
3
3 log 1,5 x2  , если x−2

12

{

13

{
{

2

x 3x , если x−1
3 ln 10,5 x , если x−1

7

{

8

{ ∣ ∣

x 22
cos
, если x3
x
 12x 2 , если x≤3

x 3⋅sin  x  , если x−3,5
5 x
, если x−3,5
2

14

{

15

{

16

x
4

e , если x −2,5
5 x 2 , если x≤−2,5

x2
, если x≥4
x3
3 e x x 2 , если x4
cos

2

x − x2 , если x≥−1
5 e x7 , если x−1

1x 3
log 
 , если x2,5
2
3 12x2− x 3 , если x≤2,5
3

2

x 3 x2 , если x3
5 sin 10,5x2 , если x3

Построить графики функций f1(x), f2(x), f2(x) в одной системе
координат на интервале [a;b]. Функции заданы в табл. 10.6.
Таблица 10.6. Варианты заданий
№ варианта
f1(x)
x−6
2
x 3

f2(x)

f3(x)

x 3⋅sin  x

 5x3 ⋅sin  x 2

17

cos

18

12x 2− x 3

e 7

19

3 1 x 3

142x 2−3x 3

cos sin  x

 72x 4

3 35x 2−x 32

20

sin



x
x
e
3



x
2

sin


x
3

497

№ варианта

f1(x)

21

5 7− x 3

22

3 ln 12x 2

23

cos

24

3 1 x 2− x32

25

x
sin 2⋅x⋅
2

 x2
 

f2(x)
cos
e

 
x

2

x
5

3

cos sin  x 2 

cos

4 1 x62x 2
2⋅sin

f3(x)

 
x

2

 1 x x 3−42

 
x


3x 4−5x 27x−2
5x 2−3x3
x
7

e 4

498

Вместо заключения
Перевернута последняя страница книги. Что теперь? Авторы надеются, что знакомство с языком Free Pascal будет только первым этапом в изучении программирования. Желание читателя что-то исправить в книге — переписать приведенные в книге программы, предложить более простые и быстро работающие алгоритмы, написать свои
программы и модули — будет лучшей благодарностью авторам. Если
у вас, читатели, появилось подобное желание, то мы выполнили свою
задачу — научили вас основам программирования.
Следующим этапом в освоении программирования будет разработка ваших алгоритмов и написание реально работающих программ
для различных операционных систем.

499

Алфавитный указатель
алгоритм....................................................................................................96
блок-схема.................................................................................................96
ввод информации......................................................................................61
вывод информации...................................................................................62
выполняемый файл...................................................................................64
выражение.................................................................................................76
главное меню......................................................................................28, 30
динамическая память...............................................................................86
запись.........................................................................................................74
значение.....................................................................................................68
идентификатор..........................................................................................68
инспектор объектов............................................................................30, 43
ключевые слова.........................................................................................67
комментарий.......................................................................................31, 67
компиляция..........................................................................................57, 64
компонент..................................................................................................43
консольное приложение...........................................................................59
константа...................................................................................................68
линейный процесс....................................................................................97
массив................................................................................................72, 213
алгоритм ввода-вывода.......................................................................217
алгоритм вставки элемента................................................................241
алгоритм нахождения произведения элементов..............................230
алгоритм нахождения суммы.............................................................230
алгоритм поиска максимального элемента и его номера................231
алгоритм сортировки................................................................................
методом выбора...............................................................................235
методом пузырька............................................................................232
алгоритм удаления элемента..............................................................237
динамический......................................................................................249
множество ................................................................................................75
настройки среды.......................................................................................31
окно ввода...............................................................................................147
окно редактора..........................................................................................44
окно формы.........................................................................................28, 30
оператор.........................................................................................................
варианта...............................................................................................117

500

передачи управления..........................................................................132
присваивания.........................................................................................97
составной...............................................................................................98
условный................................................................................................98
цикла с предусловием........................................................................126
цикла с известным числом повторений............................................129
цикла с постусловием ........................................................................127
операции........................................................................................................
арифметические....................................................................................78
логические.............................................................................................80
отношения..............................................................................................80
получения адреса..................................................................................81
разадресации.........................................................................................81
панель инструментов..........................................................................28, 32
панель компонентов...........................................................................34, 43
переменная................................................................................................68
подпрограмма..........................................................................................164
программный код......................................................................................65
программный модуль...............................................................................64
проект..................................................................................................30, 64
процедура................................................................................................166
работа с файлами......................................................................................30
разветвляющийся процесс.......................................................................97
редактор исходного кода..........................................................................30
сообщение...............................................................................................121
стандартные функции..............................................................................81
строка.........................................................................................................73
тело цикла...............................................................................................125
тип данных................................................................................................68
вещественный........................................................................................70
дата, время.............................................................................................70
интервальный........................................................................................72
логический.............................................................................................71
новый......................................................................................................71
перечислимый.......................................................................................71
символьный...........................................................................................69
структурированный..............................................................................72
целочисленный......................................................................................69

501

трансляция.................................................................................................12
указатель............................................................................................76, 246
файл...........................................................................................................75
форматированный вывод.........................................................................63
функция...................................................................................................171
рекурсивная.........................................................................................198
цикл..........................................................................................................125
итерация...............................................................................................125
параметр...............................................................................................125
шаг........................................................................................................125
циклический процесс...............................................................................97
Free Pascal..................................................................................................11

502

Литература
1. Алексеев Е.Р., Чеснокова О.В. Турбо Паскаль 7.0. - М.:НТ
Пресс, 2006. - 320 с.:ил. - (Полная версия).
2. Алексеев Е.Р. Учимся программировать на Microsoft Visual
C++ и Turbo C++ Explorer (под общей редакцией Чесноковой
О.В.)/Алексеев Е.Р. - М.:НТ Пресс, 2007. - 352 с.:ил. - (Самоучитель).
3. Фаронов В.В. Delphi. Программирование на языке высокого
уровня: Учебник для вузов. - Спб.:Питер, 2005.-640 с.:ил.
4. Чеснокова О.В. Delphi 2007. Алгоритмы и программы. Учимся программировать на Delphi 2007/Чеснокова О.В. Под общ. ред.
Алексеева Е.Р.- М.:НТ Пресс, 2008. - 368 с.:ил.
5. Бронштейн И.Н., Семендяев К.А. Справочник по математике
для инженеров и учащихся вузов.- М.:Наука, 1981. - 720 с.
6. GNU Pascal — Википедия. URL: .http://ru.wikipedia.
org/wiki/GNU_Pascal (дата обращения 03.08.2009).
7. Free Pascal - Advanced open source Pascal compiler for Pascal
and Object Pascal - Home Page. URL: http://www.freepascal.org (дата
обращения 03.08.2009).
8. GNU Pascal. URL: http://www.gnu-pascal.de/gpc/h-index.html
(дата обращения 03.08.2009).
9. Main
Page/ru

Free
Pascal
wiki.
URL:
http://wiki.freepascal.org/Main_Page/ru (дата обращения 03.11.2009).
10. Free Pascal.ru - Информационный портал для разработчиков
на Free Pascal & Lazarus & MSE. URL http://www.freepascal.ru (дата
обращения: 03.11.2009).
11. Lazarus – News. URL: http://www.lazarus.freepascal.org (дата
обращения 03.11.2009).
12. Lazarus – Википедия. URL: http://ru.wikipedia.org/wiki/Lazarus
(дата обращения 03.11.2009).

ISBN 978-966-8248-26-9

А 47

Алексеев Е.Р., Чеснокова О.В., Кучер Т.В. Самоучитель по программированию на
Free Pascal и Lazarus. - Донецк.: ДонНТУ, Технопарк ДонНТУ УНИТЕХ, 2011. 503 с.

ISBN 978-966-8248-26-9

ООО «Технопарк ДонНТУ УНИТЕХ»

 Алексеев Е.Р., Чеснокова О.В., Кучер Т.В., 2011
Издательство: ООО «Технопарк ДонНТУ УНИТЕХ»
Свидетельство о внесении субъекта издательского дела в государственный реестр издателей,
изготовителей и распространителей издательской продукции: Дк №1017 от 21.08.2002.
83000, г. Донецк, ул. Артема, 58, к.1.311
Тел. : (062) 304 90 19

Технический редактор: Аноприенко А.Я.
Дизайн обложки: Сорокина Л.C.
Корректор: Молодых Э.В.
Подписано к печати 8.09.2011 г.
Формат 60х90 1/16
Усл.печ.л. 36.04
Печать лазерная.
Заказ №
Тираж 200 экз.

Отпечатано в типографии «Друк-Инфо».
Адрес: 83000, г. Донецк, ул. Артема, 58.
Тел.: (062) 335 64 55.