ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
Государственное образовательное учреждение высшего профессионального образования П...
150 downloads
521 Views
2MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
Государственное образовательное учреждение высшего профессионального образования ПЕНЗЕНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
Л. В. Гурьянов, Л. С. Гурьянова, С. В. Самуйлов
ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ. PASCAL И DELPHI Лабораторный практикум
ПЕНЗА 2006
ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
Государственное образовательное учреждение высшего профессионального образования
«Пензенский государственный университет»
Л. В. Гурьянов, Л. С. Гурьянова, С. В. Самуйлов
ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ. PASCAL И DELPHI Лабораторный практикум
Издательство Пензенского государственного университета Пенза 2006
УДК 681.3 Г95 Р е ц е н з е н т ы: Кафедра «Прикладная информатика» Российского государственного университета инновационных технологий и предпринимательства (Пензенский филиал) Кандидат технических наук, доцент заместитель директора по учебной работе Пензенского филиала Всероссийского заочного финансово-экономического института И. Ю. Семочкина
Г95
Гурьянов, Л. В. Введение в программирование. Pascal и Delphi: лабораторный практикум / Л. В. Гурьянов, Л. С. Гурьянова, С. В. Самуйлов. – Пенза: Изд-во Пенз. гос. ун-та, 2006. – 168 с. : ил. – Библиогр. : с. 161.
Рассматриваются базовые понятия программирования, необходимые для разработки сложных программ; принципы взаимодействия программ и структура программных модулей; работа в интегрированных средах программирования Turbo Pascal и Delphi. Приведены задания для выполнения лабораторных работ. Лабораторный практикум подготовлен на кафедре «Математическое обеспечение и применение ЭВМ» и рекомендуется для студентов специальности 23.01.05 по курсам «Алгоритмические языки и программирование» и «Структуры и алгоритмы обработки данных».
УДК 681.3
© Гурьянов Л. В., Гурьянова Л. С., Самуйлов С. В., 2006 © Издательство Пензенского государственного университета, 2006
2
СОДЕРЖАНИЕ Введение. Что мы понимаем под программированием.......................................................6 1. Обработка информации на компьютере............................................................................8 1.1. Модель обработки информации на компьютере............................................... 8 1.2. Основные объекты языка программирования................................................. 10 1.2.1. Синтаксические элементы языка программирования ........................... 10 1.2.2. Значения и типы ....................................................................................... 11 1.2.3. Константы и переменные ........................................................................ 12 1.2.4. Выражения................................................................................................ 13 1.2.5. Операторы................................................................................................. 15 1.3. Простая программа............................................................................................ 17 1.4. Работа в среде Turbo Pascal .............................................................................. 20 1.4.1. Создание, загрузка и сохранение программы ........................................ 20 1.4.2. Компиляция и выполнение программы.................................................. 21 1.5. Лабораторные задания ...................................................................................... 22 1.5.1. «Логические» задачи................................................................................ 22 1.5.2. Составление простых программ ............................................................. 24 2. Управляющие структуры ..................................................................................................27 2.1. Обзор управляющих структур.......................................................................... 27 2.2. Составной оператор .......................................................................................... 30 2.3. Операторы прерывания выполнения цикла .................................................... 30 2.4. Работа в среде Turbo Pascal .............................................................................. 32 2.4.1. Редактирование текста программы. Работа с блоками ......................... 32 2.4.2. Отладка программ .................................................................................... 34 2.5 Лабораторные задания ....................................................................................... 37 2.5.1. Реализовать схемы программ с помощью операторов языка Pascal .... 37 2.5.2. Выполнить трассировку и определить результаты программы ........... 41 2.5.3. Программирование с использованием управляющих структур ........... 47 3. Структуры данных..............................................................................................................50 3.1. Массивы ............................................................................................................. 50 3.1.1. Действия над массивами.......................................................................... 51 3.2. Строки ................................................................................................................ 52 3.2.1. Стандартные процедуры работы со строками ....................................... 53 3.2.2. Стандартные функции работы со строками........................................... 53 3.3. Записи................................................................................................................. 54
3
3.4 Лабораторные задания ....................................................................................... 56 3.4.1. Одномерные массивы .............................................................................. 56 3.4.2. Двумерные массивы................................................................................. 57 3.4.3. Строки ....................................................................................................... 59 3.4.4. Записи........................................................................................................ 60 4. Структура программы........................................................................................................64 4.1. Подпрограммы................................................................................................... 64 4.1.1. Глобальные данные.................................................................................. 66 4.1.2. Способы передачи параметров................................................................ 67 4.1.3. Функции .................................................................................................... 68 4.1.4. Процедуры ................................................................................................ 70 4.1.5. Передача массивов в качестве параметров ............................................ 70 4.1.6. Передача подпрограммы как параметра................................................. 74 4.1.7. Рекурсивные подпрограммы ................................................................... 75 4.2. Лабораторные задания. Подпрограммы .......................................................... 77 4.2.1. Оформление алгоритма обработки информации в виде подпрограммы .................................................................................................... 77 4.2.2. Разработка рекурсивных подпрограмм .................................................. 77 4.2.3. Разработка программы сложной структуры .......................................... 78 4.3. Модули ............................................................................................................... 79 4.4. Лабораторные задания. Модули....................................................................... 83 5. Хранение информации.......................................................................................................84 5.1. Файлы. Основные понятия и операции ........................................................... 84 5.2. Типизированные файлы .................................................................................... 87 5.3. Текстовые файлы............................................................................................... 88 5.4. Лабораторные задания. Процедуры работы с файлами ................................. 90 6. Динамические структуры данных. Указатели ................................................................91 6.1. Основные понятия и определения ................................................................... 91 6.2. Процедуры работы с динамическими структурами данных.......................... 93 6.2.1. Процедуры New и Dispose ....................................................................... 93 6.2.2. Процедуры GetMem и FreeMem.............................................................. 95 6.3. Применение динамических структур для организации списков ................... 96 6.4 Лабораторные задания. Указатели, список .................................................... 100 7. Введение в объектно-ориентированное программирование. Классы и объекты.....102 7.1. Основные понятия и определения ................................................................. 102
4
7.2. Объектно-ориентированная разработка модуля «Геометрические фигуры» .................................................................................... 103 7.3. Лабораторное задание ..................................................................................... 112 8. Объектно-ориентированное программирование на языке Object Pascal...................113 8.1. Классы и объекты ............................................................................................ 113 8.1.1. Структура класса.................................................................................... 113 8.1.2. Создание и уничтожение объектов....................................................... 114 8.1.3. Пример. Класс – динамический массив................................................ 115 8.1.4. Операции с объектами ........................................................................... 118 8.1.5. Свойства.................................................................................................. 122 8.1.6. События .................................................................................................. 124 8.1.7. Исключительные ситуации ................................................................... 124 9. Визуальная разработка программ в Delphi....................................................................127 9.1. Интегрированная среда разработки программ.............................................. 128 9.1.1. Проект ..................................................................................................... 129 9.2. Конструирование простого приложения ....................................................... 133 9.2.1. Интерфейс пользователя........................................................................ 134 9.2.2. Визуальное конструирование................................................................ 135 9.2.3. Реализация методов ............................................................................... 142 9.2.4. Обработка исключительных ситуаций ................................................. 145 9.2.5. Файлы приложения Калькулятор.......................................................... 146 9.3. Компоненты ввода/вывода данных StringGrid и Memo................................ 147 9.3.1. Компонент StringGrid – таблица строк ................................................. 147 9.3.2. Ввод массива. Компонент StringGrid.................................................... 149 9.3.3. Компонент Memo – многострочное окно редактирования ................. 151 9.3.4. Ввод массива. Компонент Memo .......................................................... 152 9.4. Немного о графике .......................................................................................... 154 9.4.1. Свойство Canvas. Построение графика функции ................................ 154 9.4.2. Событие OnPaint..................................................................................... 160 10. Тестирующая программа по основам языка Pascal....................................................162 10.1. Руководство преподавателя.......................................................................... 162 10.2. Руководство пользователя ............................................................................ 166 Список литературы...............................................................................................................168 Приложение А. Текст модуля Figures................................................................................169 Приложение Б. Тексты файлов ProjectCalc.dpr и UnitCalc.pas .......................................169
5
Введение Что мы понимаем под программированием Реальность программного обеспечения не встраивается естественным образом в пространство. У него нет готового геометрического представления подобно тому, как местность представляется картой, кремниевые микросхемы – диаграммами, компьютеры – схемами соединений. Абстрактной сущностью программного объекта является конструкция, состоящая из сцепленных вместе концепций: наборов данных, взаимосвязей между элементами данных, алгоритмов и вызовов функций. Однако программная конструкция реальна в том смысле, что она работает, производя видимые результаты, которые отделимы от самой конструкции: печатает значения данных, рисует картинки, производит звуки, приводит в движение рычаги. В наше время осуществилось волшебство мифа и легенды. С клавиатуры вводится верное заклинание, и экран монитора оживает, показывая то, чего никогда не было и не могло быть. Компьютерная программа – это послание человека машине. Строго выстроенный синтаксис и тщательные определения нацелены на то, чтобы бездумной машине стали понятны намерения человека. Однако при составлении программы необходима безошибочная точность действий. В этом отношении компьютер также напоминает волшебство. Один неверный знак, одна пауза в заклинании, и чудо не состоялось. Человеку несвойственно совершенство, и оно является необходимым лишь в немногих сферах его деятельности. При освоении программирования труднее всего привыкнуть к требованию совершенства [По материалам статьи: Брукс Ф. Мифический человекомесяц или как создаются программные системы. – Изд. 2. – 1995]. 6
Программировать – это исключительно точно, шаг за шагом, описать последовательность преобразования информации с такой строгостью, которая не требуется ни при каком другом виде человеческой деятельности. Сложность программирования связана не столько с изучением какого-нибудь языка программирования, сколько с освоением нового способа мышления. Чтобы освоить этот способ описания преобразования информации в виде программы, мы выбрали простой, но в то же время обладающий достаточной мощью, строго типизированный язык программирования – Pascal. Этот язык выбран нами в качестве базового, потому что он содержит основные конструкции и способы обработки данных, которые присущи всем современным языкам программирования. Поняв его, программисту будет легче осваивать такие языки, как Object Pascal, С++, Java, C#, Eiffel и многие другие.
7
1. Обработка информации на компьютере 1.1. Модель обработки информации на компьютере Обработка информации – это практическая реализация некоторой функции F, которая отображает множество данных D во множество возможных результатов R. F – произвольная функция, которую надо «вычислить»: перевод текста с русского на английский, нахождение максимума, расчет траектории ракеты, построение оптимального плана и так далее. Чтобы выполнить обработку информации на компьютере необходимо располагать тремя «физическими» представлениями (рисунок 1.1): D' – физическое представление данных D; R' – физическое представление результатов R; F' – физическое представление функции обработки F.
8
Рисунок 1.1 – Модель обработки информации на компьютере
Таким образом, обработка информации на компьютере включает в себя следующие процессы: • ввод данных – чтение данных с устройства ввода (например, клавиатура) в оперативную память компьютера. При этом данные из «внешнего» представления кодируются в представление на уровне компьютера; • вычисление – выполнение последовательности действий, которые необходимы для преобразования данных в результаты. Данная последовательность должна быть описана таким образом, чтобы ее мог выполнить процессор компьютера; • вывод данных – отображение (запись) полученных результатов на устройстве вывода (например, дисплей). При этом результаты из представления на уровне компьютера преобразуются к виду, понятному человеку. Введем несколько ключевых понятий. Программа – это совокупность данных, результатов и автоматизированного преобразования, такого, что каждому x из множества данных D ставится в соответствие результат y, принадлежащий множеству результатов R. В зависимости от уровня представления данных и функции автоматизированного преобразования информации говорят об исходной программе (данные D, R и функция F) и машинной программе (данные D', R' и функция F'). Описание исходной программы выполняется на языке программирования высокого уровня (например, Pascal, C++), описание машинной программы – на языке низкого уровня (например, Assembler). Язык программирования – это система описания программ, достаточно близкая к человеку, чтобы программу можно было легко написать, понять и изменить, но в то же время достаточно строго определенная, чтобы ее мог выполнить компьютер. Что делает язык программирования высокого уровня? Он освобождает программу от значительной доли необязательной сложности. Исходная (абстрактная) программа состоит из концептуальных конструкций: операций, типов данных, последовательностей и других 9
абстрактных компонентов. Машинная программа связана с битами, регистрами, условиями, переходами, каналами, дисками и пр. В той мере, в какой в языке высокого уровня воплощены необходимые абстрактной программе конструкции и избегаются конструкции низшего порядка, он ликвидирует целый уровень сложности, совершенно не являющийся необходимым свойством программы. Компилятор – это специальная программа, которая переводит текст исходной программы, написанной на языке программирования, в последовательность команд процессора. Компилятор создает машинную программу на языке процессора, эквивалентную исходной программе.
1.2. Основные объекты языка программирования 1.2.1. Синтаксические элементы языка программирования Синтаксис языка программирования – это система обозначений правильных последовательностей синтаксических элементов программы. Правило построения правильных последовательностей символов программы может быть записано как в текстовом представлении (например, нормальная форма Бэкуса – НФБ), так и в графическом (например, синтаксический граф). И в том, и в другом случае для задания правила используются терминальные символы, определенные в языке программирования, и нетерминальные, вспомогательные символы. Пример НФБ: <цифра>::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Это правило читается так: "Цифра по определению есть 0 или 1, или 2, или … или 9". Символы этого правила: <цифра> – нетерминальный символ (заключается в < >); ::= – операция "по определению есть"; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 – терминальные символы; | – операция "или".
10
Данное правило определяет, что в языке допустимыми – правильными – являются только десять арабских цифр (от 0 до 9). К синтаксическим элементам языка программирования обычно относят следующие. Набор символов – буквы и цифры (например, символы ASCII, американского стандарта обмена информацией), а также ряд специальных символов. Идентификаторы – имена объектов языка (типов, констант, переменных и др.). Идентификатор состоит из последовательности букв и цифр, которая всегда начинается с буквы. Символы (знаки) операций, ограничители и скобки – например, символы арифметических и логических операций (+, -, /, *, not, and, or и др.), символы операций отношения (<>, =, >= и др.); символ ; – ограничитель операторов; круглые скобки и операторные скобки begin … end – парные ограничители. Ключевые слова – идентификаторы, используемые в качестве фиксированной части синтаксиса какой-либо конструкции языка (например, слово if служит началом условного оператора). Выражения – конструкции языка для вычисления и изменения значений. Выражения включают символы операций и операнды (константы, переменные и другие объекты языка). Операторы – конструкции языка, необходимые для управления порядком действий по обработке информации. Самые важные синтаксические компоненты языка. Комментарии – пояснения, включаемые в текст программы, но не обрабатываемые компилятором. Комментарии заключаются в фигурные скобки: { текст в фигурных скобках – это комментарий }
1.2.2. Значения и типы Цель программы состоит в вычислении значений. Значение данных может представлять собой число, символ или указатель на другой объект данных. При этом компьютер оперирует с физическими представлениями значений, которыми являются сово-
11
купности битов, байтов или слов оперативной памяти (множества D' и R'на рисунке 1.1). Одной из главных характеристик данных является тип. Тип определяет физическое представление данных, а также множество допустимых значений и операций над ними. Например, тип integer (целый) определяет целые значения со знаком, которые занимают в памяти 2 байта. Допустимые значения такого типа лежат в диапазоне от –32768 до +32767. Тип в языке Pascal может определяться программистом: type <имя типа> = <описание типа>
Пример: type boolean = (false, true);
Простые типы языка Pascal приведены в таблице 1.1. Таблица 1.1 – Простые типы языка Pascal Тип данных
Ключевое слово
Интервал допустимых значений
Целый
integer
–32768 ..+32767
Байтовый
byte
0 .. 255
Вещественный
real
2.9*10 .. 3.4*10
Логический
boolean
false, true
Символьный
char
Символы кодовой таблицы
-39
38
1.2.3. Константы и переменные Константы – это данные, значения которых не изменяются при выполнении программы. Константа в языке программирования характеризуется следующими атрибутами: • наименование; • значение. Формат описания в программе: <имя константы> = <значение>;
12
Пример: N = 10; {N – имя константы, 10 – значение}
Переменные – это данные, значения которых изменяются при выполнении программы. Переменная в языке программирования характеризуется следующими атрибутами: • наименование; • тип; • текущее значение. Формат описания в программе: <имя переменной> : <тип>;
Пример: X: byte; {X – имя переменной, byte – тип}
Описание переменной подразумевает выделение памяти для хранения ее значения, но не определяет само значение переменной! Поэтому в программе все начальные значения переменных должны быть инициализированы (заданы) до первого «использования» переменных. Инициализировать переменные можно, например, с помощью операторов присваивания или ввода.
1.2.4. Выражения Выражение предназначено для вычисления значения и состоит из операндов (констант, переменных, функций) и операций над ними. Порядок действий в выражении определяется приоритетами знаков операций и круглыми скобками. Типы операндов, входящих в выражение, должны совпадать или удовлетворять правилам согласования типов языка программирования. Выражения называют арифметическими, «отношения», логическими и символьными в зависимости от того, какого типа операнды и операции в них используются. Арифметические выражения включают операции, допустимые для переменных числовых типов (integer, byte, real и др.). Приоритет операций в порядке убывания следующий: /, ∗, div (частное от деления целых чисел), mod (остаток от деления целых чисел),
13
and (поразрядное «и»), or (поразрядное «или»), shl (сдвиг влево), shr (сдвиг вправо), −, +.
Пример: 45.2 / 4 { результат 11.3 } r mod 10 {если r = 25, результат 5 } r div 10 {если r = 25, результат 2 } d1 shl 2 {если d1 = 2, результат 8 }
Выражения отношения выполняют сравнение операндов и определяют истинно выражение или ложно. Все операции выражения являются бинарными. Приоритет операций в порядке убывания следующий: =, <>, <, >, <=, >=, in (операция принадлежности множеству). Результат всегда имеет логический тип. Пример: W <= R {если W = 25, R = 34, результат true } f1 <> 5 {если f1 = 5 , результат false } ch in ['a'..'z'] {если ch – латинская буква, результат true }
Логические выражения выполняют логические операции над логическими операндами. Приоритет операций в порядке убывания следующий: not, and, or, xor. Пример: (W and R) or (not f1 and f2) {если W, f2=true; R, f1=false, результат true}
Символьное выражение включает такие операнды, как символьная константа, символьная переменная, элемент массива символьного типа, функция, возвращающая значение символьного типа. Над операндами может выполняться операция конкатенации (объединения) – +. Пример: 'Pas'+'cal' {результат – символьная константа 'Pascal' } 14
Относительные приоритеты операций языка Pascal приведены в таблице 1.2. Таблица 1.2 – Приоритет операций в языке Pascal Операция
Приоритет
@, not
Первый (высший)
∗, /, div, mod, and, shl, shr
Второй
+, -, or, xor
Третий
=, <>, >,<, <=,>=, in
Четвертый (низший)
1.2.5. Операторы Для описания последовательности действий, необходимых для «вычисления» значений, в языке программирования используют операторы. Различают операторы следующих видов: • операторы собственно обработки информации. К ним будем относить оператор присваивания, операторы чтения (ввода) и операторы записи (вывода); • операторы управления работой программы во времени. Эти операторы реализуют «управляющие структуры», которые определяют последовательные, разветвляющиеся и циклические вычислительные процессы. Оператор присваивания (:=) предписывает выполнить выражение, заданное в его правой части, и присвоить полученное значение переменной, идентификатор которой расположен в его левой части. Переменная и результат вычисления выражения должны иметь один и тот же тип (или типы, подчиняющиеся правилам согласования типов языка Pascal). Формат: <имя переменной> := <выражение>;
Пример: var A, B, C, f1 : integer; V, r, s : real; F : boolean;
15
begin A := B div C; V := 34.6 + s∗r; F := f1 <> 5; end.
Все переменные должны быть предварительно описаны, а переменные, входящие в выражение, обязательно инициализированы (им должно быть присвоено некоторое значение). Операторы чтения (ввода) данных. В языке Pascal используются два оператора ввода: read и readln. Оператор read Формат: read(X1, X2, ..., Xn); { X1, X2, ..., Xn – переменные допустимых типов данных} { тип Boolean не допустим! }
Значения для переменных X1, X2, ..., Xn набираются пользователем на клавиатуре, минимум, через один пробел (в тексте пробел будем обозначать символом 9 ). После набора данных нажимается клавиша «Ввод» (Enter). Оператор readln Аналогичен оператору read. Единственное отличие заключается в том, что после считывания последнего в списке значения будет очищен буфер клавиатуры. Пример: Ввод значений двух целых чисел x и y: readln(x,y); { если Пользователь набрал на клавиатуре: 295 } { и нажал клавишу Enter, то значением x будет 2, y – 5 }
Операторы записи (вывода) данных. В языке Pascal используются два оператора вывода: write и writeln. Оператор write Формат: write (Y1, Y2, ..., Yn);
где Y1, Y2, ..., Yn – выражения.
16
После каждого выражения через двоеточие может быть записан формат вывода. Первое число, стоящее за двоеточием, определяет ширину поля вывода. Второе число в описании формата используется только для вывода вещественного значения и определяет количество цифр дробной части значения. Пример: write (a:8:3); { если значение переменной a (a: real) равно 38.52, } { результат вывода будет таким: 9938.529 }
Если формат не указан, то значение будет размещено при выводе в поле, ширина которого установлена вычислительной системой. Оператор writeln Аналогичен оператору write, но после вывода последнего в списке значения происходит перевод курсора в начало следующей строки. Оператор writeln, записанный без параметров, вызывает перевод курсора на новую строку. Пример: writeln ('При9X9равном9', x:2); {если x=5, y=12 (x, y: integer), то } writeln ('Y9равен9', y:8); {результат вывода будет таким: } {При9X9равном995 } {Y9равен999999912 }
1.3. Простая программа Программа в языке Pascal включает следующие компоненты: Program < имя программы>; uses < список модулей, используемых в программе >; const < раздел описания констант >; type < раздел описания типов >; var < раздел описания переменных >; function < описание функции >; procedure < описание процедуры >; begin {основной блок программы } <операторы>; end.
17
Пример простой программы Программа вычисляет значение общих затрат на приобретение определенного количества товара по известной цене за его единицу. Покупка товара осуществляется в фирме «Товары – почтой», где, кроме стоимости товара, взимается почтовый сбор. Программа вычисляет значение: общие затраты = количество товара × стоимость единицы + + почтовый сбор
Текст программы Account (расчет) и пояснения приведены ниже (таблица 1.3). Таблица 1.3 – Текст программы Account Текст программы
Пояснения
18
program Account;
Заголовок программы Account
const POSTAGE = 5;
Раздел описания констант почтовый сбор: имя константы – POSTAGE значение –5
Var number: integer;
Раздел описания переменных Количество товара : имя – number тип – целый Цена единицы товара: имя – price тип – целый Стоимость товара : имя – cost тип – целый
price
: integer;
cost
: integer;
begin readln(number, price); cost:= number ∗ price;
cost:= cost + POSTAGE;
writeln(cost); end.
Раздел операторов (основной блок) Оператор ввода с клавиатуры значений переменных number и price Оператор присваивания переменной cost значения произведения значений переменных number и price (результат – стоимость товара без почтового сбора) Оператор присваивания переменной cost суммы ее предыдущего значения и значения константы POSTAGE (другими словами, увеличивает значение переменной cost на значение константы POSTAGE). Вычисленное значение – общие затраты Оператор вывода на дисплей значения переменной cost (общие затраты) Завершение раздела операторов (завершение текста программы) После символа «.» (точка) любой текст компилятором не воспринимается и не обрабатывается!
Выполним трассировку (прослеживание) программы при значении переменных number = 4, price = 10. В таблицу занесем точное отображение того, как изменяются значения переменных в основном блоке программы (таблица 1.4). Таблица 1.4 – Трассировка программы Account Оператор
Значения констант и переменных POSTAGE
19
number
price
cost
вход в программу
Begin 5
?
?
?
readln ( number, price );
5
4
10
?
cost := number ∗ price;
5
4
10
40
cost := cost + POSTAGE;
5
4
10
45
writeln ( cost );
Вывод на дисплей: 45
End
Выход из программы
1.4. Работа в среде Turbo Pascal 1.4.1. Создание, загрузка и сохранение программы Создание новой программы и сохранение ее текста. Выполните следующую последовательность действий: • войдите в интегрированную среду разработки (ИСР) программ на языке Pascal и по клавише F10 вызовите главное меню; • войдите в меню File (рисунок 1.2).
Рисунок 1.2 – Меню работы с файлами (File)
На рисунке 1.2: New Open Save Save as Change dir
– «Новый», – «Открыть», – «Сохранить», – «Сохранить как», – «Изменить каталог»,
20
– «Печать», – «Выход». Exit Переход по пунктам меню осуществляется клавишами управления курсором, а выбор пункта – клавишей Enter. • Для первоначального сохранения текста программы на диске выберите в меню File пункт Save as (см. рисунок 1.2). В появившемся окне Save File as наберите имя файла (можно без расширения pas) и щелкните левой кнопкой мыши по кнопке OK. Переключение между элементами окна Save File as осуществляется клавишей Tab, выполнение действия – клавишей Enter. Сохранение программы. Если необходимо сохранить текст программы в файле, имя которого уже определено, выберите в меню File пункт Save (см. рисунок 1.2) и нажмите Enter. Это же действие можно выполнить, нажав на клавишу F2. Загрузка программы. Для работы с уже созданной программой (файл с расширением pas уже существует) необходимо выполнить загрузку программы в среду разработки: • войдите в ИСР Pascal, • по клавише F10 вызовите главное меню и войдите в меню File, • выберите в меню File пункт Open (см. рисунок 1.2). В появившемся окне Open a File наберите имя программного файла и щелкните левой кнопкой мыши по кнопке Open. Это же действие можно выполнить, нажав на клавишу F3. Print
1.4.2. Компиляция и выполнение программы Компиляция программы. Компилятор ИСР Pascal выполняет синтаксический анализ исходного текста программы (файл с расширением pas) и в случае отсутствия ошибок создает эквивалентную ему машинную программу (файл с расширением exe). Для компиляции программы выберите из меню Compile пункт Compile или нажмите комбинацию клавиш ALT+F9. При обнаруже-
21
нии ошибки в верхней части окна появится соответствующее сообщение. В этом случае необходимо устранить ошибку и повторно выполнить компиляцию. Если ошибок не обнаружено, на экране появляется сообщение об успешной компиляции (рисунок 1.3). Сообщение может быть удалено с экрана нажатием любой клавиши.
Рисунок 1.3 – Сообщение об успешной компиляции
Выполнение программы. Для выполнения успешно откомпилированной программы необходимо выбрать в меню Run пункт Run или нажать клавиши Ctrl+F9. Просмотр результатов. Для просмотра результатов работы программы нажмите клавиши Alt+F5. Возврат в окно редактирования программы осуществляется нажатием любой клавиши.
1.5. Лабораторные задания 1.5.1. «Логические» задачи 1. В поезде ехали Аня, Галя и Женя. Их профессии – журналист, доктор и менеджер. Они читали газеты «Аргументы и факты», «Жизнь России», «Правда». Кто какую газету читал и у кого какая профессия, если известно, что:
22
Галя не доктор, Аня не читала «Аргументы и факты», имя, профессия одного из пассажиров и название газеты совпадают по первой букве. 2. Программист был в гостях у своего друга, у которого трое детей. Друг предложил программисту определить возраст каждого ребенка, сообщив ему, что произведение их возрастов равно 36. Обдумав задачу, программист сказал, что ему необходима подсказка. Тогда его друг назвал ему сумму возрастов детей. Подумав еще немного, программист попросил еще какую-нибудь подсказку. «Старший играет на пианино». Услышав это, программист назвал возраст каждого ребенка. Сколько лет детям? 3. Когда вы садились в лодку, ваша шляпа упала в воду, но вы этого не заметили. Скорость течения реки 2,5 км/ч. Шляпа поплыла вниз по течению. Тем временем вы плыли вверх против течения реки со скоростью 4,75 км/ч (относительно воды). Спустя 10 мин вы заметили пропажу, развернули лодку и поплыли вниз по реке догонять шляпу. Через какое время вы поймаете шляпу? 4 Допустим, у нас есть большой и маленький стаканчики для вина. Сначала наполним вином маленький стаканчик и перельем его в большой. Затем наполним маленький стаканчик водой. Перельем некоторое количество воды из маленького стаканчика в большой стаканчик и смешаем воду с вином. После этого перельем смесь из большого стаканчика в маленький стаканчик, пока он не наполнится. Чего теперь больше в маленьком стаканчике – воды в вине или вина в воде?
5. Перед соревнованиями участники A, B, C, D делали прогнозы: участник A предсказал, что победит B, участник B предсказал, что D будет последним, участник C предсказал, что A будет третьим, участник D предсказал, что сбудется прогноз A.
23
Только один прогноз был верным, и это был прогноз победителя. В каком порядке закончили соревнования участники? 6. Путешественник, у которого есть золотая цепочка из 7 звеньев, должен остановиться в уединенном отеле на 7 ночей. Плата за каждую ночь в отеле составляет одно звено его цепочки. Какое наименьшее число звеньев надо разрезать, чтобы путешественник мог платить владельцу отеля одно звено каждое утро, не внося плату заранее? 7. Отец с двумя сыновьями отправился в поход. На их пути встретилась река, у берега которой находилась лодка. Лодка выдерживает на воде либо отца, либо сыновей. Как переправиться на другой берег путешественникам и сколько им потребуется времени, если каждая поездка через реку занимает 5 мин? 8. На некоторой планете Х деревья растут очень быстро. За день пока солнце поднимается и находится в зените, они вырастают на 1 м, когда же солнце заходит, их рост сокращается на 10 см. На какой день высота нового дерева превысит 4,5 м? 9. В кафе встретились три друга: скульптор Белов, скрипач Чернов и художник Рыжов. «Замечательно, что один из нас имеет белые, другой – черные, а третий – рыжие волосы, но при этом ни у одного из нас нет волос того цвета, на который указывает фамилия», – заметил черноволосый. «Ты прав», – сказал Белов. Какой цвет волос у художника? 10. Определите значение выражения x and 1 = 0 при различных значениях логической переменной x. Зависит ли значение выражения от x?
1.5.2. Составление простых программ 1. Написать программу, которая присваивает переменной A результат вычисления заданного выражения (значения переменных выражения вводятся с клавиатуры): a. (S > 6) and (F <> 2) b. (R shl 2) + 1
24
c. (K mod 10) ∗ 5 d. W / T ∗ 10 – 1.25 e. (C div D) > 3
2. Написать программу вывода таблицы истинности для логической операции: a. «ИЛИ», b. «И», c. «НЕ», d. «Исключающее ИЛИ». Если операнды имеют различные значения, то значение операции «Исключающее ИЛИ» – true, в противном случае – false.
3. Написать программу, которая преобразует дробное число в денежный формат. Например, число 25.5 преобразуется в 25 руб. 50 коп. 4. Написать программу, которая пересчитывает временной интервал, заданный в минутах, в количество часов и минут. Например, число 150 преобразуется в 2 ч 30 мин. 5. Написать программу, которая переводит вес, заданный в фунтах, в килограммы (1 российский фунт = 409.5 г). 6. Написать программу, которая вычисляет площадь треугольника, если известны координаты его углов x1, y1; x2, y2; x3, y3: 1 S = ± ∗ (( x1 − x3 ) ∗ ( y 2 − y3 ) − ( x2 − x3 ) ∗ ( y1 − y3 )) . 2
7. Написать программу, которая вычисляет время, через которое встретятся движущиеся навстречу друг другу автомобили, если их скорости V1 и V2, а начальное расстояние между ними – S. 8. Написать программу, рассчитывающую расстояние, которое пройдет автобус (его скорость V1), пока его не догонит легковой автомобиль. Легковой автомобиль отправляется из того же пункта, что и автобус, с задержкой в 30 мин. Скорость автомобиля – V2 9. Программа печатает квадрат на экране из символов '∗' и '9': ∗99∗99∗99∗ 25
∗99999999∗ ∗99999999∗ ∗99∗99∗99∗ 10. Программа выводит на экран рисунок, состоящий из символов '∗' и '9': a)∗9999
b) ∗∗∗∗∗
c) 9999∗ d) ∗∗∗∗∗
∗∗999
∗∗∗∗9
999∗∗
9∗∗∗∗
∗∗∗99
∗∗∗99
99∗∗∗
99∗∗∗
∗∗∗∗9 ∗∗∗∗∗
∗∗999 ∗9999
9∗∗∗∗
999∗∗
∗∗∗∗∗
9999∗
26
2. Управляющие структуры 2.1. Обзор управляющих структур Процессор компьютера способен выполнять некоторое число элементарных операций над данными: сложение, вычитание, присваивание, сравнение и др. Процессор может самостоятельно управлять последовательностью этих операций во времени по заданной программе. Каким образом с помощью программы можно указать порядок выполнения операций? Для этого в программе используют три основные категории управляющих структур: последовательность; ветвление (порядок выполнения определяется значением условия); цикл (повторение). Эти структуры дают нам «конструктор», комбинируя элементы которого, можно реализовать процесс вычислений произвольной сложности, сохраняя отчетливое видение общей структуры процесса. Все управляющие структуры имеют один вход и один выход. Базовыми структурами являются структуры «Последовательность», «Если_То_Иначе» и «Цикл_Пока». Все современные языки программирования имеют операторы, которые однозначно реализуют управляющие структуры. Рассмотрим управляющие структуры и операторы языка Pascal, которые их реализуют (таблица 2.1). Для графического представления управляющих структур будем использовать следующие узлы (рисунок 2.1). Функциональный
Предикатный (условный) Да
A Определяет изменение данных
P
Слияния
Нет
Определяет последовательность выполнения
Объединяет «ветви» выполнения
Рисунок 2.1 – Узлы управляющих структур
27
Таблица 2.1 – Управляющие структуры Оператор языка Pascal
Управляющая структура
Пример
A; B; Последовательность
Если_То_Иначе
Сначала выполняется A, затем B. A, B – операторы обработки информации
readln(x); y:= x;
if P then A else B;
if x>0 then y:= 1
Если значение логическо- else y:=0; го выражения P истинно, то выполняется A, иначе – B Если_То if P then A;
Выбор
case K of 1: A; 2: B; 3: C else D; end; K – переключатель, пе-
ременная, значение которой определяет выполнение операторов: если K = 1, то A; если K = 2, то B; если K = 3, то C, иначе – D
28
if x>0 then y:= 1;
var ch: char; begin ... case ch of '0'..'9': writeln ('Это цифра'); 'a'..'z': writeln ('Это буква') else writeln ('Это другой символ'); end; ... end.
Продолжение таблицы 2.1 Оператор языка Pascal
Управляющая структура
Пример
Цикл_Пока (цикл с предусловием)
while P do A;
while N>0 do
Пока значение логического выражения P истинно, оператор A выполняется
N:=N-1;
Цикл_со_счетчиком (цикл с предусловием) for i:= <начальное значение> to <конечное do
значение>
A;
Переменная i – это показатель цикла, значение которого на каждом шаге цикла автоматически увеличивается (или уменьшается) на 1
Цикл_До
for i:= 1 to N do writeln(i); for i:= N downto 1 do writeln(i);
repeat
(цикл с постусловием)
A; until P;
repeat
Оператор A выполняется до тех пор, пока логическое выражение P не станет истинным
until N <= 0;
N:=N-1;
29
2.2. Составной оператор Управляющие структуры ветвления и цикла в каждой своей «ветви» содержат не более одного оператора обработки информации (в таблице 2.1 A, B). Во многих программах этого недостаточно даже для реализации простого алгоритма. Для того, чтобы распространить область действия значения условия или цикла на несколько операторов, необходимо объединить их в составной оператор. Составной оператор – это последовательность операторов, заключенная в операторные скобки begin …end. Пример: if x>0 then begin y:= 1; { здесь составной оператор – это операторы y:=1 и k:=k+1,} k:= k+1; { которые выполняются только при условии, что x > 0 } end;
На практике использование составного оператора означает, что мы просто заменяем функциональный узел «внутри» управляющей структуры такой управляющей структурой, которая необходима для реализации алгоритма. В приведенном примере функциональный узел в структуре «Если_То» был заменен структурой «Последовательность» (рисунок 2.2). Этот способ построения программы дает нам возможность, используя всего несколько базовых структур, построить программу любой сложности. При этом разработка программы осуществляется «сверху вниз»: от общей структуры программы, как одного функционального узла, к ее конкретному уточненному представлению в виде совокупности вложенных управляющих структур.
2.3. Операторы прерывания выполнения цикла Реализация циклических алгоритмов требует в некоторых случаях прекращения «шага» цикла или всего цикла до выполнения условия
30
его завершения. Для этих целей в языках программирования предусмотрены специальные операторы (НЕ управляющие структуры!).
A
Да
Составной оператор содержит операторы y:=1; k:=k+1;
P Нет
begin Да
y:=1
k:=k+1
end
x>0 Нет
Рисунок 2.2 – Составной оператор
В языке Pascal это такие операторы: continue – оператор завершения шага цикла. По этому оператору прекращается выполнение текущего шага цикла, и управление передается на следующий шаг; break – оператор «выхода» из цикла. Прекращается выполнение цикла и управление передается оператору, следующему за последним оператором цикла; exit – оператор «выхода» из программы. По этому оператору выполнение программы завершается. Рекомендуется использовать для выхода из подпрограмм. В качестве примера рассмотрим такую задачу. Пусть компьютер «задумал» случайное число (переменная M) в диапазоне от 0 до 10. Пользователь вводит с клавиатуры число (переменная N), пытаясь угадать «задумку» компьютера. Программа подсчитывает количество «угадываний» пользователя (переменная K).
31
uses crt; { Подключение системного модуля crt языка Pascal } { Здесь он нужен для генерации случайных чисел. } var K, M, N: byte; begin randomize; { Инициализация датчика случайных чисел } M := random(10); { Генерация случайного числа в диапазоне } { от 0 до 10 } K := 0; { Количество угадываний в начале равно 0 } while true do { «Бесконечный» цикл } begin writeln('Введите число в диапазоне от 0 до 10'); readln(N); K := K+1; { Количество «угадываний» увеличивается на 1. } if N = M then break; { Выход из цикла: Пользователь угадал число } end; writeln('Число угадываний = ', K); end.
2.4. Работа в среде Turbo Pascal 2.4.1. Редактирование текста программы. Работа с блоками Блок – горизонтальный участок текста, содержащий символы одной или нескольких строк. Для работы с блоками используют меню Edit (рисунок 2.3) или комбинации клавиш.
32
Рисунок 2.3 – Меню работы с блоками (Edit)
На рисунке 2.3: Undo – отменить действие; Redo – повторить действие; Cut – вырезать и поместить в буфер обмена (clipboard); Copy – копировать (поместить копию) в буфер обмена; Paste – вставить в текст из буфера обмена; Clear – удалить выделенный текст; Show clipboard – показать буфер обмена. Комбинации клавиш для работы с блоками следующие: отметить блок можно клавишами управления курсором при нажатой клавише Shift; копировать отмеченный блок в указанную курсором позицию можно клавишами Ctr+K+C или за два шага: – Ctrl+Ins – копировать блок в буфер обмена (clipboard), – Shift+Ins – вставить блок из буфера обмена в текст; переместить отмеченный блок в указанную курсором позицию можно клавишами Ctrl+K+V или за два шага: – Shift+Del – вырезать блок и поместить в буфер обмена, – Shift+Ins – вставить блок из буфера обмена в текст; удалить отмеченный блок можно клавишами Ctrl+Del или Ctrl+K+Y;
спрятать (убрать отметку)/показать блок можно клавишами Ctrl+K+H;
33
записать блок в файл можно клавишами Ctrl+K+W. Имя файла для сохранения блока указывается в появляющемся диалоговом окне; считать блок из файла можно клавишами Ctrl+K+R. Блок помещается в текст, начиная с текущей позиции курсора. Имя файла указывается в появляющемся окне; Вывести блок на печать можно клавишами Ctrl+K+P.
2.4.2. Отладка программ Отладка программы – это поиск ошибок в программе (тестирование) и исправление ошибок. Интегрированная среда разработки Pascal предоставляет программисту средства, которые позволяют просматривать и модифицировать значения данных в процессе выполнения программы, а также выполнять программу в пошаговом режиме и прерывать ее выполнение в точке останова (точке прерывания). Режим выполнения программы определяется пунктами меню Run. Меню отладки Debug позволяет задать точки останова, просмотреть и модифицировать данные. Режимы выполнения программы. Меню Run (рисунок 2.4) содержит следующие пункты, которые определяют режимы выполнения программы: Run – выполнение программы; Trace over – выполнение программы «по шагам» (трассировка программы): оператор за оператором. При этом вызов подпрограммы выполняется за один шаг. Если операторы расположены на одной строке, то шаг отладки будет распространяться на все операторы строки. Чтобы точно определить, какие операторы выполняются, располагайте на строке только один оператор!
34
Рисунок 2.4 – Меню выполнения программы (Run)
Trace into – выполнение программы «по шагам» с трассировкой операторов подпрограмм; Go to cursor – выполнение программы до оператора, указанного курсором; Program reset – завершение (прерывание) выполнения программы; Parameters... – задание параметров программы. Меню отладки. Меню Debug приведено на рисунке 2.5.
Рисунок 2.5 – Меню отладки программы (Debug)
На рисунке 2.5: Breakpoints…
– окно конфигурирования точек останова,
Call stack
– окно просмотра стека,
Register
– окно просмотра регистров,
35
Watch
– окно просмотра значений переменных,
Output
– Окно просмотра выводимых значений,
User screen
– «Экран пользователя»,
Evaluate/modify… – вычисление и изменение значений, Add watch…
– добавить переменную в окно Watch,
Add breakpoints… – добавить точки останова.
Как видно из названия пунктов меню Debug, ИСР Pascal позволяет организовать выполнение и отладку программы в многооконном режиме. Пример пошаговой отладки программы с использованием окна просмотра значений переменных приведен на рисунках 2.6 и рисунке 2.7.
Рисунок 2.6 – Добавление значения переменной i в окно Watch
36
Рисунок 2.7 – Пошаговая отладка программы с просмотром значений переменных в окне Watch
2.5. Лабораторные задания 2.5.1. Реализовать схемы программ с помощью операторов языка Pascal (рисунок 2.8) 1.
2. X>0
3.
K=K+1
Нет
Да X=X–1 X>0
X=X–1
4.
Вывод K, X
Да
Не
K=K+1 Нет X=X+1
K=K+1 X<0 X = X +Да1
Вывод K, X Вывод K, X
Да K=K+1
37
X<0 Нет Вывод K, X
Рисунок 2.8 – Схемы программ. Начало
5.
6. Нет
K=K+1
Да
X>0
X=X–1 X=X–1 Да K=0
K=K+1
K<0 Нет
X<0
K=0
Нет
X>0 Да
Нет
Да
X=X–1
Вывод K, X
K=K+1
Вывод K, X
Рисунок 2.8 – Схемы программ. Продолжение
38
7.
8. Нет
X>0
Да
K= 1
K=K+1
X=X–1
X=X–1 K
K=0
Нет
X>0
Нет
Да
Вывод K, X
Да X>0
X=X–1
Да Нет
K=K+1 K=K+1 Вывод K, X
Рисунок 2.8 – Схемы программ. Продолжение
39
X=X–1
9.
10.
Нет
Да
X>0
X=X–1
K=0
K=–1
K= 1
Да
K>N или X≤0
K=K+1
Нет
Вывод K, X
X=X–1 X>0 Да
Нет
Нет
X<0 Да
K=K+1
Вывод K, X
Рисунок 2.8 – Схемы программ. Окончание
40
X=X–1
2.5.2. Выполнить трассировку и определить результаты программы 1. Пользователь ввел с клавиатуры значения 3 и 5. Определите, какое значение выведет компьютер на дисплей. program exam2_1; var f, x, y : integer; max, min: integer; begin readln(x,y); if x>=y then begin max:= x; min:= y; end else begin max:= y; min:= x; end; if x∗y>0 then f:=max else f:=min; writeln(f); end.
2. Нарисуйте область на плоскости, при попадании в которую точки с координатами x, y программа выводит значение True. program exam2_2; var x, y : integer; b:boolean; begin readln(x,y); b:= (abs(x-y)<=1) and (abs(x+y)<=1); writeln(b);
41
end.
3. Определите, в какие интервалы должно «попасть» значение х, чтобы программа выводила значение 0. program exam2_3; var f, x : integer; begin readln(x); if (x>=-1) and (x<=4) or (x>=5) and (x<=10) then f:= 1 else f:= 0; writeln(f); end.
4. Пользователь ввел с клавиатуры значение переменной х. Определите, какое значение выведет компьютер на дисплей, если х равно: 3; 4; -2; -4; 15. program exam2_4; var f, x: integer; begin readln(x); case x of 1, 3, 5, 7, 9 : f:=2∗x+1; 2, 4, 6, 8 : f:=2∗x; 10..100 : f:=x∗10; -3..-1 : f:=-1; else f:=0; end; writeln(f); end.
42
43
5.Выполните трассировку программы и определите результат. program exam2_5; var s, i, k: integer; begin s:= 0; k:= 1; for i:=1 to 5 do begin s:=s+i; k:=k*i; end; writeln(s+k); end.
6.Выполните трассировку программы и определите результат. program exam2_6; var s, i, k: integer; begin s:= 0; k:= 1; for i:=1 to 5 do begin s:=s+i; k:=k∗i; if s+k>25 then break; end; writeln(s:5, k:5); end.
44
7. Выполните трассировку программы и определите результат, если пользователь ввел с клавиатуры значения: 1, 7, 2. Дайте геометрическую интерпретацию работы программы, если значение переменной s рассматривать как площадь геометрической фигуры. program exam2_7; var s, x, x0, x1, d: integer; n : integer; begin readln(x0, x1, d); n:= (x1-x0) div d; x:= x0; s:= 0; while n>0 do begin s:=s+d∗x; x:=x+d; n:=n-1; end; writeln(s:5); end.
8. Пользователь ввел с клавиатуры значение переменной х. Выполните трассировку программы и определите результат, если х равно: 5; 8. Можно ли использовать программу для определения, простое число или нет? program exam2_8; var n, f, i: integer; begin readln(n); i:=2; f:=1;
45
while i<=sqrt(n) do begin if n mod i = 0 then begin f:=0; break; end; i:=i+1; end; writeln(f); end.
9. Программа должна вычислять значение наибольшего общего делителя. Выполните трассировку и проверьте работу программы для значений m и n: 4, 2; 12, 8. program exam2_9; var m, n, p: integer; begin readln(m, n); {m>n} repeat p:= m mod n; if p<>0 then begin m:= n; n:= p; end; until p=0; writeln(n); end.
10. Выполните трассировку и определите вид арифметического выражения, значение которого (переменная р) вычисляет программа.
46
program exam2_10; var s, i, k, n, p: integer; begin p:= 1; k:= 1; n:= 1; for i:=1 to 4 do begin s:=0; while k<=n do begin s:= s+k; k:= k+1; end; n:=i+k; p:=p*s; end; writeln(p); end.
2.5.3. Программирование с использованием управляющих структур Напишите программу, которая осуществляет обработку информации по одному из условий, заданных ниже. 1. Присвоить переменной К значение 1, если два числа из трех чисел x, y, z являются положительными и кратными 3, и значение 0 – в противном случае. 2. Найти наибольшее из трех чисел x, y, z. 3. Присвоить переменной К значение true, если точка с координатами x, y принадлежит заданной области, и значение false – в противном случае (рисунок 2.9). 4. Дано натуральное число N. Определить: a) сколько цифр 5 и 8 входит в это число, b) произведение цифр заданного натурального числа, 47
Рисунок 2.9 – Геометрические области
c) число, получаемое выписыванием в обратном порядке цифр заданного натурального числа, d) является ли заданное натуральное число палиндромом, т. е. таким, десятичная запись которого читается одинаково слева направо и справа налево, e) сколько чисел натурального ряда необходимо перемножить, чтобы их произведение превысило заданное натуральное число. 5. Определить десятичный эквивалент целого положительного двоичного числа К. 6. Определить двоичный эквивалент целого положительного десятичного числа N. 7. Вычислить сумму:
...
a)
3+ 6+ 9+
b)
1 1 + + 1∗ 3 3∗5
96 + 99 ,
... +
1 , 199 ∗ 201
48
c)
1 1 1 1 1 1 1 1 1 1 1 1 ( + )( + + )...( + + + + + ), 3 5 7 9 11 13 33 35 37 39 41 43
d) x −
x 3 x5 x 2 n +1 n (с точностью 0.001). + − K + (− 1) ⋅ (2n + 1)! 3! 5!
8. Начав тренировки, спортсмен в первый день пробежал 10 км. Каждый следующий день он увеличивал дневную норму на 10 % от нормы предыдущего дня. Какой суммарный путь пробежит спортсмен за 7 дней? 9. Вычислить приближенную площадь одной арки косинусоиды, разделив отрезок от –π/2 до π/2 на 10 частей и суммируя площади десяти прямоугольников с основанием π/10 и высотой, равной значению функции на правой границе каждого интервала. 10. Найти три таких целых числа a, b и c в диапазоне от 0 до 20, для которых справедливо равенство Пифагора a2 + b2 = c2.
49
3. Структуры данных 3.1. Массивы Массив – это структура данных, состоящая из фиксированного числа элементов, имеющих один и тот же тип и расположенных в памяти последовательно. Операция выбора элемента массива называется индексацией; синтаксически она записывается как имя массива, за которым в квадратных скобках следует значение индекса (номера) выбираемого элемента. Массив – это структура данных с произвольным доступом, т. е. время доступа к значению элемента массива не зависит от номера элемента. Формат описания массива: array[<размерность>] of <тип элементов>;
Пример: type ArrayType1 = (one, two, three); ArrayType2 = 1..5; var mas_int : array[- 5..5] of integer; mas_real : array[1..7, 1..4] of real; mas_byte1 : array[ArrayType1] of byte; mas_byte2 : array[ArrayType2] of byte; begin mas_int[- 4] := 10; mas_real[2, 5] := 10.5; mas_byte1[one]:= 75; mas_byte2[2] := mas_byte1[one]; end;
50
3.1.1. Действия над массивами Над массивами, как едиными целыми, допустимы только операции сравнения =, <> и операция присваивания. Массивы, участвующие в этих операциях, должны иметь одинаковые размерности и типы компонент. Пример: const N=2; M=3; type massiv = array[1..N, 1..M] of real; {2-мерный массив, N строк } { и M столбцов элементы вещественного типа } var a, b : massiv; { описание 2-мерных массивов a и b } c :array[1..10] of integer; { описание одномерного массива } { c из 10 элементов целого типа } i, j : byte; { индексы элементов массивов } begin {ввод значений массива c} for i:=1 to 10 do readln(c[i]); {инициализация массива a значением переменной i} for i:=1 to N do for j:=1 to M do a[i, j]:=i; {присвоение элементам b соответствующих значений элементов a }
b:=a;
{ возможно только для массивов одинакового типа! }
{вывод значений массива b по строкам} for i:=1 to N do begin for j:=1 to M do begin { вывод i–й строки массива b }
51
write(b[i, j]); end; writeln; end; end.
{ переход на новую строку }
3.2. Строки Строка – это объект данных, составленный из последовательности символов. В программе на языке Pascal можно определить некоторую максимальную длину строки, а фактически строки могут содержать меньшее количество символов или не содержать их совсем (пустая строка). При выполнении программы длина строки может изменяться. Максимальная длина строки не превышает 255 символов. Физическое представление строки приведено на рисунке 3.1.
Рисунок 3.1 – Физическое представление строки
Формат описания строки: string; {в этом случае максимальная длина строки = 255} string [<максимальная длина строки>];
Существует множество операций над строками, наиболее важные их них следующие: операция конкатенации (+) применяется для объединения двух строк в одну результирующую строку; операции отношения ( =, <>, >, <, >=, <= ) используются для сравнения двух строк. При сравнении строк используется понятие лексикографического (алфавитного) порядка. Результат выполнения операций отношения над строками имеет логический тип; 52
выбор подстроки с помощью позиционного индекса. Это операция выделяет подстроку (непрерывную последовательность символов) по позиции ее первого символа в исходной строке и указанной длине подстроки; выбор подстроки на основе сопоставления с образом. Операция поиска в строке подстроки, соответствующей заданному образцу (символу или последовательности символов); форматирование ввода–вывода. Использование строк для облегчения форматирования данных при выводе или вводе. В языке Pascal реализованы многие из этих операций.
3.2.1. Стандартные процедуры работы со строками Delete(St, Poz, N) – удаление N символов строки St, начиная с по-
зиции Poz. Insert(St1, St2, Poz) – вставка строки St1 в строку St2, начиная с
позиции Poz. Str(Number, St) – преобразование числового значения Number в
строку St. Val(St, Number, Cod) – преобразование значения строки St в значение переменной Number целого или вещественного типа. Cod – код завершения преобразования: 0 – успешное преобразование, другое значение – ошибка.
3.2.2. Стандартные функции работы со строками Copy(St, Poz, N) возвращает подстроку из строки St, начиная с символа в позиции Poz и длиной N символов. Length(St) возвращает длину строки St. Pos(St1, St2) поиск первого появления подстроки St1 в строке St2. Результат – позиция символа, начиная с которого, подстрока St1 расположена в строке St2; в противном случае – 0. Concat(S1 ,S2, ..., Sn) объединяет несколько строк S1 ,S2, ..., Sn в одну строку.
53
Пример использования строковых процедур и функций приведен на рисунке 3.2.
Рисунок 3.2 – Пример использования строковых процедур и функций
3.3. Записи Запись – это структурированный тип данных, состоящий из фиксированного числа компонентов разного типа. Выбор компонентов является основной операцией над записями. Эта операция подобна выбору элементов из массива, но с одним существенным отличием: индекс здесь всегда является именем компонента и никогда не может быть вычисляемым значением. Синтаксически операция выбора компонента записи представляет собой имя записи, за которым следует имя компонента. Компоненты записи называют полями, и соответственно имена компонентов являются именами полей. Формат описания в программе: record <имя поля>: <тип поля>; ...
54
<имя поля>: <тип поля> end;
Пример: type Student = record name : string[20]; gruppa : string[5]; number: integer; end; var s: Student; begin s.name := 'Иванов И.И.'; s.number:= 5; writeln (s.name, s.number); end.
Никаких ограничений на тип компонентов не накладывается, поэтому компонентом записи может быть, в свою очередь, тоже запись. Операция присваивания одной записи некоторой другой допустима, если записи имеют одну и ту же структуру. Обращение к полям записи может иметь громоздкий вид. Для того, чтобы при выборе поля записи указывать только имя поля (не указывая имя записи) необходимо поместить обращение к полю записи в области действия оператора with (оператора присоединения), связанного с этой записью. Формат оператора with: with <имя записи> do <оператор>;
Пример (переменная s: Student): with s do begin name := 'Иванов И.И.'; number:= 5;
55
writeln (name, number); end.
3.4. Лабораторные задания 3.4.1. Одномерные массивы Напишите программу, которая осуществляет обработку информации по одному из условий, заданных ниже. 1. Для массива А, состоящего из N элементов: a) построить гистограмму значений массива: каждый элемент массива отображается на одной строке и содержит количество '∗', равное значению элемента; b) найти индекс первого положительного числа, оканчивающегося на 0. Если такого элемента нет, то выдать соответствующее сообщение; c) найти среднее арифметическое значение элементов массива, расположенных между наибольшим и наименьшим элементами массива, включая наименьшее и наибольшее значения; d) найти количество элементов массива, начиная со второго, значение которых больше суммы индексов элементов, стоящих перед ними; e) назовем элемент Аi (i = 2, … , N-1) особым, если слева от него расположены элементы, меньшие его, а справа – большие. Найти количество таких элементов; f) присвоить переменной F значение true, если элементы массива составляют строго возрастающую арифметическую прогрессию, и false в противном случае; g) сколько значений элементов встречаются в массиве более одного раза? Какие это значения? h) сформировать массив В из таких элементов массива А, которые превышают среднее значение массива А; i) записать в массив В положительные элементы массива А, отрицательные элементы – в массив С;
56
2. Вычислить значения функции zi =
( xi + a i ) / 2
для всех таких
значений xi и ai (i = 1, 2, …, N), что подкоренное выражение больше нуля. 3. Решить уравнение ai ⋅ xi = bi для заданных пар значений ai и bi (i = 1, 2, …, N). 4. Даны два массива X(N) и Y(M). Сформировать массив Z(N+M) из положительных элементов массивов X и Y. Если положительных элементов меньше N+M, то оставшимся элементам массива Z присвоить значение +1. 5. Даны массивы А, В, состоящие из N элементов каждый. Присвоить переменной F значение true, если все элементы массива А встречаются в массиве В, и false в противном случае.
3.4.2. Двумерные массивы Напишите программу, которая осуществляет обработку информации по одному из условий, заданных ниже. 1. Задана целочисленная квадратная матрица A размерностью N: a) поменять местами элементы матрицы, расположенные на одной строке и принадлежащие главной и побочной диагоналям; b) найти минимальный элемент, расположенный на главной диагонали матрицы A, а из элементов строки и столбца, на пересечении которых он находится, сформировать одномерный массив B; c) среди элементов, расположенных ниже главной диагонали матрицы A, найти те элементы, которые удовлетворяют условию K1 ≤ Ai,j ≤ K2 (K1, K2 – произвольные числа), и сформировать из них одномерный массив B; d) найти номер строки матрицы A, наиболее удаленной от первой строки, если расстояние S между строками L и K матрицы определяется по формуле: S ( L, K ) =
∑ abs( A
L, j
j
57
∗ AK , j ) ;
e) найти «седловую» точку матрицы – такой элемент Ai,j, который является наибольшим в строке i и наименьшим в столбце j. Если такого элемента нет, то выдать соответствующее сообщение; f) сформировать одномерный массив B, элементы которого Bi равны true, если элементы i-й строки матрицы A упорядочены по возрастанию, и false – в противном случае; g) сформировать одномерный массив B, элементы которого Bj равны 1, если хотя бы один элемент j-го столбца матрицы A больше суммы элементов этого столбца, и 0 – в противном случае. 2. Из массивов X(N) и Y(M) построить квадратную матрицу A размерностью K (K = N + M ) таким образом, чтобы элементы массива X были расположены на главной диагонали и выше ее. 3. Задана целочисленная матрица A размерностью N×M и массив X(N). Обнулить строки матрицы с номером K, для которого X[K] ≥ 0. 4. Задана целочисленная матрица A размерностью N×M. Соседями элемента Ai,j матрицы A будем считать элементы AK,L, для которых i-1≤ K ≤i+1 и j-1≤ L ≤j+1; (K, L) ≠ (i, j). Сформировать матрицу B путем «сглаживания» матрицы A – заменой каждого элемента A средним арифметическим его соседей. 5. Заданы целочисленные матрицы A, B размерностью N×M. Поменять местами столбец матрицы A, где расположен минимальный элемент, со столбцом матрицы B, где расположен максимальный элемент. 6. Заданы целочисленные квадратные матрицы A, B размерностью N. Вывести на экран значения той матрицы, которая содержит больше строк, с положительной суммой элементов. 7. Заданы целочисленные квадратные матрицы A, B размерностью N. Поменять местами строку матрицы A, которая содержит только положительные элементы и имеет минимальный номер в матрице A, со столбцом матрицы B, номер которого совпадает с номером найденной строки матрицы A. Если строка в матрице A не найдена, то выдать соответствующее сообщение.
58
3.4.3. Строки Напишите программу, которая осуществляет обработку информации по одному из условий, заданных ниже. Разделителем слов предложения считать пробел ( '9' ). 1. Строка содержит произвольные символы X1, X2, X3, X4, X5, X6. Изменить исходный состав символов и их порядок с помощью минимального числа вызовов строковых процедур и функций: a) b) c) d) e)
X6, X5, X1, X2, X3, X4, X2, X5, X6, X2, X4, X6, X2, X3, X5, X6, X4, X5, X6, X3, X4, X1, X2.
2. Ввести с клавиатуры фамилию, имя и отчество. Программа должна преобразовать введенные данные и вывести их в виде инициалов и фамилии. Например, при вводе Тургенев Иван Сергеевич программа должна вывести И.С. Тургенев. 3. В предложении заменить одинаковые, стоящие подряд символы одним символом, после которого в скобках указать количество символов, которые были заменены. 4. Найти в предложении слова длиной не более 6 символов, в которых количество гласных букв составляет не менее 30%. 5. Найти в предложении все слова, которые являются палиндромами. 6. Заменить в предложении окончания слов «ing» на окончания «ed». 7. Найти в предложении все слова, в которых встречаются первые три буквы первого слова предложения. 8. В предложении S найти все слова, которые содержат строку S1 (длина строки – 2 символа) или строку S2 (длина строки – 3 символа). 9. В предложении S1 найти самое длинное слово, которое отсутствует в предложении S2. 10. В предложении S1 найти все слова, которые есть в предложении S2.
59
11. Пример оператора вывода в языке С/С++: cout<<"Сумма=9"<<summa<<"\n",
где cout
– оператор вывода, – разделитель,
<<
"Сумма=9" – строка, summa
– переменная,
"\n"
– символ перехода на новую строку.
Сформировать строки (строку), которые содержат операторы вывода языка Pascal, эквивалентные заданному оператору вывода языка С/С++. Для данного примера это будут строки: write('Сумма=9', summa); writeln;
3.4.4. Записи Для заданной преподавателем структуры записи (рисунок 3.3) реализовать ее описание в программе и выполнить операции ввода– вывода значений полей записи. 1.
Запись
Integer
Real
String[3]
Real
[1..Char..2] 2.
Запись
Real
Boolean
Integer 60
[1..Real..2]
Char
Рисунок 3.3 – Структуры записи. Начало
3.
Запись Real
Integer
Boolean
[1 ..
Real
.. 2]
4.
Запись
Char
Real
[ 1 ..
Boolean
Integer
5.
Запись
Integer
Boolean
Char
Real 61
.. 2 ]
[ 1 ..
.. 2 ]
Рисунок 3.3 – Структуры записи. Продолжение
6.
Запись
Real
Char
Boolean
Char
[1..Integer..2] 7.
Запись
Char
Integer
String[3]
Real
[1..Boolean..2] 8.
Запись Char
Real [ 1 ..
Integer
62
Real .. 2 ]
Рисунок 3.3 – Структуры записи. Продолжение
9.
Запись
Real
Integer [ 1 ..
String[2]
Boolean
10.
Запись
Boolean
Integer [ 1 ..
String[3]
Real
.. 2 ]
Рисунок 3.3 – Структуры записи. Окончание
63
.. 2 ]
4. Структура программы Очевидно, что сложные программы составляются из концептуальных блоков, значительно более крупных, чем отдельные операторы языка программирования. Такими блоками являются подпрограммы и модули. Декомпозиция (разбиение) программы на небольшие логически завершенные блоки – это один из основных путей написания программы в ясной и понятной форме.
4.1. Подпрограммы Подпрограмма – это логически завершенный компонент программы. Подпрограмма представляет собой некоторую функцию обработки информации, которая отображает конкретный набор аргументов в некоторый набор результатов. Определение подпрограммы состоит из двух частей: спецификации и реализации. Спецификация (прототип) подпрограммы включает: тип подпрограммы: function (функция), procedure (процедура). function – подпрограмма явно возвращает только один результирующий объект данных; procedure – подпрограмма возвращает более одного значения или действия подпрограммы сводятся только к модификации ее аргументов вместо возвращения результата; имя подпрограммы; формальные параметры: аргументы (порядок следования, тип каждого аргумента) и результаты (порядок следования, тип каждого результата). Реализация подпрограммы (тело подпрограммы) включает: описание локальных данных, используемых подпрограммой; операторы, задающие действия, которые должна выполнить подпрограмма. Локальные данные и операторы инкапсулированы (спрятаны), так что ни локальные данные, ни операторы по отдельности не доступны пользователю подпрограммы. Пользователь может только вызвать
64
подпрограмму. В тело подпрограмм могут входить определения других (вложенных) подпрограмм. Вызывающая программа – программа (подпрограмма), которая обращается к подпрограмме (вызывает подпрограмму). Оператор вызова – оператор вызывающей программы, с помощью которого она обращается к подпрограмме. Оператор вызова подпрограммы содержит: имя подпрограммы; список фактических параметров. Фактические параметры – это элементы вызывающей программы (константы, переменные, массивы и др.), значения которых передаются в подпрограмму или возвращаются из нее. При вызове подпрограммы значения фактических параметров присваиваются соответствующим формальным параметрам (типы фактических и формальных параметров должны совпадать!). Вызываемая программа – подпрограмма, к которой обращается вызывающая программа. Вызываемая программа возвращает управление вызывающей программе, которая продолжает свое выполнение с оператора, следующего за оператором вызова. Схема передачи управления между вызывающей и вызываемой программами приведена на рисунке 4.1.
65
Рисунок 4.1 – Схема передачи управления между вызывающей и вызываемой программами
Обмен информацией между вызывающей и вызываемой программами может осуществляться с использованием глобальных данных или передачей параметров.
4.1.1. Глобальные данные Глобальные данные – это данные (константы, переменные, массивы и др.), объявленные в начале программы и доступные в подпрограммах и «главной программе» (основном блоке программы). Глобальные данные следует использовать только для передачи информации от одной программы (подпрограммы) к другой. Например, одна подпрограмма формирует значения данных, а другая подпрограмма использует эти значения (рисунок 4.2).
66
Рисунок 4.2 – Структура программы
4.1.2. Способы передачи параметров Когда вызывающая программа обращается к подпрограмме, требуется связать фактические параметры вызывающей программы с формальными параметрами подпрограммы. Чаще всего применяются два подхода: либо фактический параметр вычисляется, и полученное значение передается формальному параметру (передача значением); либо формальному параметру становится доступен адрес значения фактического параметра (передача по адресу). Передача значением Схема обмена информацией с использованием передачи параметра значением приведена на рисунке 4.3.
67
Рисунок 4.3 – Передача параметра значением
В этом случае формальный параметр a обрабатывается в подпрограмме как локальная переменная, инициализируемая в начале выполнения подпрограммы значением соответствующего фактического параметра x. В операторе вызова фактическим параметром может быть: константа; переменная; выражение; функция. Значение фактического параметра при изменении соответствующего ему формального параметра не изменяется. В приведенном примере (см. рисунок 4.3) после вызова подпрограммы P значение фактического параметра x остается равным 0 Передача по адресу Схема обмена информацией с использованием передачи параметра по адресу приведена на рисунке 4.4. В этом случае формальный параметр a (описание параметра начинается со слова var) обрабатывается в подпрограмме как переменная, адрес которой есть адрес соответствующего фактического параметра x. В операторе вызова фактическим параметром может быть только переменная. Любое изменение формального параметра a есть изменение соответствующего ему фактического параметра x. После вызова подпрограммы P (рисунок 4.4) значение x равно 1.
4.1.3. Функции Формат спецификации функции: function <имя>(<список формальных параметров>): <тип результата>;
Для возвращения результата функция должна содержать хотя бы один оператор присваивания следующего вида: <имя подпрограммы> := <результат>;
68
где результат – это вычисленное значение в подпрограмме (константа, переменная, элемент массива и другие элементы данных).
Рисунок 4.4 – Передача параметра по адресу
Вызов функции включается в оператор языка Pascal. Пример вызова функции P(x): y:= P(x); {вызов P(x) в операторе присваивания} if P(x)>0 then {вызов P(x) в операторах if и writeln } writeln(P(x));
В качестве примера рассмотрим описание и использование функции power, которая возводит переменную base в степень exponent – baseexponent. function power( base, exponent: real): real; begin power:= exp( exponent ∗ ln(base)); {exp, ln – встроенные функции Pascal:
69
exp (x) – ex , ln (x) – натуральный логарифм x } end;
Вызов функции power может быть, например, таким: writeln (power(3, 5));
4.1.4. Процедуры Формат спецификации процедуры: procedure <имя>(<список формальных параметров>);
Входные параметры (аргументы) процедуры передаются значением или по адресу, а выходные параметры (результаты) – по адресу. Вызов процедуры – это отдельный оператор, который содержит имя процедуры и список фактических параметров. Например: P(x); {это вызов процедуры P(x) }
В качестве примера использования процедуры рассмотрим описание и использование той же самой подпрограммы power. В этом случае, наряду с аргументами base и exponent, которые передаются по значению, необходимо добавить в спецификацию процедуры выходной параметр (результат), который должен быть передан по ссылке (в примере это pow). procedure power( base, exponent: real; var pow: real); begin pow:= exp( exponent ∗ ln(base)); end;
Пример вызова процедуры power: power(3, 4, j); writeln(j);
4.1.5. Передача массивов в качестве параметров В качестве примера будем использовать подпрограмму вычисления суммы значений элементов одномерного массива.
70
4.1.5.1. Формальные параметры как массивы с фиксированными размерами
В данном примере для описания типов параметров используется заранее определенный тип massiv с фиксированной размерностью. uses crt; const N=3; type massiv = array[1..N] of integer; function sum_1( x: massiv ): integer; var i : integer; sum: integer; begin sum:= 0; for i:= 1 to N do sum:= sum+x[i]; sum_1:= sum; end; var {main – главная программа } i:integer; a:massiv; begin clrscr; writeln('massiv a'); for i:=1 to N do readln(a[i]); writeln('summa= ', sum_1(a)); end.
71
4.1.5.2. Формальные параметры как массивы со «свободными» размерами
Существует несколько возможностей передавать массивы в подпрограмму, не указывая их размеры. В языке Pascal для этого можно использовать функции low, high и sizeof. Использование функций low, high и sizeof требует подключения модуля crt. Функции low и high возвращают соответственно наименьшее и наибольшее значение индекса массива. Использование функции high для определения размера массива в подпрограмме приведено на рисунке 4.5.
72
Рисунок 4.5 – Использование функции high
Для лучшего понимания и правильного использования этих функций раскомментируйте отладочные операторы (debug) программы (см. рисунок 4.5), а также познакомьтесь с содержанием Помощи (меню Help) для этих функций. Использование функции sizeof для определения размера массива в подпрограмме приведено на рисунке 4.6. Функция sizeof возвращает размер объекта данных в байтах.
73
Рисунок 4.6 – Использование функции sizeof
Обратите внимание, что в данных примерах описание размеров фактического массива a начинается с 0.
4.1.6. Передача подпрограммы как параметра Если необходимо передать в качестве фактического параметра имя подпрограммы, то соответствующий ему формальный параметр должен иметь процедурный тип, соответствующий прототипу подпрограммы. В качестве примера рассмотрим программу, которая строит таблицу сумм и произведений целых чисел. Для построения таблицы используется процедура PrintTable, которая для вычисления значения таблицы вызывает функцию add (вычисление суммы) или функцию Multiply (вычисление произведения). Имя вызываемой функции процедура получает как параметр Operation. В программе описание процедурного типа имеет вид type Func = function (x,y;integer):integer;
Спецификация подпрограммы, имя которой используется в качестве параметра, должна содержать ключевое слово far («дальний вызов»). Это указание необходимо компилятору для правильной генерации исполняемой программы. Пример передачи подпрограммы как параметра приведен на рисунке 4.7.
74
Рисунок 4.7 – Пример передачи подпрограммы как параметра
4.1.7. Рекурсивные подпрограммы Слово рекурсия происходит от латинского слова «recursio» – возвращение.
75
В программировании рекурсия означает, что подпрограмма обращается сама к себе непосредственно или через цепочку вызовов других подпрограмм. Известными рекурсивными подпрограммами являются вычисление факториала (рисунок 4.8), решение задачи о Ханойских башнях, быстрая сортировка К. Хоара, подпрограммы работы с динамическими структурами данных, подпрограммы построения фракталов и многие другие.
Рисунок 4.8 – Рекурсивная подпрограмма вычисления 3!
Главные требования к организации рекурсивной подпрограммы следующие: рекурсивная подпрограмма имеет хотя бы один параметр; рекурсивная подпрограмма всегда содержит условие завершения рекурсии и, если это условие не выполняется, подпрограмма вызывает сама себя с изменением значения параметра.
76
4.2. Лабораторные задания. Подпрограммы 4.2.1. Оформление алгоритма обработки информации в виде подпрограммы Оформить по заданию преподавателя одну из ранее разработанных программ разд. 3.4 как подпрограмму. Операции ввода данных и вывода результатов должны выполняться в главной программе. Для передачи информации между главной программой и подпрограммой использовать параметры.
4.2.2. Разработка рекурсивных подпрограмм Напишите программу, которая осуществляет рекурсивную обработку информации по одному из условий, заданных ниже: 10
1. y =
∑ (2 + i) . i
2. y =
3+ 6+ 9+
...
1
3. y =
.
1
1+
96 + 99 .
1
3+
1
5+ 7+
1
1 11 4. Определить наибольший общий делитель по алгоритму Евклида для двух чисел А и В (А≥0, В≥0, В>А). 5. Реализовать двоичный поиск заданного значения х в упорядоченном массиве А. 6. Реализовать решение нелинейного уравнения методом «половинного деления». 7. Упорядочить массив по возрастанию методом прямого выбора: 9+
77
просматривая массив с первого элемента, найти минимальный элемент и поставить его на место первого, а первый – на место минимального; просматривая массив со второго элемента, найти минимальный элемент и поставить его на место второго, а второй – на место минимального; и так до предпоследнего элемента. 8. Разделить прямоугольник на прямоугольники меньших размеров (минимальная длина стороны задана). Использовать рекурсивную процедуру деления прямоугольника на два прямоугольника меньших размеров. 9. Нарисовать треугольник Серпинского. Рисуется треугольник и его средние линии. В образованных при углах треугольника новых треугольниках нарисовать средние линии и т. д. Завершением рекурсии может служить порядок вложенности или минимальная длина стороны треугольника. 10. Нарисовать шестиконечную снежинку. Рисуется правильный шестиугольник и его диагонали. Для каждого угла шестиугольника вызывается рекурсивная процедура рисования шестиугольника и его диагоналей и т. д. Порядок вложенности равен 4.
4.2.3. Разработка программы сложной структуры Разработать программу следующей структуры (рисунок 4.9). Назначение компонент: главная программа осуществляет вызов подпрограмм обработки данных с использованием меню. Например: 1. Создание массива записей. 2. Просмотр массива записей. 3. Выход; процедуры обработки данных: • создание массива записей – ввод исходных данных массива записей, • просмотр массива записей – отображение данных массива записей на дисплее. 78
Главная программа ПРОЦЕДУРЫ ОБРАБОТКИ ДАННЫХ
Создание массива
Просмотр массива
...
ПРОЦЕДУРЫ РАБОТЫ С МАССИВОМ ЗАПИСЕЙ
Таблица Рисунок 4.9 – Структура разрабатываемой программы
Для ввода–вывода данных используется таблица; процедура «Таблица» отражает на экране «пустую» таблицу. Каждый столбец таблицы соответствует полю записи. Количество строк таблицы определяется входным параметром K(K≤20). Таблица отображается с использованием символов псевдографики (например: ├, │, ┼ и др.), которые задаются в операторах вывода программы комбинацией ALT+<код символа>.
4.3. Модули Д. Парнас (David Parnas) определил модуль как программный объект с собственной моделью данных и собственным набором операций. Доступ к данным модуля возможен только через имеющиеся в нем операции.
79
Понятие модуля, как программного компонента, используемого для создания программ и программных систем, тесно связано с такими понятиями разработки программных средств, как абстракция и сокрытие информации. Суть абстракции состоит в выделении существенных свойств с игнорированием второстепенных деталей. По мере декомпозиции программной системы на модули каждый из них становится частью абстракции на соответствующем уровне. «Сокрытием информации (information hiding) называют приемы, благодаря которым одни программы маскируют информацию, получаемую из других программ. Программа может скрывать детали реализации, такие, как алгоритмы и данные, благодаря чему в случае, если их необходимо изменить, другие программы, от них зависящие, не придется переписывать. Программы, скрывающие информацию, взаимодействуют друг с другом через общедоступные интерфейсы. Главное достоинство сокрытия информации заключается в увеличении независимости программ друг от друга» [David Parnas «On the Criteria to Be Used in Decomposing Systems into Modules»]. Достоинством информационной закрытости является возможность осуществить: a) независимую разработку программных средств несколькими программистами; b) легкую модификацию программной системы, так как можно производить изменения одного модуля независимо от других. Главные части модуля – интерфейс и реализация (рисунок 4.10). Каждый модуль компилируется независимо от других компонент программы. Имя файла с исходным текстом модуля и название модуля должны совпадать. Для того чтобы включить модуль в программу на языке Pascal, необходимо указать имя модуля в предложении uses.
80
Рисунок 4.10 – Структура модуля
Формат подключения модулей: uses <список имен модулей>;
Структура модуля в языке Pascal: unit <имя модуля>; interface {интерфейс модуля} uses {подключение других модулей} const type var procedure function implementation {реализация } uses const type var
81
procedure function begin {инициализация } <операторы> {исполняются один раз перед выполнением } {операторов программы, включающей модуль } end.
Пример использования модуля. Рассмотрим программу, которая включает модуль Math, содержащий функцию power(a,b) возведения числа a в произвольную степень b и функцию log(c) вычисления десятичного логарифма числа c. Исходный текст модуля сохраняем в файле Math.pas: unit Math; interface function power( base, exponent: real): real; function log ( argument : real): real; implementation function power( base, exponent: real): real; begin power:= exp( exponent * ln(base)); end; function log ( argument : real): real; const base=10; begin log:= ln(argument) / ln(base); end; end.
После его успешной компиляции создается файл Math.tpu (расширение tpu – Turbo Pascal Unit). Разместим этот файл в том же каталоге, что и текст программы ex_Math.
82
program ex_Math; uses Math; {подключение модуля Math} var a, b, c: real; begin readln(a, b, c); writeln('A в степени B = ', power(a, b)); writeln('Логарифм C по основанию 10 = ', log(C)); end.
4.4. Лабораторные задания. Модули Оформите процедуры обработки данных задания 4.2.2 в виде модуля.
83
5. Хранение информации 5.1. Файлы. Основные понятия и операции Все рассмотренные ранее структуры данных (массивы, строки, записи) обеспечивают хранение информации в оперативной памяти, т. е. только на время работы программы. А как сохранить информацию после завершения работы программы? Для этого используют структуру данных, которую называют файл. Файл – это структура данных, обладающая двумя основными свойствами: обычно она располагается на каком-либо внешнем носителе (например, магнитная лента, магнитный или оптический диск), и, следовательно, ее размер может быть значительно больше, чем размеры других типов структур данных; ее время жизни может значительно превышать время выполнения программы, создавшей ее. Файловая переменная – переменная в программе, которая используется для описания структуры файла и логических операций с файлом (операций на уровне программы). Формат описания файловой переменной: <имя файловой переменной> : file of T; {Т – тип компонентов файла}
Перед выполнением любой операции над файлом файловая переменная должна быть предварительно инициализирована – сопоставлена с физическим файлом: аssign (<имя файловой переменной>, <путь к файлу и его имя>);
Наиболее распространенными являются файлы с последовательным доступом к их компонентам. Последовательный доступ к компонентам файла Доступ к компонентам файла осуществляется либо в режиме записи, либо в режиме чтения.
84
В режиме записи указатель текущей позиции в файле всегда расположен после последнего компонента файла, и единственно возможной операцией в этом режиме является запись очередного компонента файла, в результате чего файл «расширяется». В режиме чтения указатель текущей позиции может располагаться в любом месте файла, и единственно возможной операцией в этом режиме является доступ к компоненту, следующему непосредственно за указателем, т. е. считывание этого компонента. Основные операции над файлами с последовательным доступом к их компонентам таковы. Открытие файла. Операция открытия получает в качестве параметров имя файла и режим доступа (чтение или запись). В режиме чтения предполагается, что файл существует. Операция открытия запрашивает у операционной системы информацию о расположении и свойствах файла, отводит требуемый объем памяти для буфера обмена и устанавливает указатель текущей позиции перед первым компонентом файла. В режиме записи операционная система получает указание создать новый пустой файл или, если файл с таким именем уже существует, уничтожить всю содержащуюся в нем информацию так, чтобы он стал пустым. Указатель текущей позиции устанавливается в начало этого пустого файла. Чтение. Операция чтения передает содержимое текущего компонента (определяемого указателем текущей позиции файла) в переменную программы. Запись. Операция записи создает новый компонент в текущей позиции файла и передает значение программной переменной этому новому компоненту. Проверка конца файла (Eof – End of file). Операция чтения не может быть выполнена, если указатель текущей позиции достиг конца файла. Так как длина файла не фиксирована, требуется проводить явную проверку на достижение конца файла. Закрытие файла. Когда обработка файла завершена, его необходимо закрыть. Обычно эта операция приводит к передаче сообщения операционной системе о том, что файл следует отсоединить от про-
85
граммы и освободить область памяти, которая использовалась при работе с файлом (буфер обмена). При изменении режима доступа к файлу (от записи к чтению и наоборот) его следует закрыть и открыть в требуемом режиме. Схема формирования файла var F: file of T; a: T; begin Assign(F, <путь к файлу и его имя>); Rewrite(F); { Открытие файла для записи – создание пустого файла } <цикл формирования файла> begin <получить значение а>; write(F, a); { записать а в конец файла } end; Close(F); { закрыть файл } end.
Схема просмотра (использования файла) var F: file of T; a: T; begin Assign(F, <путь к файлу и его имя>); Reset(F); { Открытие файла для чтения, файл уже существует } while not Eof(F) do begin { пока не конец файла выполнять} read(F, a); { прочитать данные из файла в переменную а } <использовать а >; end; Close(F); { закрыть файл } end.
86
5.2. Типизированные файлы Если все операции ввода–вывода с файлом используют данные некоторого определенного типа T, то такой файл называют типизированным. Такому файлу соответствует тип файловой переменной – file of T.
Часто компонентами типизированного файла являются записи. Пример описания типизированного файла: type Student = record name : string[20]; gruppa : string[5]; number: integer; end; var F: file of Student;
Стандартные процедуры и функции работы с типизированными файлами Assign(F, Str) – процедура определения файловой переменной. F – файловая переменная, Str – строка, содержащая путь к файлу и его имя. Rewrite(F) – процедура открытия файла для записи (создание нового файла). Reset(F) – процедура открытия существующего файла для чтения. Read(F, P) – процедура чтения данных из файла. P – переменная того же типа, что и компоненты файла. Write(F, P) – процедура записи данных в файл. Seek(F, n) – процедура устанавливает указатель текущей позиции файла на компонент с порядковым номером n (n = 0, 1, 2, …). Обеспечивает прямой доступ к данным. Close(F) – процедура закрытия файла. Truncate(F) – процедура уничтожает все компоненты файла, начиная с текущего, и подготавливает файл для записи.
87
Eof(F) – функция проверки маркера конца файла. Функция возвращает True, если указатель текущей позиции файла находится сразу за последней его компонентой, и False – в противном случае. FilePos(F) – функция возвращает номер текущего компонента файла. FileSize(F) – функция возвращает длину файла – количество компонент в файле. IOResult(F) – функция возвращает код ошибки последней операции ввода–вывода. Если IOResult(F) = 0, операция ввода–вывода успешно завершилась – ошибки нет. Для использования данной функции в программе необходимо отключить системную обработку ошибок ввода–вывода {$I-} перед выполнением операции с файлом, а потом вернуть обработку ошибок системе – {$I+}. Пример: var F: file of byte; begin Assign(F, 'MyFile'); {$I-} Reset(F); {$I+} If IOResult = 0 then Writeln('Размер файла в байтах: ', FileSize(F)) else Writeln('Файл не найден'); end.
5.3. Текстовые файлы Текстовый файл – это файл, компонентами которого являются символы. Текстовые файлы – это одна из форм последовательных файлов. Поэтому с ними можно производить те же действия, что и с последовательными файлами.
88
Особенностью является наличие специальной процедуры (Append) открытия существующего файла для записи в него новых компонент. Формат описания файловых переменных текстового файла: <имя файловой переменной> : text;
Процедуры и функции работы с текстовыми файлами Assign(F, Str) – процедура определения файловой переменной. F – файловая переменная, Str – строка, содержащая путь к файлу и его имя. Rewrite(F) – процедура создания нового файла. Файл открывается для записи. Указатель текущей позиции в файле устанавливается на начало файла. Append(F) – процедура открытия существующего файла для добавления (записи) данных. Указатель текущей позиции в файле устанавливается на его конец. Reset(F) – процедура открытия существующего файла для чтения. Указатель текущей позиции в файле устанавливается на начало файла. Close(F) – процедура закрытия файла. Read(F, Ch) – процедура считывания символа из файла. Ch – переменная типа char. Write(F, Ch) – процедура записывает символ в файл. Readln(F, Str) – процедура считывает строку из файла. Str – переменная типа string. Writeln(F, Str) – процедура записывает строку в файл. Eoln(F) – функция возвращает True, если указатель текущей позиции в файле достиг маркера конца строки. SeekEof(F) – функция возвращает True, если указатель текущей позиции в файле достиг маркера конца файла.
89
5.4. Лабораторные задания. Процедуры работы с файлами В разработанную ранее согласно заданию 4.2.2 программу добавьте процедуры работы с файлами (рисунок 5.1).
Рисунок 5.1 – Структура программы для задания 5.1
Процедура «Создание файла» использует заранее определенное количество записей файла. Исходные данные компонентов файла вводятся с клавиатуры (так же, как и при работе с массивами записей, используется процедура Таблица). Процедура «Просмотр файла» автоматически определяет количество записей файла и отображает в таблице значения данных компонентов файла.
90
6. Динамические структуры данных. Указатели 6.1. Основные понятия и определения При разработке программ часто возникает проблема, связанная с тем, что объем обрабатываемой в программе информации (соответственно и размер памяти, необходимой для хранения этой информации) неизвестен или может быть определен только в процессе работы программы. Например, количество компонент файла можно определить только после того, как он будет открыт (после выполнения в программе оператора Reset). Использовать такую удобную для обработки информации структуру данных, как массив, нельзя, если неизвестно количество его элементов. Все объявления в разделе описания переменных (раздел var) требуют точного значения размерности (например, array[1..10]), так как на основе этой информации компилятор "распределяет" память для используемых в программе данных. Статическое распределение памяти – это распределение памяти в процессе компиляции программы, т. е. до начала ее выполнения. Динамическое распределение памяти – это распределение памяти в процессе работы программы. Для получения памяти в этом случае в программе необходимо выполнить запрос к операционной системе (ОС). По этому запросу ОС выделяет память в динамической области оперативной памяти компьютера – "куче" (heap) и возвращает программе начальный адрес выделенного участка оперативной памяти. Доступ к данным, значения которых расположены в выделенной динамической области памяти, требует использования в программе переменной, значением которой и будет возвращаемый ОС адрес. Такая переменная имеет специальный, ссылочный тип данных – указатель.
91
Формат: type <имя типа> = pointer; <имя типа> = ^<идентификатор типа>;
Например: type T = pointer; {указатель не связан с определенным типом данных} T1 = ^integer; {указатель связан с данными целого типа} var { переменные типа указатель} ptr1: T; ptr2: T1;
Для правильной работы с указателями очень важно четко различать два понятия значение указателя и значение по указателю: • значение самого указателя – адрес динамической памяти. В приведенном выше примере это значение переменных ptr1, ptr2; • значение по указателю – значение данных, адрес которых является значением указателя на эти данные. В программе оно обозначается: <имя переменной типа указатель>^ Для указателей ptr1, ptr2 значения по указателю будут обозначаться так: ptr1^, ptr2^ . Чтобы "почувствовать разницу" между значением указателя и значением данных, адресуемых этим указателем, рассмотрим следующую схему (рисунок 6.1). На рисунке 6.1: после выполнения операции ptrY:= ptrX изменяется значение указателя ptrY и доступ к данным по предыдущему значению этого указателя потерян (данные превращаются в "мусор")!
92
после выполнения операции ptrY^:= ptrX^ изменяется значение данных по указателю ptrY. Значение указателя ptrY не изменяется!
Рисунок 6.1 – Значение указателя и значение по указателю
В конце работы программы необходимо освободить выделенную память, т. е. сообщить ОС, что динамическая область памяти, выделенная программе, может использоваться для других программ или в целях самой ОС.
6.2. Процедуры работы с динамическими структурами данных 6.2.1. Процедуры New и Dispose
В этих процедурах размер запрашиваемой и освобождаемой памяти явно не указывается в процедуре и определяется типом данных.
93
Поэтому описание указателя должно быть только такого вида: ^<имя типа данных>. New(P) – выделить память, размер которой определяется типом данных указателя P. После успешного завершения операции New значением переменной P становится начальный адрес выделенной области памяти. Выделяемая процедурой New память не инициализируется какимлибо значением. Dispose(P) – освободить память, начальный адрес которой определяется значением указателя P. Размер освобождаемой памяти определяется типом данных указателя P. Пример 1. Программа сохраняет информацию, отображаемую на дисплее в текстовом режиме (размер экрана: 80 символов в строке × 25 строк; размер памяти для сохранения одного символа: 2байта – всего 4000 байт). type ekr =array[1..4000] of byte; {изображение – это массив из 4000 байт } var Ekran : ekr absolute $B800:$0000; { Значение переменная Ekran (4000 байт) размещается } { в памяти, начиная с адреса $B800:$0000 – } { адреса видеопамяти текстового режима } SaveEkran: ^ekr; {указатель на данные типа ekr} begin new(SaveEkran); { получить память для размещения } { 4000 байт –здесь будет сохраняться изображение экрана } SaveEkran^ := Ekran; { сохранение состояния экрана – } { запоминание 4000 байт видеопамяти} … < операторы изменения состояния экрана> … Ekran := SaveEkran ^; { восстановление изображения на экране }
94
Dispose(SaveEkran); { освобождение выделенной памяти end.
}
6.2.2. Процедуры GetMem и FreeMem В этих процедурах размер запрашиваемой и освобождаемой памяти явно указывается в процедуре. Для определения необходимого размера выделяемой памяти для информации различного типа рекомендуется использовать функцию Sizeof(). GetMem(P, Size) – выделить память размером Size (единовременно не более 65528 байт) и поместить значение начального адреса выделенной области памяти в указатель P. FreeMem(P, Size) – освободить выделенную память размером Size, начальный адрес которой определяется значением указателя P. Пример 2. "Летящее красное ядро": uses Graph, crt; var grDriver, grMode, errCode, i : integer;{ переменные для графики } Р:pointer; { указатель "на ядро" } size :word; { размер "области ядра" } begin {инициализация графического режима} grDriver:= Ditect; InitGraph(grDriver, grMode, ''); errCode:= GraphResult; if errCode= grOk then begin {работа в графическом режиме} size:= ImageSize(9, 20 ,30, 40);{ определяем размер памяти для "ядра" } if MaxAvail > size then begin {проверяем есть ли свободная память } GetMem(P, size); { выделяем память и начинаем рисовать }
95
setcolor(RED); { цвет ядра – красный for i:= 1 to 10 do { ядро – 10 окружностей с координатами circle(20, 30, i); { центра 20, 30 и радиусом, равным i GetImage(9, 20, 30, 40, P^);{запоминаем "ядро" по адресу Р } readln; ClearDevice; { очищаем экран For i:= 1 to 120 begin { ядро "летит" PutImage (10+i, 10, P^, NormalPut);{восстанавливаем изображение ядра на "новом месте" } delay(100); { задержка, чтобы посмотреть end; readln; FreeMem(P, size); { освобождаем память end else writeln('Нет памяти'); CloseGraph; { "закрытие" графического режима end else writeln('Ошибка инициализации графики:', GraphErrMsg(errCode)); end.
} } }
} }
}
}
}
6.3. Применение динамических структур для организации списков Списком называется упорядоченная динамическая структура данных, каждый элемент которой содержит данные и ссылку, связывающую его со следующим элементом (рисунок 6.2).
96
Рисунок 6.2 – Структура списка
Структура элемента списка может быть объявлена в программе, например, следующим образом: type ptrList = ^TList;{ тип указателя связан со структурой элемента списка } TList = record { структура элемента списка: } inf : <тип данных>; { информация (данные) } next: ptrList; { указатель на элемент списка } end;
Рассмотрим типовые схемы создания, просмотра и удаления списка на примере односвязного списка, структура которого приведена выше. Создание списка. var p1, p2, pList: ptrList; { p1 – указатель на новый элемент списка } { p2 – вспомогательный указатель, в начале = NIL} { pList – указатель на начало списка } begin p2 := NIL; { список пуст } <Цикл добавления элементов в список> begin New(p1); { выделяем память для элемента списка } p1^.inf := <данные>; { формируем данные элемента списка } p1^.next := p2; { "связываем" элементы списка } p2 := p1; { сохраняем адрес элемента списка в p2 }
97
end; pList:= p2; { Список создан. pList – адрес начала списка } end.
Схема создания списка (шаг 1 и шаг 2) приведена на рисунке 6.3.
98
ШАГ 1 (добавление первого элемента в список) New (p1);
Выделение памяти: p1 – адрес нового элемента
p1
Формирование данных элемента списка
p1^. Inf := <данные>; p1
p1^.next := p2;
p1
NIL
«Пустой» указатель (NIL) – это адрес конца списка
p2 p2 := p1;
p1
NIL
Сохранение адреса элемента списка в p2
ШАГ 2 (добавление второго элемента в список) p2
NIL
New (p1);
Первый элемент создан на шаге 1 Выделение памяти: p1 – адрес нового элемента
p1
p2
NIL Формирование данных второго элемента списка
p1^. Inf := <данные>; p1
p2
NIL
p1^.next := p2; p1
«Связывание» второго элемента списка с первым элементом
NIL p2 := p1;
Сохранение адреса элемента списка в p2
p2 p1
Рисунок 6.3 – Схема создания списка из двух элементов
99
Просмотр списка var p1, pList: ptrList; {pList – указатель на начало списка } begin p1 := pList; while p1<> NIL do begin <.использование данных элемента списка (p1^.inf) >; p1 := p1^.next; { перемещаем указатель p1 на следующий элемент } end; end.
Удаление списка. var p1, p2, pList: ptrList; { pList – указатель на начало списка } begin p1 := pList; while p1<> NIL do begin p2:=p1; { сохраняем адрес элемента списка в p2 } p1 := p1^.next; { перемещаем указатель p1 на следующий элемент } dispose(p2); { удаляем элемент списка, адрес которого p2 } end; pList:=NIL; { список пуст } end.
6.4. Лабораторные задания. Указатели, список В разработанную ранее согласно заданию 4.2.2 программу добавьте процедуры работы со списком (рисунок 6.4). Процедура «Создание списка» формирует односвязный список из данных компонентов файла. Количество записей файла определяется в процедуре автоматически. 100
Рисунок 6.4 – Структура программы для задания 6.1
Процедура «Просмотр списка» отображает в таблице значения данных элементов списка. Процедура «Удаление списка» освобождает память, занимаемую элементами списка.
101
7. Введение в объектноориентированное программирование. Классы и объекты 7.1. Основные понятия и определения Подход к разработке программных средств, в основе которого лежит объектная декомпозиция программной системы, получил название объектно-ориентированного. Объектная декомпозиция заключается в представлении программной системы в виде совокупности классов и объектов, которые наиболее естественным образом отражают предметную область работы системы. При этом иерархический характер системы отражается в иерархии классов, а ее функционирование рассматривается как взаимодействие объектов этих классов. Объект обладает индивидуальностью и поведением. Индивидуальность объекта, его свойства – это значения атрибутов (данных), которые определяют его состояние. Поведение – это совокупность методов (процедур и функций), определяющих взаимодействие объекта с "внешней" средой и изменяющих его состояние. Таким образом, объект объединяет данные (свойства) и код (поведение) в единое целое. Каждый объект является представителем некоторого класса. Класс – это совокупность однотипных объектов. Класс определяет общие свойства для всех его объектов. Графическое изображение класса в нотации UML (Unified Modeling Language) следующее (рисунок 7.1). Объектно-ориентированной разработке присущи следующие характерные свойства классов и объектов: • инкапсуляция – объединение данных и кода в одно целое. Скрытие информации – имеется возможность запретить любой доступ к данным объекта, кроме как через его методы. Внутренняя структура объекта скрыта от пользователя;
102
• наследование – возможность создавать новые классы по принципу "от общего к частному". Наследование позволяет классампотомкам при сохранении всех свойств классов-родителей добавлять свои собственные свойства, которые отражают их индивидуальность;
Рисунок 7.1 – Графическое представление класса
• полиморфизм – способность объектов выбирать реализацию метода на основе типов данных, принимаемых в сообщении. Объекты разных классов реагируют по-своему на одно и тоже сообщение. Это позволяет разным объектам иерархии классов реализовать своим собственным образом некоторый метод обработки данных (с одним и тем же именем для всех объектов).
7.2. Объектно-ориентированная разработка модуля «Геометрические фигуры» Рассмотрим объектный подход на примере разработки модуля построения на плоскости графического изображения, состоящего из простых геометрических фигур. В основу иерархии классов положим тезис о том, что все геометрические фигуры представляют собой совокупность точек, а каждая точка характеризуется своим местоположением и видимостью. Тогда иерархию классов, необходимую для построения изображения на плоскости, можно представить так (рисунок 7.2). Класс "Местоположение" (Location). Свойства (координаты на плоскости): x – координата x на плоскости, 103
y – координата y на плоскости. Методы: Create – задать местоположение (инициализировать координа-
ты x, y), GetX – получить координату x, GetY – получить координату y.
Рисунок 7.2 – Иерархия объектов для построения изображения
Описание класса "Местоположение " на языке Pascal следующее: type Location = Object {Класс "Местоположение"} x, y: integer; procedure Create(InitX, InitY : integer); function GetX : integer; function GetY : integer; end;
Реализация методов класса "Местоположение" очень проста. Отличие от рассмотренных в предыдущих разделах процедур и функ-
104
ций – это явное указание имени класса в заголовке (еще маленький нюанс – отсутствие описания переменных x, y в методах своего класса): {методы класса Location} procedure Location.Create(InitX, InitY : integer); { инициализация координат x, y } begin x := InitX; y := InitY; end; function Location.GetX : integer; {возвращает координату x} begin GetX := x; end; function Location.GetY : integer; {возвращает координату y} begin GetY := y; end;
Класс "Точка" (Point) наследуется от класса "Местоположение". Таким образом, объект класса "Точка" имеет свойства x, y и методы инициализации местоположения и получения координат. Добавим в класс "Точка" свойство видимости (Visible), а также методы "Показать точку" (Show), "Спрятать точку" (Hide – сделать невидимой), "Переместить точку" (MoveTo) и "Получить состояние точки" (IsVisible – видима точка или не видима?). Описание класса "Точка" на языке Pascal следующее: type Point = Object(Location) {наследование от класса Location } Visible : boolean; {свойство "видимость" } procedure Create(InitX, InitY: integer); procedure Show; {показать } procedure Hide; {спрятать – сделать невидимым }
105
function IsVisible : boolean; {точка видима? procedure MoveTo(NewX, NewY: integer); { переместить { в координаты NewX, NewY end;
} } }
Реализация методов класса "Точка" требует подключения стандартного модуля Graph языка Pascal. {методы класса Point} procedure Point.Create(InitX, InitY: integer); begin Location.Create(InitX, InitY); {вызов метода родителя } { Location.Create для инициализации } { местоположения точки } Visible := False; { состояние: точка не видима } end; procedure Point.Show; { Показать точку } begin Visible := true; { состояние: точка видима } PutPixel(x, y, GetColor); {"рисование" точки цветом символов } end; procedure Point.Hide; {Спрятать точку } begin Visible := false; {состояние: точка не видима } PutPixel(x, y, GetBkColor); {"рисование" точки цветом фона } end; function Point.IsVisible : boolean; {возвращает состояние точки } begin IsVisible := Visible; end; procedure Point.MoveTo(NewX, NewY : integer); {Переместить точку } begin Hide; {Спрятать точку }
106
x := NewX; y := NewY; Show; end;
{Установить новые координаты точки: } { NewX, NewY } {Показать точку }
Для того, чтобы создать и показать точку, достаточно объявить объект класса "Точка" и вызвать соответствующие его методы, например, так: var XPoint: Point; { XPoint – объект класса "Точка" (Point) } begin XPoint.Create(150, 80); { 150, 80 – координаты точки } XPoint.Show; {Показать точку } XPoint.MoveTo(200, 100); {Переместить точку в координаты 200, 100 } XPoint.Hide; {Спрятать точку } end.
В качестве фигуры выберем окружность – геометрическое место точек, равноудаленных от центра. Действительно, трудно придумать другой пример фигуры, в котором бы иерархия классов (фигура >точка -> место) проявлялась так ясно. Класс "Окружность" (Circle) наследуется от класса "Точка". Для работы с окружностью нам необходимо добавить только свойство "Радиус" (Radius). Описание класса "Окружность" следующее: type Circle = Object(Point) {наследование от класса Point Radius : integer; {свойство "Радиус" (Radius) procedure Create(InitX, InitY, InitRadius :integer); { InitX, InitY – это координаты { центра окружности procedure Show; {показать окружность procedure Hide; {спрятать – сделать окружность невидимой} procedure MoveTo(NewX, NewY: integer);
107
} } } } }
{переместить центр окружности { в координаты NewX, NewY
} }
end;
Метод "Показать" в классах "Окружность" и "Точка" называется одинаково – Show, но реализуется в каждом классе по-своему. В классе "Окружность" метод Show рисует окружность, в классе "Точка" – точку (аналогично и для метода "Спрятать" – Hide). Код метода MoveTo для класса "Окружность" (Circle.MoveTo): Hide; x := NewX; y := NewY; Show;
полностью совпадает с кодом метода MoveTo класса "Точка". Зачем же писать одно и то же дважды?! Может быть, лучше в классе "Окружность" наследовать этот метод из класса "Точка"? Будет ли в этом случае вызов объектом класса "Окружность" метода MoveTo (наследуемого из класса "Точка") приводить к перемещению окружности, а не точки? Будет, если мы используем такое свойство объектно-ориентированной разработки, как полиморфизм. В языке Pascal полиморфизм реализуется с помощью виртуальных методов. Для использования полиморфизма необходимо выполнить следующие действия: для инициализации объекта класса использовать специальную процедуру Конструктор (constructor). При вызове конструктора создается Таблица виртуальных методов (VMT), одна для конкретного класса. Эта таблица содержит указатели на код реализации методов данного класса. Когда в программе вызывается виртуальный метод, то осуществляется обращение к Таблице виртуальных методов того класса, объект которого в данный момент является активным. Затем по указателю таблицы находится соответствующий код реализации вызванного метода и ему передается управление; одноименные в разных классах методы (в нашем случае это Show и Hide) описать как виртуальные (virtual).
108
Например: procedure Point.Show; virtual; если объекты создаются динамически, то описать в классе специальную процедуру Деструктор (destructor), которая освобождает, занимаемую объектом динамическую память. Рекомендуется описывать деструктор как виртуальную процедуру. Итак, вместо procedure Create в классах "Точка" и "Окружность" будем использовать Constructor Create. Затем добавим в эти классы описание virtual для методов Show, Hide. И, последнее, исключим метод MoveTo из класса "Окружность" (диаграмма классов на рисунке 7.3).
109
Рисунок 7.3 – Диаграмма классов для построения изображения
После этих изменений при вызове объектом класса "Окружность" метода MoveTo (наследуемого из класса "Точка") будет выбрана реализация виртуальных методов Show и Hide класса "Окружность" – это то, что нам надо; это и есть полиморфизм. Интерфейс и реализация классов Location, Point и Circle объединены в модуль Figures.
110
Для того, чтобы динамически создавать объекты, в модуль Figures добавлены указатели на объекты классов "Точка" (PointPtr = ^Point) и "Окружность" (CirclePtr = ^Circle). Создание объекта в
этом случае может включать вызов конструктора класса. Пример создания объекта "Точка": New (PointPtr, Create(100, 50));
Текст модуля Figures приведен в приложении. Создаваемое изображение на плоскости будем представлять как список, элементы которого содержат указатели на объекты (геометрические фигуры), наследуемые от класса Point. Схему списка можно представить следующим образом (рисунок 7.4).
Рисунок 7.4 – Схема списка геометрических фигур
Описание элемента списка на языке Pascal может выглядеть, например, так: NodePtr = ^Node; {указатель на элемент списка} Node = Record {элемент списка } Item : PointPtr; Next : NodePtr; end;
111
Сам список фигур (графическое изображение) реализуем как объект класса "Список"(List): ListPtr = ^List; List = Object { класс "Список" } Nodes : NodePtr; { указатель на начало списка } constructor Create; { инициализация: пустой список } destructor Destroy; virtual; { удаление списка } procedure Add(Item : PointPtr); { добавление элемента в список } procedure Report; { просмотр списка – это } { "рисование" его элементов } end;
Понятно, что из точки и окружности трудно создать какое-то изображение. Но нет преград для того, чтобы расширить модуль Figures новыми классами (новыми фигурами – "Прямоугольник", "Треугольник" и др.), которые наследуются от класса Point, и построить на экране что-нибудь интересное.
7.3. Лабораторное задание Сконструируйте новый класс, соответствующий геометрической фигуре, заданной преподавателем, и реализуйте следующие методы работы со списком геометрических фигур: создать пустой список – Create, добавить в список – Add, просмотреть список – Report, удалить список – Destroy.
112
8. Объектно-ориентированное программирование на языке Object Pascal 8.1. Классы и объекты 8.1.1. Структура класса Синтаксис описания класса: <имя класса> = class(<имя класса-родителя>) private {закрытый } {Данные и методы, доступные только в данном классе} protected {защищенный} {Данные и методы, доступные только в наследуемых классах} public {открытый} {Данные и методы, доступные всем} published {публикуемый} {Данные и методы, доступные в Инспекторе объектов Delphi } end;
Имя класса в Object Pascal принято начинать с буквы Т, а имя данных (их называют полями) – с буквы F. Базовый класс в Object Pascal – TObject. Этот абстрактный класс, объявленный в модуле System, является родителем всех других классов и содержит только спецификации методов, включая базовый конструктор и деструктор. Если в объявлении класса не указан класс-родитель, то объявляемый класс будет считаться наследником класса TObject: type TMyClass = Class { эквивалентно TMyClass = Class(TObject) } ... end;
113
8.1.2. Создание и уничтожение объектов Главное отличие объектов в Object Pascal заключается в том, что все объекты создаются динамически. Для создания объекта необходимо вызвать конструктор (в Object Pascal он обычно называется Create), который возвращает указатель – адрес созданного объекта. Для уничтожения объекта рекомендуется вызывать метод Free, который проверяет существование объекта (не равен ли он nil), а затем вызывает деструктор (в Object Pascal он обычно называется Destroy). Пример создания и уничтожения объекта: type ТМуClass = class (TObject) private ... public ... constructor Create; // Конструктор destructor Destroy; // Деструктор end; ... // Реализация методов класса var МуObject: ТМуClass; begin МуObject := ТМуClass.Create; { Создание объекта: имя объекта, МуObject – указатель, результат вызова конструктора конструктор по синтаксису процедура, но вызывается как функция конструктор вызывается c именем класса – ТМуClass.Create } ... МуObject.Free; // Уничтожение объекта end.
114
В реализации конструктора необходимо сначала вызвать конструктор класса-родителя – inherited, а затем выполнить необходимые действия. Реализация деструктора должна завершаться вызовом деструктора класса-родителя – inherited.
8.1.3. Пример. Класс – динамический массив Динамический массив – это массив, память для которого выделяется во время работы программы. Синтаксис объявления динамического массива: <имя массива> : аrray of <тип элементов>;
Индекс динамического массива всегда начинается с 0 ! Имя динамического массива – это указатель, который не требует разыменования (символа ^) для доступа к данным. Например, FArray [2]. Оператор присваивания для имен динамических массивов означает присваивание указателей! Выделение памяти для динамического массива осуществляется процедурой SetLength (<имя массива>, <количество элементов>), освобождение памяти – процедурой Finalize (<имя массива>). Пример: Var FArray: array of integer; ... begin SetLength (FArray, 10); {выделяем память для 10 элементов массива} ... {что-то делаем с массивом } {не хватило элементов массива?} SetLength (FArray, Length(FArray) + 10); {добавим еще 10 элементов } ... { делаем с массивом что-то еще } Finalize (FArray); {освобождаем память } End.
115
Использование многомерных динамических массивов позволяет создать "матрицу", которая имеет различное количество элементов в каждой строке. Пример многомерного динамического массива: Var FArray: array of array of integer; begin SetLength (FArray, 10); {память для 10 строк } ... SetLength (FArray[0], 5); { память для 5 элементов первой строки } SetLength (FArray[1], 4); { память для 4 элементов второй строки } SetLength (FArray[2], 6); { память для 6 элементов третьей строки } . . . { Например, FArray[1, 3] – четвертый элемент второй строки } Finalize (FArray);{освобождаем память, выделенную для массива } End.
Рассмотрим создание класса – динамический массив [BYTE, март 2000, Cover Story – языки программирования]. Будем разрабатывать программу, использующую этот класс, как консольное приложение Delphi. Консоль – это монитор и клавиатура, рассматриваемые как единое устройство. Консольное приложение Delphi – это программа на языке Object Pascal, которая выполняется без графического интерфейса в отдельном окне операционной системы Windows. Когда открывается новое консольное приложение в интегрированной среде разработки Delphi, новая форма не создается и для разработки программы используется только редактор кода. Для создания консольного приложения войдите в интегрированную среду разработки программ Delphi и выполните следующее: • выберите меню File, • выполните команду New/Other (Новый/Другие), • в появившемся окне New Items (рисунок 8.1) выберите консольное приложение – Console Application, • нажмите ОК. 116
Рисунок 8.1 – Выбор типа приложения
117
В консольном приложении (текст на языке Object Pascal приведен на рисунках 8.2, 8.3, 8.4) создается класс ТМуАггау для работы с динамическим массивом, который содержит целые значения. Исходные данные, используемые для формирования массива, находятся в файле TestFile.dat. Процедура ReadElementsFromFile формирует массив и выводит на экран нечетные значения массива в порядке, обратном их расположению в файле. Данные класса ТМуАrrау: FArray – массив целых чисел, FPoz – текущее количество (счетчик) элементов массива. Методы класса ТМуАrrау: AddElement – добавляет элемент в конец массива, Create – конструктор, создает массив из delta элементов, Destroy – деструктор, освобождает память, выделенную для элементов массива, GetElement – возвращает значение элемента массива по указанному номеру, GetLastNumber – возвращает номер последнего элемента.
8.1.4. Операции с объектами Для объектов определены следующие операции: = , <>, is, as. Операции = , <> – это операции отношения для объектов одного класса. 8.1.4.1. Оператор is
Оператор is выполняет проверку принадлежности объекта к указанному классу или его наследникам. Выражение <объект> is <класс> возвращает True, если объект является экземпляром данного класса или одного из его наследников, или False в противном случае. Если объект = nil, то результат выражения – False. 118
Рисунок 8.2 – Программа ConsoleExample. Описание класса ТМуАrrау
119
Рисунок 8.3 – Программа ConsoleExample (продолжение). Реализация методов класса ТМуАrrау
120
Рисунок 8.4 – Программа ConsoleExample (продолжение). Процедура ReadElementsFromFile и главная программа
Пример: if Sender is TEdit then TEdit(Sender).Text := 'Пример оператора is';
В этом примере, если объект Sender принадлежит классу TEdit, можно использовать свойство объекта Text. 8.1.4.2. Оператор as
Оператор as выполняет контролируемое преобразование типа объекта к указанному классу. Выражение <объект> as <класс> возвращает тот же самый объект, приведенный к указанному классу. Если преобразование невозможно, то формируется ошибка.
121
Пример: (Sender as TButton).Caption := 'Ok'
8.1.4.3. Копирование объектов одного класса
Если в программе необходимо создать объект, содержание которого является копией другого объекта (оба объекта относятся к одному классу), то необходимо выполнить следующие действия: создать объекты. Например, МуObject1, МуObject2; копировать данные объекта МуObject1 в объект МуObject2: МуObject2.Assign(МуObject1);
Для копирования нельзя использовать оператор присваивания, так как в этом случае происходит присваивание указателей! Например, оператор МуObject2 := МуObject1; присваивается значение указателя МуObject1 указателю МуObject2!
8.1.5. Свойства Доступ к данным класса должен осуществляться только методами класса. Этот принцип объектно-ориентированной разработки программ, называемый инкапсуляцией, в языке Object Pascal реализован с помощью свойств (property). Свойства определяют доступ к полям класса через методы класса, делая сами поля недоступными. Для стандартных классов Delphi это выполняется на 100 %. Синтаксис описания свойства: property <имя свойства> = <тип> read <имя поля или метода чтения> write <имя поля или метода чтения> default <значение по умолчанию> Пример описания свойства SomeColor: type TSomeObject = class(TObject) function GetColor: TSomeType; procedure SetColor(NewValue: TSomeType); property SomeColor: TSomeType read GetColor write SetColor; end;
122
В данном примере доступ к значению свойства SomeColor осуществляется через вызовы методов GetColor и SetColor. Однако в обращении к этим методам в явном виде нет необходимости: достаточно написать, например: AnObject. SomeColor := SomeValue; SomeVariable := AnObject. SomeColor; и компилятор самостоятельно оттранслирует обращение к свойству SomeColor в вызовы методов GetColor или SetColor. В методах, входящих в состав свойств, может осуществляться проверка устанавливаемой величины на попадание в допустимый диапазон значений и вызов других процедур, зависящих от вносимых изменений. Если в описании свойства отсутствует write – то, значит, свойство доступно только для чтения! Аналогично можно сконструировать свойство только для записи. Пример векторного свойства: type TRectangle = class private FCoordinates: array[0..3] of Longint; function GetCoordinate(Index: Integer): Longint; procedure SetCoordinate(Index: Integer; Value: Longint); public property Left: Longint index 0 read GetCoordinate write SetCoordinate; property Top: Longint index 1 read GetCoordinate write SetCoordinate; property Right: Longint index 2 read GetCoordinate write SetCoordinate; property Bottom: Longint index 3 read GetCoordinate write SetCoordinate; property Coordinates[Index: Integer]: Longint read GetCoordinate write SetCoordinate; end;
123
8.1.6. События События возникают в результате воздействий пользователя, аппаратуры компьютера или других программ. Известие о наступлении события в операционной системе Windows – это сообщение. События имеют разное количество и тип параметров, в зависимости от происхождения и предназначения. Общим для всех является параметр sender, он указывает на объект-источник события. В Delphi вызовы обработчиков событий находятся в методах, обрабатывающих сообщения Windows. Все события в Delphi принято предварять префиксом On. Например, onCreate, onMouseMove, onPaint и др.
8.1.7. Исключительные ситуации Исключительная ситуация – это ситуация, которая возникает в результате ошибки в работе программы (например, деление на нуль, попытка открыть несуществующий файл или получить данные по нулевому указателю). Для обработки исключительных ситуаций предназначены специальные классы и операторы языка Object Pascal: • Exception (исключение) – базовый класс для всех классов – исключительных ситуаций. Названия классов, наследуемых от Exception, начинаются с Е, например EZeroDivide; • Операторы try…except и try…finally. В случае возникновения исключительной ситуации выполнение программы немедленно прекращается, и управление передается операторам, идущим за ключевыми словами except или finally. 8.1.7.1. Операторы try…except Операторы try…except применяются для обработки исключительных ситуаций. Синтаксис: try <Операторы> except on <Класс исключения> do <Оператор обработки>;
124
on <Класс исключения> do <Оператор обработки>; ... else { обработчик прочих исключительных ситуаций} <0ператор> end;
Выполнение оператора начинается с секции try. При отсутствии исключительных ситуаций только она и выполняется. Секция except получает управление в случае возникновения исключения. После обработки исключительной ситуации управление обратно в секцию try не передается; выполняются операторы, стоящие после end. Пример: var a, b, c: ShortInt; begin try c:= a div b; except on EIntError {Класс исключений для ошибок целочисленной арифметики (деление на 0, переполнение)} do MessageDlg('Ошибка', mtWarning, [mbOK], 0); { вывод сообщения об ошибке в диалоговое окно с кнопкой OK} end; end.
8.1.7.2. Операторы try…finally Операторы try…finally применяются, когда необходимо возвратить выделенные программе ресурсы даже в случае аварийной ситуации. Синтаксис: try <Операторы> finally <Операторы>; end;
125
Следующие за try операторы исполняются в обычном порядке. Если за это время не возникло никаких исключительных ситуаций, далее следуют те операторы, которые стоят после finally. В случае, если между try и finally произошла исключительная ситуация, управление немедленно передается на операторы после finally, которые называются кодом очистки. Пример: type pList = ^TList; TList = record ... end; var p1: pList; begin new(p1); try ... finally dispose(p1); p1:=Nil; end; end.
Операторы try…finally выполняют только определенные действия, связанные с освобождением ресурсов, но не обрабатывают саму исключительную ситуацию.
126
9. Визуальная разработка программ в Delphi Delphi – это объектно-ориентированная среда визуальной разработки программ и программных систем. Основу Delphi составляют язык Object Pascal и Библиотека визуальных компонентов (Visual Component Library – VCL). VCL – это иерархия объектов Object Pascal, которая обеспечивает быструю и эффективную разработку программ. Палитра компонент и Инспектор объектов среды разработки Delphi позволяют Вам перетаскивать VCL-компоненты на Формы. Манипулируя свойствами компонентов и событиями элементов управления (визуальных компонентов), Вы можете создавать интерфейс пользователя программы практически без написания программного кода. Упрощенная иерархия базовых классов Delphi показана на рисунке 9.1.
127
Рисунок 9.1 – Упрощенная иерархия базовых классов Delphi
Базовые классы Delphi позволяют разработчикам проектировать любые типы приложений.
9.1. Интегрированная среда разработки программ Главное окно интегрированной среды разработки Delphi приведено на рисунке 9.2.
Рисунок 9.2 – Главное окно интегрированной среды разработки
128
Основные элементы интегрированной среды Delphi: • главное меню, • панель инструментов быстрого доступа к командам главного меню – «быстрые клавиши», • палитра компонентов, • инспектор объектов, • редактор форм, • редактор кода.
9.1.1. Проект При старте Delphi создает проект с именем Project1, который является готовым приложением Windows и может работать (заметьте, Вы не написали ни строчки кода, а программа уже работает!). Проект Delphi включает главную программу, формы, модули, ресурсы и другую информацию. Каждой форме соответствует свой модуль. Структура проекта отображается в дереве проектов Менеджера проекта (рисунок 9.3).
129
Рисунок 9.3 – Структура проекта Project1
Автоматически создаваемый при старте Delphi проект Project1 содержит главную программу с именем Project1 (файл Project1.dpr), форму Form1(файл Unit1.dfm) и соответствующий ей модуль Unit1(файл Unit1.pas). Главная программа проекта Delphi скрывает практически все, что необходимо для создания программы – приложения, выполняемого в среде Windows. Текст программы содержит только подключение модулей, соответствующих формам, а также операторы инициализации приложения, создания формы и выполнения приложения (запуск цикла обработки сообщений Windows). Текст главной программы program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin Application.Initialize;
// инициализация приложения
130
Application.CreateForm(TForm1, Form1); // создание формы Application.Run; // цикл обработки сообщений – // запуск выполнения приложения end.
Текст главной программы НЕ следует без необходимости изменять! Формы – это основа визуального программирования в Delphi. Редактор форм позволяет размещать на форме необходимые компоненты, изменять их размеры, выравнивать компоненты и многое другое. В проекте Project1 форма не содержит компонентов (см. рисунок 9.2) и называется Form1. Форма Form1 – это главное окно приложения Windows, формируемого Delphi на основе проекта Project1.
Файл Unit1.dfm – это двоичный файл описания параметров формы и расположенных на ней компонентов. Текстовое представлении Unit1.dfm: object Form1: TForm1 Left = 398 Top = 105 Width = 552 Height = 420 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 end
131
Из описания видно, что форма Form1 – объект класса TForm1, а значит, является визуальным компонентом Delphi. Модуль Unit1 (рисунок 9.4) в интерфейсной части содержит описание класса TForm1, наследуемого от базового класса TForm, и описание единственного объекта этого класса – формы Form1. Так как форма не содержит компонентов, то и класс TForm1 не содержит ни данных, ни методов. Часть реализации модуля Unit1 первоначально также пуста. Проект Project1 можно выполнить, выбрав в меню Run команду Run. Результат выполнения – главное окно приложения – будет находиться на экране, пока пользователь ни нажмет кнопку его завершения. Как изменится описание класса формы и что добавится в реализацию модуля, рассмотрим при конструировании приложения Delphi.
132
Рисунок 9.4 – Модуль Unit1
9.2. Конструирование простого приложения В
качестве
примера
рассмотрим
разработку
приложения
Калькулятор.
Главное окно приложения Калькулятор должно содержать два поля для ввода операндов и одно поле для вывода результата. Калькулятор должен выполнять четыре основные операции: сложение, вычитание, умножение и деление. Для выполнения этих операций необходимо разместить в окне приложения четыре кнопки с символами соответствующих операций. Необходимо предусмотреть кнопку очистки всех полей, а также кнопку выхода из программы. 133
9.2.1. Интерфейс пользователя Интерфейс пользователя приложения Калькулятор может выглядеть, например, как показано на рисунке 9.5.
Рисунок 9.5 – Приложение Калькулятор. Интерфейс пользователя
Для реализации интерфейса будем использовать следующие визуальные компоненты закладки Standard Палитры компонентов: – поле ввода/вывода. Класс TEdit, – кнопка. Класс TButton, – метка. Класс TLabel. Используем для реализации знаков операций и знака =, – панель. Класс TPanel. Используем для реализации «подчеркивания».
134
9.2.2. Визуальное конструирование Начнем конструирование приложения Калькулятор с подготовки проекта: • создадим папку Калькулятор, где будут храниться все файлы проекта, • сохраним в созданной папке «пустой» проект Project1 под именем ProjectCalc (от англ. Calculate – вычислять), а модуль Unit1 – под именем UnitCalc. Дальнейшая разработка приложения, связанная с реализацией интерфейса пользователя, заключается в размещении компонентов на форме, настройке их свойств и назначении обработчиков событий, необходимых для функционирования приложений. Эта работа не требует написания программного кода (поэтому и называют ее визуальной) и выполняется с помощью Редактора форм и Инспектора объектов. Шаг 1. Главная форма приложения. Выделим компонент Форма – для этого щелкнем по нему мышкой. В Инспекторе объектов изменим свойства Caption и Name, как показано на рисунке 9.6. Используем событие OnActivate (возникает, когда приложение становится активным) для очистки полей ввода и результата. Задаем имя обработчика этого события – OnCalcActivate (рисунок 9.7). После того, как задано имя обработчика события, Delphi автоматически помещает спецификацию метода с таким же названием в описание класса TFormCalc и «пустую» реализацию метода в модуль UnitCalc. Шаг 2. Поля ввода значения операндов и поле вывода результата
Выбираем компонент Edit ( ) в Панели инструментов и размещаем его на форме FormCalc. В Инспекторе объектов устанавливаем значения свойств и обработчиков событий. Описание свойств и методов компонента Edit в приложении Калькулятор смотрите в таблице 9.1.
135
Рисунок 9.6 – Приложение Калькулятор. Настройка свойств главной формы
Рисунок 9.7 – Приложение Калькулятор. Обработка событий главной формы
136
Таблица 9.1 – Использование компонента Edit Компонент Edit – отображение, ввод и редактирование однострочного текста. Основное свойство – Text Наименование
Значение
Комментарии
ПОЛЕ ВВОДА ПЕРВОГО ОПЕРАНДА СВОЙСТВА Name
EditOperand1
Наименование объекта
Text
Пусто
В начале выполнения приложения значение первого операнда отсутствует СОБЫТИЯ Обработка нажатия клавиш:
OnKeyPress
Operand1KeyPress
0..9, Backspace (←) – доступны при вводе значения операнда Enter – переход в поле второго операнда
ПОЛЕ ВВОДА ВТОРОГО ОПЕРАНДА СВОЙСТВА Name
EditOperand2
Наименование объекта
Text
Пусто
В начале выполнения приложения значение второго операнда отсутствует
ПОЛЕ ВЫВОДА РЕЗУЛЬТАТА СВОЙСТВА Name
EditResult
Наименование объекта
Text
Пусто
В начале выполнения приложения значение результата отсутствует
ReadOnly
True
Значение True запрещает ввод данных с клавиатуры в это поле
После выполнения данного шага Delphi автоматически помещает в описание класса TFormCalc объекты EditOperand1, EditOperand2, EditResult и спецификацию метода Operand1KeyPress, а также добавляет «пустую» реализацию метода Operand1KeyPress в модуль UnitCalc.
137
Шаг 3. Кнопки
Выбираем компонент Button ( ) в Панели инструментов и размещаем его на форме FormCalc. В Инспекторе объектов устанавливаем значения свойств и обработчиков событий. Описание свойств и методов компонента Button в приложении Калькулятор смотрите в таблице 9.2. Таблица 9.2 – Использование компонента Button Компонент Button – командная кнопка. Используется для выполнения команд пользователя Наименование
Значение
Комментарии
КНОПКА – ОПЕРАЦИЯ СЛОЖЕНИЯ СВОЙСТВА Name
BtnAdd
Наименование объекта
Caption
+
Надпись на кнопке СОБЫТИЯ
OnClick
Нажатие клавиши
BtnAddClick
КНОПКА – ОПЕРАЦИЯ ВЫЧИТАНИЯ СВОЙСТВА Name
BtnMinus
Наименование объекта
Caption
-
Надпись на кнопке
OnClick
BtnMinusClick
СОБЫТИЯ Нажатие клавиши
КНОПКА – ОПЕРАЦИЯ УМНОЖЕНИЯ СВОЙСТВА Name
BtnMult
Наименование объекта
Caption
Η
Надпись на кнопке СОБЫТИЯ
OnClick
Нажатие клавиши
BtnMultClick
138
Таблица 9.2 – Использование компонента Button. Продолжение Компонент Button – командная кнопка. Используется для выполнения команд пользователя Наименование
Значение
Комментарии
КНОПКА – ОПЕРАЦИЯ ДЕЛЕНИЯ СВОЙСТВА Name
BtnDivide
Наименование объекта
Caption
/
Надпись на кнопке СОБЫТИЯ
OnClick
BtnDivideClick
Нажатие клавиши
КНОПКА – ОЧИСТИТЬ СВОЙСТВА Name
BtnClear
Наименование объекта
Caption
Очистить
Надпись на кнопке СОБЫТИЯ
OnClick
BtnClearClick
Нажатие клавиши
КНОПКА – ВЫХОД СВОЙСТВА Name Caption
BtnClose
Наименование объекта
Выход
Надпись на кнопке СОБЫТИЯ
OnClick
BtnCloseClick
Нажатие клавиши
После выполнения данного шага Delphi автоматически помещает в описание класса TFormCalc объекты BtnAdd, BtnMinus, BtnMult, BtnDivide, BtnClear, BtnClose и спецификации методов BtnAddClick, BtnMinusClick, BtnMultClick, BtnDivideClick, BtnClearClick, BtnCloseClick, а также добавляет «пустые» реализации этих методов в модуль UnitCalc.
139
Шаг 4. Метка и панель.
Выбираем компонент Label ( ) в Панели инструментов и размещаем его на форме FormCalc. В Инспекторе объектов устанавливаем значения свойств. Выбираем компонент Panel ( ) в Панели инструментов и размещаем его на форме FormCalc. В Инспекторе объектов устанавливаем значения свойств. Описание свойств компонентов Label и Panel в приложении Калькулятор смотрите в таблице 9.3. Таблица 9.3 – Использование компонентов Label и Panel Компонент Label – отображение текста, не изменяемого пользователем. Основное свойство – Caption Наименование
Значение
Комментарии
ЗНАК ОПЕРАЦИИ СВОЙСТВА Name
OperatorLabel
Наименование объекта
Caption
?
В начале выполнения приложения знак операции отсутствует
ЗНАК = СВОЙСТВА Name
ResultLabel
Наименование объекта
Caption
?
В начале выполнения приложения знак = отсутствует
Компонент Panel – группирование визуальных компонентов. Основное свойство – Caption «ПОДЧЕРКИВАНИЕ» СВОЙСТВА Name
PanelResult
Наименование объекта
Caption
Пусто
В приложении – объемный прямоугольник, который отделяет операнды от результата
140
Таким образом, форма FormCalc будет содержать объекты визуальных компонентов классов TEdit, TButton, TLabel, TPanel (рисунок 9.8). После того, как завершено редактирование формы, фактически завершена разработка структуры приложения Калькулятор – определены основные классы, объекты, свойства и методы объектов Диаграмма классов приложения Калькулятор приведена на рисунке 9.9. Рисунок 9.8 – Классы визуальных компонентов приложения. Калькулятор
Рисунок 9.9 – Приложение Калькулятор. Диаграмма классов
141
Сохраним проект ProjectCalc (для первоначального сохранения проекта выберите в меню File команду Save Project as….) и перейдем к программированию.
9.2.3. Реализация методов Для завершения разработки приложения Калькулятор необходимо добавить программный код в методы обработчиков событий. Методы, автоматически добавляемые Delphi в приложение, первоначально имеют следующую структуру (на примере обработчика события OnActivate): procedure TFormCalc.OnCalcActivate(Sender: TObject); begin end; Шаг 1. Активизация приложения. Метод OnCalcActivate.
При запуске приложения Калькулятор необходимо: • очистить поля ввода и поле результата, • знак операции и знак = должны иметь начальное значение?, • установить курсор в поле первого операнда для ввода числа. Код метода OnCalcActivate: procedure TFormCalc.OnCalcActivate(Sender: TObject); begin EditOperand1.Text :='' ; // Свойство Text – пустая строка EditOperand2.Text :='' ; EditResult.Text :='' ; OperatorLabel.Caption:='?';// Свойство Caption – символ ? ResultLabel.Caption :='?'; EditOperand1.SetFocus; // Установить фокус (курсор) // в поле первого // операнда – EditOperand1 end;
142
Шаг 2. Ввод данных. Метод Operand1KeyPress.
Компонент Edit автоматически осуществляет обработку символов, которые пользователь набирает в поле ввода. После завершения ввода строка введенных символов сохраняется в свойстве Text компонента. Однако в ряде случаев необходимо разрешить ввод только определенных символов и не обрабатывать остальные. На примере ввода первого числа рассмотрим, как можно обрабатывать событие Нажатие клавиши (OnKeyPress). Метод обработки этого события получает, кроме значения параметра Sender(источник вызова метода), еще и код нажатой клавиши – параметр Key. Код метода Operand1KeyPress: procedure TFormCalc.Operand1KeyPress(Sender: TObject; var Key: Char); begin case Key of '0'..'9', chr(8): ; // можно ввести числа 0..9 // и удалить предыдущий // символ ( chr(8) – клавиша Backspace) chr(13) : EditOperand2.SetFocus; // Если нажата клавиша // ENTER – курсор в поле второго операнда else key:=chr(0); // не обрабатывать нажатие других клавиш end; end; Шаг 3. Вычисления. Код метода BtnAddClick: procedure TFormCalc.BtnAddClick(Sender: TObject); begin EditResult.Text:= IntToStr(StrToInt(EditOperand1.Text)+ StrToInt(EditOperand2.Text));
143
OperatorLabel.Caption := '+'; ResultLabel.Caption := '='; EditOperand1.SetFocus; end;
При нажатии на кнопку
(сложить) в поле результата (объект
EditResult, свойство Text) отображается сумма операндов. Знак операции (OperatorLabel.Caption) будет отображаться как символ +. Знак завершения операции (ResultLabel.Caption) – символ =.
Остальные методы вычислений подобны методу BtnAddClick. Отличие только в преобразовании строки в число/числа в строку в операции деления (метод BtnDivideClick), так как результат вычисления может быть дробным числом. Шаг 4. Очистка полей и завершение работы приложения.
Код метода очистки полей ввода и поля результата (метод BtnClearClick) полностью совпадает с методом активизации приложения (OnCalcActivate).
Для завершения работы приложения достаточно в методе BtnCloseClick вызвать процедуру Close – закрытие формы. Шаг 5. Выполнение приложения.
Откомпилируйте проект ProjectCalc. Для компиляции выберите из меню Project команду Compile или нажмите комбинацию клавиш Ctrl+F9. После успешной компиляции для выполнения приложения Калькулятор необходимо выбрать в меню Run команду Run или нажать клавишу F9. На рисунке 9.10 приведено главное окно приложения Калькулятор после выполнения операции сложения. Не изменяя значения операндов, можно вычислить их разность, произведение и получить результат деления. Достаточно просто щелкнуть по соответствующей кнопке. Изменить значения операндов можно, набирая новое значение в поле ввода операндов. Для очистки этих полей необходимо щелкнуть по кнопке Очистить. 144
Рисунок 9.10 – Приложение Калькулятор. Сложение чисел
Завершить работу приложения можно щелчком по кнопке Выход или закрыть окно, щелкнув по кнопке .
9.2.4. Обработка исключительных ситуаций В процессе выполнения приложения Калькулятор возможны исключительные ситуации, связанные с отсутствием значений операндов при вычислениях, а также делением на нуль при выполнении операции деления. В случае попытки вычисления при пустом поле ввода произойдет ошибка преобразования – пустая строка будет преобразовываться в число. Для обработки этих исключительных ситуаций добавим в методы обработчики событий OnClick операторы try…except. Пример обработки в методе BtnDivideClick: procedure TFormCalc.BtnDivideClick(Sender: TObject); begin try EditResult.Text:= FloatToStr( StrToFloat(EditOperand1.Text)/ StrToFloat(EditOperand2.Text)); OperatorLabel.Caption:='/'; ResultLabel.Caption :='='; EditOperand1.SetFocus;
145
except on EConvertError do MessageDlg('Ошибка данных', mtWarning, [mbOK], 0); on EZeroDivide do MessageDlg('Деление на нуль', mtError, [mbOK], 0); end; end;
В методы BtnAddClick, BtnMinusClick, BtnMultClick следует добавить обработки исключений классов EConvertError и EIntError (класс исключений для ошибок целочисленной арифметики – деление на 0, переполнение).
9.2.5. Файлы приложения Калькулятор Теперь перейдем в директорию, куда был сохранен проект ProjectCalc, и посмотрим, какие файлы там присутствуют. Рассмотрим назначение этих файлов: • ProjectCalc.cfg – откомпилированный файл настроек проекта • ProjectCalc.dof – файл содержит опции проекта. Например, RootDir = D:\Введение в конструирование программ\calculator\
• ProjectCalc.dpr – файл проекта, • ProjectCalc.res – файл содержит ресурсы проекта, такие как иконки, курсоры и др., • UnitCalc.pas – файл с исходным кодом модуля UnitCalc, • UnitCalc.dfm – файл содержит информацию о форме, • UnitCalc.ddp – вспомогательный файл модуля UnitCalc, • UnitCalc.dcu – откомпилированного файл модуля UnitCalc. Тексты файлов ProjectCalc.dpr и UnitCalc.pas приведены в приложении Б.
146
9.3. Компоненты ввода/вывода данных StringGrid и Memo Компоненты StringGrid и Memo прежде всего предназначены для ввода и отображения строк. Однако их можно использовать и для работы с числовой и графической информацией.
9.3.1. Компонент StringGrid – таблица строк Компонент StringGrid представляет собой таблицу, ячейки которой содержат строки. Иконка компонента расположена в закладке Additional Палитры компонентов. Иконка и основные свойства отображения таблицы приведены на рисунке 9.11.
Число столбцов Число фиксированных столбцов Число фиксированных строк
Возможность редактировать ячейки таблицы Число строк
Рисунок 9.11 – Компонент StringGrid и его свойства
Основное свойство компонента StringGrid – это Cells: Cells[<номер столбца>, <номер строки>] – ячейки таблицы.
На рисунке 9.12 показано отображение таблицы, свойства которой определены в Инспекторе объектов (см. рисунок 9.11).
147
Рисунок 9.12 – Компонент StringGrid и его отображение
Пример инициализации таблицы StringGrid: procedure TForm1.OnFormActivate(Sender: TObject); begin //Свойства таблицы приведены на рисунке 9.10 with StringGrid1 do begin Cells[0, 1]:= 'Строка 1'; Cells[0, 2]:= 'Строка 2'; Cells[1, 0]:= 'Столбец 1'; Cells[2, 0]:= 'Столбец 2'; Cells[3, 0]:= 'Столбец 3'; Cells[4, 0]:= 'Столбец 4'; Cells[1, 1]:= '1, 1'; Cells[2, 1]:= '1, 2'; Cells[3, 1]:= '1, 3'; Cells[4, 1]:= '1, 4'; Cells[1, 2]:= '2, 1'; Cells[2, 2]:= '2, 2'; Cells[3, 2]:= '2, 3'; Cells[4, 2]:= '2, 4'; end; end;
148
Результат выполнения этой процедуры (рисунок 9.13).
Рисунок 9.13 – Таблица в виде компонента StringGrid
Полезными при разработке программ будут следующие свойства компонента StringGrid: – номер столбца, Col ColCount – количество столбцов, Row – номер строки, RowCount – количество строк.
9.3.2. Ввод массива. Компонент StringGrid Используем компонент StringGrid (Massiv: TStringGrid;) для ввода значений элементов массива (A: array[1..N] of integer;). Шаг 1. Интерфейс пользователя. Размещаем компонент StringGrid на форме (рисунок 9.14). В Инспекторе объектов определяем значения следующих свойств (таблица 9.4). Рисунок 9.14 – Компонент StringGrid для одномерного массиива Таблица 9.4 – Свойства компонента StringGrid для одномерного массива Свойство
Значение
Комментарий
ColCount
10
Количество столбцов
DefaultColWidth
40
Ширина столбца (по умолчанию)
FixedCols
0
Количество фиксированных столбцов
FixedRows
0
Количество фиксированных строк
RowCount
1
Количество строк
149
Шаг 2. Обработка события OnKeyPress компонента StringGrid. procedure TForm1.MassivKeyPress(Sender: TObject; var Key: Char); begin case Key of #8,'0'..'9' : ; // можно ввести числа 0..9 и удалить // предыдущий символ ( #8 – клавиша Backspace) #13: // клавиша Enter if Massiv.Col < Massiv.ColCount-1 then Massiv.Col := Massiv.Col + 1; // курсор устанавливается в // следующий столбец else key := Chr(0); // не обрабатывать нажатие других клавиш end; end; Шаг 3. Формирование массива из строк компонента StringGrid.
Поместим этот код в обработчик события (например, OnClick – щелчок по кнопке), который вызывается после заполнения ячеек компонента StringGrid. for i:= 1 to N do if Length(Massiv.Cells[i-1, 0]) <>0 then
// ячейка содержит // непустую строку a[i]:= StrToInt(Massiv.Cells[i-1,0]) // преобразуем строку // в число и // помещаем в массив else a[i] := 0; // пустая ячейка – значение элемента массива = 0
Шаг 4. Выполнение приложения.
После запуска приложения (вычисляет сумму значений элементов массива, рисунок 9.15) щелкнем мышью в первой ячейке компонента 150
StringGrid, вводим значение и нажимаем клавишу Enter. Повторяем эти действия для ввода остальных значений массива.
Рисунок 9.15 – Компонент StringGrid и его использование для ввода значений элементов массива
Для примера введем значения 1, 2, …, 10. Щелкнем по кнопке Сумма. Вызывается обработчик, который формирует массив из строк ячеек StringGrid (см. шаг 3) и вычисляет сумму.
9.3.3. Компонент Memo – многострочное окно редактирования Компонент Memo обладает так же, как компонент Edit, свойствами и функциями редактора текста. Основное свойство – Lines содержит текст окна редактирования в виде списка строк. Свойство Strings[Index:Integer] можно использовать для того, чтобы получить текст строки. Например, Memo1.Strings[0] – это текст первой строки в окне редактирования. Методы LoadFromFile/SaveToFile свойства Lines позволяют загружать/сохранять текст в/из окна редактирования. Свойство CaretPos может использоваться для определения положения курсора в окне редактирования, а, следовательно, и получения значения символа (перед которым стоит курсор). Например, Memo1.CaretPos.Y+1 – номер строки, Memo1.CaretPos.X+1 – номер символа в строке.
151
9.3.4. Ввод массива. Компонент Memo Используем компонент Memo (MassivMemo: TMemo;) для ввода значений элементов массива (A: array[0..N-1] of integer;). На рисунках 9.16, 9.17 приведен код модуля AverageUnit, в котором использован компонент Memo для ввода массива и вычисления среднего арифметического его значений. Результат выполнения приложения приведен на рисунке 9.18.
Рисунок 9.16 – Модуль AverageUnit
152
Рисунок 9.17 – Модуль AverageUnit (продолжение)
Рисунок 9.18 – Компонент Memo и его использование для ввода значений элементов массива
153
9.4. Немного о графике Программа может выводить графическую информацию на некоторый абстрактный холст. Холст состоит из отдельных точек – пикселов (pixel). Положение пикселя характеризуется координатами X, Y (рисунок 9.19). Координаты возрастают сверху вниз (Y) и слева направо (X). Холсту соответствует свойство Canvas («поверхность», «холст для рисования») – объект класса TCanvas. Методы класса TCanvas обеспечивают вывод графических примитивов: точек, линий, окружностей, прямоугольников и других. Свойства TCanvas позволяют задать характеристики выводимых графических примитивов (цвет, толщину и стиль линий; цвет и вид заполнения областей), а также характеристики шрифта при выводе текстовой информации.
9.4.1. Свойство Canvas. Построение графика функции Для вычерчивания на холсте линий и контуров применяется свойство Реn (карандаш) – объект класса TPеn. Для закрашивания областей холста, ограниченных контурами, применяется свойство Brush (кисть) – объект класса TBrush. Для вывода текста на поверхность графического объекта используется метод TextOut. Шрифт, который используется для вывода текста, определяется значением свойства Font соответствующего объекта Canvas. Пример. Построение графика функции на поверхности формы
На рисунке 9.19 показан интерфейс пользователя: область построения графика и две кнопки управления (График – для вывода графика функции, Выход – для завершения работы). Для построения графика необходимо пересчитывать значение функции в координаты холста. Размер холста можно получить, обратившись к свойствам формы ClientHeight и ClientWidth (высота и ширина клиентской области).
154
Клиентская область формы – это прямоугольная область, в которой отображается результат работы приложения, например, текст или графические изображения. Клиентской области соответствует свойство ClientRect (рисунок 9.20). Начало координат
(0, 0)
Направление оси Х
ClientRect – клиентская область окна
X
Направление оси Y
Y
Область вывода графика функции
Canvas (холст) - поверхность, на которую программа может выводить графику
Рисунок 9.19 – Форма, клиентская область и графические координаты property
ClientRect: TRect; Left, Top – координаты левого верхнего угла Right, Bottom – координаты правого нижнего угла
155
Рисунок 9.20 – Свойство клиентской области
На рисунках 9.21–9.23 показан текст модуля graphExample главной формы приложения для построения графика функции.
Рисунок 9.21 – Модуль graphExample
Собственно построение графика – это цикл, в котором вычисляется значение функции, преобразуется в координаты точки на холсте, а затем соединяется линией с предыдущей точкой.
156
Аргумент функции x меняется от xmin до xmax с шагом stepx. Продолжение цикла по условию x<=xmax кажется совершенно естественным. Однако из-за погрешности вычислений вещественных чисел может оказаться, что значение x не будет точно равно xmax, поэтому последняя точка будет потеряна. Чтобы избежать этой
157
Рисунок 9.22 – Модуль graphExample (продолжение)
158
Рисунок 9.23 – Модуль graphExample (окончание)
ситуации следует подсчитать количество точек n и организовать цикл с целочисленным показателем: n:= Round((xmax - xmin)/stepx)-1; While n>=0 do begin ...
Результат работы приложения – график функции (рисунок 9.24). 159
Рисунок 9.24 – Результат работы приложения
9.4.2. Событие OnPaint Используйте событие OnPaint для выполнения некоторых действий при перерисовке формы. Событие OnPaint происходит перед тем, как компоненты управления отображаются на форме. Если Вы хотите, чтобы перерисовывалась не вся форма, а только ее часть, используйте свойство ClipRect объекта Сanvas (например, Form1.Canvas). Пример. Использование события OnPaint
Пусть обработчик события OnPaint используется для нанесения растрового изображения (Bitmap) в качестве фона формы. Добавим в класс TForm1 закрытый объект – TheGraphic: TBitmap, а в метод FormCreate операторы его создания и загрузки. В обработчике события OnPaint вызовем метод Draw для рисования на форме объекта TheGraphic.
160
procedure TForm1.FormPaint(Sender: TObject); // обработчик события OnPaint begin Form1.Canvas.Draw(0, 0, TheGraphic); // рисование на холсте формы end; procedure TForm1. FormCreate (Sender: TObject); // обработчик события Создание формы begin TheGraphic := TBitmap.Create; // Создание объекта TheGraphic TheGraphic.LoadFromFile('BKGRND.png'); // Загрузка из файла end;
161
10. Тестирующая программа по основам языка Pascal Тестирующая программа по основам языка Pascal предназначена для приема экзаменов и зачетов, а также может быть использована для промежуточного контроля знаний по отдельным темам курса. После запуска программы (файл Test_bp.exe) на экране появляется стартовое окно (рисунок 10.1).
Рисунок 10.1 – Стартовое окно тестирующей программы
В этот момент преподаватель может выполнить настройку программы (см. п. 10.1) либо студент после ввода своей фамилии, группы и названия предмета может приступить к тестированию (см. п. 10.2).
10.1. Руководство преподавателя Перед началом тестирования преподаватель может выполнить настройку программы. Для активации панели настройки используется комбинация клавиш Ctrl+Shift+N. Панель настройки состоит из трех закладок: «Выбор вопросов», «Настройка билетов» и «Выбор тем».
162
На закладке «Выбор вопросов» преподаватель может отметить в перечне вопросов те из них, которые будут использоваться для тестирования студентов (рисунок 10.2).
Рисунок 10.2 – Закладка «Выбор вопросов»
На закладке «Настройка билетов» может быть определено количество вопросов в экзаменационном билете, цена одного балла итоговой оценки, время тестирования, а также выбрана форма контроля знаний: «Тест» или «Экзамен» (рисунок 10.3). В режиме «Тест» тестируемому предлагается ответить на все выбранные для теста вопросы. Этот режим может использоваться для промежуточного контроля знаний по отдельным темам. Режим «Экзамен» используется для итогового тестирования. В этом случае студенту предлагается ответить на пять выбранных случайным образом вопросов. Закладка «Выбор тем» позволяет (с помощью выбора темы тестирования) выбрать сразу все относящиеся к этой теме вопросы (рисунок 10.4).
163
Рисунок 10.3 – Закладка «Настройка билетов»
Рисунок 10.4 – Закладка «Выбор тем»
164
После завершения тестирования на экране появляется окно «Статистика» (рисунок 10.5), с помощью которого можно посмотреть и проанализировать весь процесс тестирования.
Рисунок 10.5 – Окно «Статистика»
Однако, если студент досрочно прервал тест, то преподаватель может просмотреть статистику его ответов с помощью комбинации клавиш Ctrl+Shift+T, которую надо нажать сразу после запуска программы.
165
10.2. Руководство пользователя Большинство вопросов тестирующей программы имеет структуру, показанную на рисунке 10.6. Кроме номера вопроса и его названия с возможным пояснительным текстом, на панели, как правило, находятся блок «Варианты ответа» и блок «Ответ». Блок «Варианты ответа» содержит некоторые объекты, из которых будет строиться ответ в блоке «Ответ». Ответы на большинство вопросов тестирующей программы осуществляются методом перетаскивания объектов из блока «Варианты ответа» в соответствующие прямоугольники блока «Ответ». В случае ошибочного ответа используйте ″стерку″.
Рисунок 10.6 – Пример вопроса
Следующий тип вопросов также использует перетаскивание, однако ответ необходимо набрать из предлагаемых составляющих частей (рисунок 10.7).
166
Рисунок 10.7 – Набор ответа из составляющих частей
После окончания экзамена выдается протокол тестирования в окне «Статистика». Протокол содержит сведения о дате и времени экзамена, сведения о студенте, задаваемые вопросы и анализ правильности ответов, набранные баллы и итоговую оценку.
167
Список литературы 1. Мейер Б. Методы программирования / Б. Мейер, К. Бодуэн. Т. 1. – М.: Мир, 1982. 2. Miller L. N. Advanced programming: Design and Structure using Pascal, Addison-Wesley publishing Company, 1986. 3. Вирт Н. Алгоритмы и структуры данных. – М.: Мир, 1989. 4. Delannoy C. Exercises en Turbo-Pascal, Eyrolles, Paris, 1990. 5. Епанешников А. Программирование в среде Turbo-Pascal 7.0 / А. Епанешников, В. Епанешников. – М.: Диалог-МИФИ, 1993. 6. Самуйлов С. В. Разработка программ в среде Турбо-Паскаля 7.0. Лабораторный практикум. – Пенза, 1996. 7. Марченко А. И. Программирование в среде Turbo Pascal 7.0 / А. И. Марченко, Л. А. Марченко. – Киев: Век +, 2000. 8. Фаронов В. В. Turbo Pascal 7.0. – М.: Надежда, 2000. 9. Брукшир Дж. Гленн. Введение в компьютерные науки. – М.: Вильямс, 2001. 10. Есипов А. С. Информатика. Задачник. / А. С. Есипов, Н. И. Паньгина, М. Г. Громада. – СПб.: Наука и техника, 2001. 11. Пратт Т. Языки программирования: разработка и реализация / Т. Пратт, М. Зелковиц. – СПб.: Питер, 2002 12. Архангельский А. Я. Программирование в Delphi 7. – М.: Бином, 2005.
168
ПРИЛОЖЕНИЕ А Текст модуля Figures unit Figures; interface uses Graph, Crt; type Location = Object {Местоположение} x, y : integer; procedure Create(InitX, InitY : integer); function GetX : integer; function GetY : integer; end; PointPtr = ^Point; Point = Object(Location) {Точка } Visible : boolean; constructor Create(InitX, InitY: integer); destructor Destroy; virtual; procedure Show; virtual; {Показать} procedure Hide; virtual; {Спрятать} function IsVisible : Boolean; procedure MoveTo(NewX, NewY: integer); {Переместить} end; CirclePtr = ^Circle; {Окружность} Circle = Object(Point) Radius : integer; constructor Create(InitX, InitY, InitRadius : integer); procedure Show; virtual; procedure Hide; virtual; end; implementation {Реализация методов класса Location}
169
procedure Location.Create(InitX, InitY : integer); begin x := InitX; y := InitY; end; function Location.GetX : integer; begin GetX := x; end; function Location.GetY : integer; begin GetY := y; end; {Реализация методов класса Point} constructor Point.Create(InitX, InitY: integer); begin Location.Create(InitX, InitY); Visible := false; end; destructor Point.Destroy; begin Hide; end; procedure Point.Show; begin Visible := true; PutPixel(x, y, GetColor); end; procedure Point.Hide; begin Visible := false; PutPixel(x, y, GetBkColor); end;
170
function Point.IsVisible : boolean; begin IsVisible := Visible; end; procedure Point.MoveTo(NewX, NewY : integer); begin Hide; x := NewX; x := NewY; Show; end; {Реализация методов класса Circle} constructor Circle.Create(InitX, InitY, InitRadius : integer); begin Point.Create(InitX, InitY); Radius := InitRadius; end; procedure Circle.Show; begin Visible := true; Graph.Circle(x, y, Radius); end; procedure Circle.Hide; var TmpColor : integer; begin TmpColor:= Graph.GetColor; Graph.SetColor(GetBkColor); Visible := false; Graph.Circle(x, y, Radius); Graph.SetColor(TmpColor); end; end.
171
ПРИЛОЖЕНИЕ Б Тексты файлов ProjectCalc.dpr и UnitCalc.pas Файл ProjectCalc.dpr program ProjectCalc; uses Forms, UnitCalc in 'UnitCalc.pas' {CalcForm}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TCalcForm, CalcForm); Application.Run; end. Файл UnitCalc.pas unit CalcUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TCalcForm = class(TForm) EditOperand1: TEdit; EditOperand2: TEdit; EditResult: TEdit; OperatorLabel: TLabel; ResultLabel: TLabel;
172
BtnAdd: TButton; PanelResult: TPanel; BtnMinus: TButton; BtnDivide: TButton; BtnClear: TButton; BtnClose: TButton; BtnMult: TButton; procedure BtnAddClick(Sender: TObject); procedure BtnMinusClick(Sender: TObject); procedure BtnDivideClick(Sender: TObject); procedure BtnClearClick(Sender: TObject); procedure BtnCloseClick(Sender: TObject); procedure BtnMultClick(Sender: TObject); procedure Operand1keyPress(Sender: TObject; var Key: Char); procedure OnCalcActivate(Sender: TObject); private { Private declarations } public { Public declarations } end; var CalcForm: TCalcForm; implementation {$R *.DFM} procedure TCalcForm.BtnAddClick(Sender: TObject); begin EditResult.Text:= IntToStr(StrToInt(EditOperand1.Text)+ StrToInt(EditOperand2.Text)); OperatorLabel.Caption:='+'; ResultLabel.Caption :='='; EditOperand1.SetFocus; end;
173
procedure TCalcForm.BtnMinusClick(Sender: TObject); begin EditResult.Text:= IntToStr(StrToInt(EditOperand1.Text)StrToInt(EditOperand2.Text)); OperatorLabel.Caption:='-'; ResultLabel.Caption :='='; EditOperand1.SetFocus; end; procedure TCalcForm.BtnDivideClick(Sender: TObject); begin EditResult.Text:= FloatToStr(StrToFloat(EditOperand1.Text)/ StrToFloat(EditOperand2.Text)); OperatorLabel.Caption:='/'; ResultLabel.Caption :='='; EditOperand1.SetFocus; end; procedure TCalcForm.BtnClearClick(Sender: TObject); begin EditOperand1.Text :='' ; EditOperand2.Text :='' ; EditResult.Text :='' ; OperatorLabel.Caption:='?'; ResultLabel.Caption :='?'; EditOperand1.SetFocus; end; procedure TCalcForm.BtnCloseClick(Sender: TObject); begin Close; end;
174
procedure TCalcForm.BtnMultClick(Sender: TObject); begin EditResult.Text:= IntToStr(StrToInt(EditOperand1.Text)* StrToInt(EditOperand2.Text)); OperatorLabel.Caption:='*'; ResultLabel.Caption :='='; EditOperand1.SetFocus; end; procedure TCalcForm.Operand1keyPress(Sender: TObject; var Key: Char); begin case Key of '0'..'9', '-', chr(8): ; chr(13) : EditOperand2.SetFocus; else key:=chr(0); end; end; procedure TCalcForm.OnCalcActivate(Sender: TObject); begin EditOperand1.Text :='' ; EditOperand2.Text :='' ; EditResult.Text :='' ; OperatorLabel.Caption:='?'; ResultLabel.Caption :='?'; EditOperand1.SetFocus; end; end.
175