Turbo Pascal — Основной

advertisement
ПОЛНЫЙ ОБУЧАЮЩИЙ КУРС
TURBO PASCAL
1
СОДЕРЖАНИЕ
ВВОД-ВЫВОД ........................................................................................................................................................................................................... 4
Занятие 1. Язык программирования Паскаль. Знакомство со средой программирования Турбо Паскаль. Основные понятия.
Первая программа. Оператор присваивания. ............................................................................................................................. 4
Занятие 2. Ввод - вывод. Операторы Read (Readln), Write (Writeln). Простейшие линейные программы......................................... 9
ГРАФИКА ................................................................................................................................................................................................................. 14
Занятие 1: Графический режим. Инициализация графического режима. Построение точки, линии. ............................................... 14
Занятие 2: Построение дуги, окружности, прямоугольника, эллипса. ..................................................................................................... 18
Занятие 3: Вывод текста. ................................................................................................................................................................................... 20
Занятие 4. Процедуры рисования закрашенных фигур. ............................................................................................................................. 21
ОПЕРАТОРЫ УСЛОВИЯ И ВЫБОРА .................................................................................................................................................................. 24
Занятие 1. Разветвляющиеся алгоритмы. Оператор условия If. ............................................................................................................... 24
Занятие 2. Логический тип данных. Логические операции not, and, or. Нахождение значений логических выражений.
Самостоятельная работа. .............................................................................................................................................................. 28
Занятие 3. Вложенные условные операторы. Решение задач. .................................................................................................................... 30
Занятие 4. Оператор выбора case. Решение задач. ....................................................................................................................................... 33
Занятие 5. Оператор безусловного перехода Goto. Решение задач. ........................................................................................................... 35
Занятие 6. Контрольная работа ....................................................................................................................................................................... 37
ЦИКЛЫ ..................................................................................................................................................................................................................... 39
Занятие 1. Циклические алгоритмы. Цикл с предусловием. ...................................................................................................................... 39
Занятие 2. Цикл с предусловием в графике. .................................................................................................................................................. 43
Занятие 3. Контрольная работа ....................................................................................................................................................................... 44
Занятие 4. Цикл с постусловием repeat. ......................................................................................................................................................... 44
Занятие 5. Работа с клавиатурой. Стандартные процедуры read и readLn. Стандартные функции readKey и KeyPressed; их
применение в циклах. .................................................................................................................................................................... 45
Занятие 6. Цикл со счетчиком. ......................................................................................................................................................................... 48
Занятие 7-8. Самостоятельное решение задач. .............................................................................................................................................. 49
ПРОЦЕДУРЫ И ФУНКЦИИ................................................................................................................................................................................... 51
Занятие 1. Понятие подпрограммы. Процедуры и функции. Стандартные подпрограммы. Примеры употребления подпрограмм
в решении задач. ............................................................................................................................................................................. 51
Занятие 2. Формальные и фактические параметры. Вызов по ссылке и по значению. Локальные и глобальные переменные и
подпрограммы ................................................................................................................................................................................. 54
Занятие 3. Процедуры. ....................................................................................................................................................................................... 56
Занятие 4. Процедуры в графическом режиме. ............................................................................................................................................. 60
Занятие 5. Функции. ........................................................................................................................................................................................... 60
Занятие 6. Решение задач .................................................................................................................................................................................. 62
РЕКУРСИЯ ............................................................................................................................................................................................................... 66
Занятие 1. Понятие рекурсии. .......................................................................................................................................................................... 66
Занятие 2. Примеры задач рекурсивного решения в текстовом и графическом режимах. .................................................................. 68
Занятие 3. Косвенная рекурсия. ....................................................................................................................................................................... 69
Занятие 4. Решение задач .................................................................................................................................................................................. 70
ОДНОМЕРНЫЕ МАССИВЫ .................................................................................................................................................................................. 75
Занятие 1. Понятие массива. Одномерные массивы. Способы задания одномерных массивов .......................................................... 75
Занятие 2. Доступ к элементам массива ......................................................................................................................................................... 77
Занятие 3. Удаление элементов из одномерного массива. ........................................................................................................................... 79
Занятие 4. Вставка элементов в одномерный массив. ................................................................................................................................. 80
Занятие 5. Перестановка элементов массива. ............................................................................................................................................... 83
Занятие 6. Самостоятельное решение задач. ................................................................................................................................................. 84
ДВУМЕРНЫЕ МАССИВЫ ..................................................................................................................................................................................... 88
Занятие 1. Понятие двумерного массива. Описание типа массива. Формирование значений элементов массива случайным
образом. ............................................................................................................................................................................................. 88
Занятие 2. Работа с элементами массива. ....................................................................................................................................................... 90
Занятие 3. Вставка и удаление строк и столбцов. ......................................................................................................................................... 95
Занятие 4. Перестановка элементов массива. ............................................................................................................................................... 96
Занятие 5. Самостоятельное решение задач. ................................................................................................................................................. 97
Занятие 6. Контрольная работа ..................................................................................................................................................................... 100
МЕТОДЫ СОРТИРОВКИ МАССИВА ................................................................................................................................................................ 102
Занятие 1. Сортировка массива. Способы сортировки массива. ............................................................................................................. 102
Занятие 2. Сортировка вставкой. Сортировка выбором. ......................................................................................................................... 104
Занятие 3. Сортировка методом простого обмена. Рекурсивная сортировка ....................................................................................... 107
Занятие 4. Сортировка методом слияний. ................................................................................................................................................... 108
Занятие 5-6. Самостоятельное решение задач. ............................................................................................................................................ 109
СТРОКИ .................................................................................................................................................................................................................. 110
Занятие 1. Тип данных char. Операции над символами ............................................................................................................................ 110
Занятие 2. Строка. Тип данных string. Строковые переменные, их описание. Длина строки. Операции над строками .............. 112
Занятие 3. Стандартные функции для работы со строками (concat,copy,length, pos,upcase). ............................................................. 114
Занятие 4. Стандартные процедуры для работы со строками (delete, insert,str,val). ........................................................................... 116
Занятие 5. Контрольная работа ..................................................................................................................................................................... 117
Занятие 6. Решение задач. ............................................................................................................................................................................... 121
2
МНОЖЕСТВА ........................................................................................................................................................................................................ 124
Занятие 1. Множественный тип данных. Множество. Элемент множества. Способы задания множества. Объединение множеств.
Разность множеств. Пересечение множеств. ............................................................................................................................ 124
Занятие 2. Логические операции над множествами: проверка принадлежности элемента множеству, проверка включения
элемента в множество, сравнение множеств. ........................................................................................................................... 126
Занятие 3. Примеры решений задач на применение множества. ............................................................................................................ 128
Занятие 4. Самостоятельное решение задач. ............................................................................................................................................... 133
ЗАПИСЬ .................................................................................................................................................................................................................. 135
Занятие 1. Комбинированный тип данных. Запись. Описание записи. Доступ к полям записи. Оператор With. Примеры решения
задач ................................................................................................................................................................................................ 135
Занятие 2. Самостоятельное решение задач ................................................................................................................................................ 138
Занятие 3. Сортировка записей. ..................................................................................................................................................................... 141
Занятие 4. Записи с вариантами. ................................................................................................................................................................... 143
Дополнительно. Решение задач...................................................................................................................................................................... 149
ФАЙЛЫ ................................................................................................................................................................................................................... 151
Занятие 1. Файлы. Виды файлов. Типизированные файлы ..................................................................................................................... 151
Занятие 2. Процедуры и функции для работы с типизированными файлами ...................................................................................... 156
Занятие 3. Самостоятельное решение задач ................................................................................................................................................ 157
Занятие 4. Процедуры и функции работы с файлами. Решение задач ................................................................................................... 161
ТEКСТОВЫЕ ФАЙЛЫ .......................................................................................................................................................................................... 164
Занятие 1. Тeкстовые файлы, их описание и основные отличия от типизированных файлов. ......................................................... 164
Занятие 2. Способы обмена с текстовыми файлами. ................................................................................................................................. 166
Занятие 3. Стандартные текстовые файлы Input и Output. Примеры задач ........................................................................................ 169
Занятие 4. Самостоятельное решение задач ................................................................................................................................................ 171
НЕТИПИЗИРОВАННЫЕ ФАЙЛЫ....................................................................................................................................................................... 178
Занятие 1. Нетипизированные файлы. Их отличия. Процедуры blockread и blockwrite. ................................................................... 179
Занятие 2. Решение задач ................................................................................................................................................................................ 182
Занятие 3. Использование типизированных файлов в качестве нетипизированных .......................................................................... 183
Занятие 4. Использование текстовых файлов в качестве нетипизированных...................................................................................... 183
Занятие 5. Примеры решения творческих задач ........................................................................................................................................ 186
ГРАФ ....................................................................................................................................................................................................................... 191
Занятие 1. Основные понятия. ....................................................................................................................................................................... 191
Занятие 2. Представление деревьев. Основные операции над деревом.................................................................................................. 194
Занятие 3. Самостоятельное решение задач. ............................................................................................................................................... 195
Занятие 4. Идеально сбалансированное дерево........................................................................................................................................... 196
СТЕК........................................................................................................................................................................................................................ 203
Занятие 1. Стек. Отличия стека от списка. Основные операции со стеком. ......................................................................................... 203
Занятие 2. Самостоятельное решение задач ................................................................................................................................................ 209
Занятие 3. Очереди. Основные операции над очередью. ........................................................................................................................... 210
Занятие 4. Самостоятельное решение задач ................................................................................................................................................ 216
Занятие 5. Кольцо. Формирование кольца. Основные операции над кольцом. ................................................................................... 216
Занятие 6. Примеры решения задач с применением динамической структуры кольцо. Творческая работа. ................................ 218
СПИСОК ................................................................................................................................................................................................................. 222
Занятие 1. Список. Создание списка путем добавления элементов в конец списка. Просмотр списка. .......................................... 222
Занятие 2. Создание списка путем вставления элементов в начало. ...................................................................................................... 225
Занятие 3. Упорядочивание списка. Вставление элемента в середину списка. .................................................................................... 227
Занятие 4-5. Примеры задач, решаемых с помощью списка. Решение задач. ....................................................................................... 228
Занятие 6. Удаление элемента из списка. ..................................................................................................................................................... 232
Занятие 7. Зачет. ............................................................................................................................................................................................... 235
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ...................................................................................................................................................... 235
Занятие I. Динамические структуры данных. Статические и динамические переменные. Адреса. Указатели и их объявление.235
Занятие 2. Присвоение значений указателю. Оператор @ с переменной. Оператор @ с параметром процедуры, переданным по
значению. Оператор @ с параметром процедуры, переданным по ссылке. ...................................................................... 238
Занятие 3. Список. Создание списка путем добавления элементов в конец списка. Просмотр списка ........................................... 241
Занятие 4. Создание списка путем вставления элементов в начало. ...................................................................................................... 244
Занятие 5. Упорядочивание списка. Вставление элемента в середину списка. .................................................................................... 245
Занятие 6. Удаление элемента из списка. ..................................................................................................................................................... 249
3
ВВОД-ВЫВОД
Занятие 1. Язык программирования Паскаль. Знакомство со средой программирования Турбо
Паскаль. Основные понятия. Первая программа. Оператор присваивания.
Паскаль – язык профессионального программирования, который назван в честь французского математика и философа
Блеза Паскаля (1623–1662) и разработан в 1968–1971 гг. Никлаусом Виртом. Первоначально был разработан для обучения,
но вскоре стал использоваться для разработки программных средств в профессиональном программировании.
Паскаль популярен среди программистов по следующим причинам:
1. Прост для обучения.
2. Отражает фундаментальные идеи алгоритмов в легко воспринимаемой форме, что предоставляет программисту
средства, помогающие
проектировать программы.
3. Позволяет четко реализовать идеи структурного программирования и структурной организации данных.
4. Использование простых и гибких структур управления: ветвлений, циклов.
5. Надежность разрабатываемых программ.
Турбо Паскаль – это система программирования, созданная для повышения качества и скорости разработки программ
(80-е гг.). Слово Турбо в названии системы программирования – это отражение торговой марки фирмы-разработчика Borland
International (США).
Систему программирования Турбо Паскаль называют интегрированной (integration – объединение отдельных элементов
в единое целое) средой программирования, т.к. она включает в себя редактор, компилятор, отладчик, имеет сервисные
возможности.
Основные файлы Турбо Паскаля:
Turbo.exe – исполняемый файл интегрированной среды программирования;
Turbo.hlp – файл, содержащий данные для помощи;
Turbo.tp
– файл конфигурации системы;
Turbo.tpl – библиотека стандартных модулей, в которых содержатся встроенные процедуры и функции (SYSTEM,
CRT, DOS, PRINTER, GRAPH, TURBO3, GRAPH3).
Запуск интегрированной среды программирования.
Для запуска интегрированной среды программирования нужно установить текущим каталог с Турбо Паскалем
(TP7\BIN) и ввести команду: turbo.exe.
Задание. Запустите среду программирования и рассмотрите экран. Перед вами полоса меню, область окна и строка
статуса. Нажмите клавишу F10 – теперь вам доступны все опции меню. С помощью клавиш перемещения курсора
рассмотрите меню. С командами меню мы будем знакомиться постепенно. Нажмите клавишу Esc (вы вышли из меню).
Перемещая курсор в окне следите за строкой статуса. Запишите в тетрадь ответ на вопрос: какая информация отражается в
этой строке?
Почти все что вы видите и делаете в среде Турбо Паскаль происходит в окнах.
Окно – это область экрана, которую можно перемещать, изменять в размере, перекрывать, закрывать и открывать.
Интегрированная среда программирования Турбо Паскаль позволяет иметь любое количество открытых окон, но в
любой момент времени активным может быть только одно.
Активное окно – это окно с которым вы в настоящий момент работаете.
Общие горячие клавиши:
F1 – выводит окно подсказки;
F2 – сохраняет файл активного окна;
F3 – появление диалогового окна и возможность открыть файл;
F4 – запускает программу до строки, на которой стоит курсор;
F5 – масштабирует диалоговое окно;
F6 – переходит к следующему открытому окну;
F7 – запускает программу в режиме отладки с заходом внутрь процедур;
F8 – запускает программу в режиме отладки, минуя вызов процедур;
F9 – компилирование программы в текущем окне;
F10 – возвращение в меню.
Мы начнем изучение меню с наиболее важных и необходимых режимов.
Как войти в меню? Всего есть три возможности:
- с помощью "мышки";
- с помощью клавиши F10;
- с помощью комбинации Alt+<выделенная буква>. О том, что мы в меню свидетельствует курсор - прямоугольник
зеленого цвета.
С помощью клавиш управления курсором подсветите слово FILE и нажмите клавишу "Enter". Что вы видите?
Появилась вертикальная таблица со списком команд, называемая выпадающим меню. Познакомимся с ним.
Open-F3 – открыть существующий файл (при активизации этой опции появляется окно со списком файлов, где можно
выбрать необходимый),
New – создать новый файл (очищает память редактора и переводит в режим создания нового файла, которому
присваивается имя Noname.pas; имя можно изменить при записи файла на диск),
Save-F2 – сохранить файл (переписывает файл из памяти редактора на диск),
Save as – сохранить с новым именем,
4
Save all – сохранить все в окнах (записывает содержимое всех окон редактора в соответствующие файлы),
Change dir – смена каталога (позволяет изменить установленный по умолчанию диск или каталог),
Print – печать файла,
Get info – выдача информации о текущем состоянии программы и используемой памяти,
DOS Shell – выход в DOS без выгрузки из памяти (для возврата ввести команду exit),
Exit – выход и выгрузка из памяти.
Программы на языке Паскаль имеют блочную структуру:
1. Блок типа PROGRAM – имеет имя, состоящее только из латинских букв и цифр. Его присутствие не обязательно, но
рекомендуется записывать для быстрого распознавания нужной программы среди других листингов.
2. Программный блок, состоящий в общем случае из 7 разделов:
•раздел описания модулей (uses);
•раздел описания меток (label);
•раздел описания констант (const);
•раздел описания типов данных (type);
•раздел описания переменных (var);
•раздел описания процедур и функций;
•раздел описания операторов.
Общая структура программы на языке Паскаль следующая:
Рrogram ИМЯ..; {заголовок программы}
Uses ...;
{раздел описания модулей}
Var ..;
{раздел объявления переменных}
...
Begin
{начало исполнительной части программы}
...
{последовательность
...
операторов}
End.
{конец программы}
Начнем знакомство с Паскалем с программы, которая складывает два числа и выводит сумму на экран.
Откройте файл, в который Вы запишите эту программу. Для этого нажмите клавишу F10, чтобы выйти в главное меню,
затем клавишами перемещения курсора выберите опцию File, а в выпавшем меню команду New.
Примечание. Обратите внимание на оформление текста программы.
Program Summa2;
{Задача. Вычислить сумму двух чисел и вывести на экран.
Решение. Иванов Петр, 10 А класс.}
Var
number1,
{переменная для хранения первого числа}
number2,
{переменная для хранения второго числа}
rezult
{переменная для хранения результата вычисления}
: integer;
Begin
{признак начала программы}
number1 := 3;
{присваиваем переменной number1 значение 3}
number2 := 4;
{присваиваем переменной number2 значение 4}
{складываем значения переменных number1 и number2 и результат присваиваем переменной rezult }
rezult := number1 + number2;
Write (number1, '+', number2,'=',rezult);
{вывод примера на экран}
End.
{признак конца программы}
Задание. 1) Найдите в этой программе заголовок, раздел описания переменных, признак начала программы, признак
конца программы, тело программы, комментарий.
2) Что обозначает строчка
number1, number2, rezult : integer;
3) Как вы понимаете запись:
number1 := 3;
4) Чему равно значение переменной rezult после выполнения оператора
rezult := number1 + number2;
5) Переведите с английского языка слово Write. Как вы думаете, что должен делать оператор с таким названием?
6) Поменяем местами второй и третий операторы. Будет ли программа работать? Почему?
7) Какой недостаток Вы видите у этой программы? Как нужно изменить условие задачи, чтобы решать подобные задачи
с любыми числами. Подумайте, что должно измениться в теле нашей программы, чтобы выполнить эту задачу.
А теперь подведем итог вашим размышлениям.
Имя этой программы Summa2. Заметим, что требования к имени выполняются: оно отражает содержание программы, а
также не содержит недопустимых символов.
Далее идет специально выделенный комментарий, в котором вы должны записать подробно условие задачи и указать,
кто написал эту программу и когда.
Из разделов описаний имеется лишь один – раздел переменных. Он начинается со служебного слова Var. Мы описали
три переменные: number1, number2, rezult. Все они переменные целого типа. Поэтому мы перечислили их через запятую,
поставили двоеточие и указали тип переменных. Подобные объявления разделяются между собой точкой с запятой.
5
После описательной части идет раздел операторов, начинающийся со служебного слова Begin, после которого идут
операторы языка.
Недостатком этой программы является то, что значения переменных постоянны. А нам нужно научиться писать такие
программы, которые решают поставленные задачи в общем виде, т. е. для любых значений переменных. Для этого мы
научимся запрашивать значения у пользователя, анализировать их и выдавать соответствующий результат.
Оператор присваивания. Арифметические выражения
Первый оператор, с которым мы познакомимся,– оператор присваивания.
Оператор присваивания - основной оператор любого языка программирования. Общая форма записи оператора:
имя величины := выражение
Например, V:=A; или V:=A+1;
При помощи оператора присваивания переменной могут присваиваться константы и выражения, значения переменных
любого типа.
Как только в программе встречается переменная, для неё в памяти отводится место. Оператор присваивания помещает
значение переменной или значение выражения в отведённое место.
Если в процессе выполнения программы встречается пере присваивание (т.е. та же самая переменная принимает другое
значение), то старое значение переменной стирается, на свободное место записывается новое значение. Команда
присваивания позволяет лучше понять смысл слова переменная (т.е. меняющая своё значение по ходу программы).
Выражение может быть арифметическим, логическим или литерным. Важно, чтобы тип величины был согласован с
видом выражения.
Арифметические выражения должны быть записаны в так называемой линейной записи согласно следующим правилам:
• выражение должно быть записано в виде линейной цепочки символов;
• используемые операции приведены в таблице:
НАЗВАНИЕ ОПЕРАЦИИ
ФОРМА ЗАПИСИ
сложение
x+y
вычитание
x-y
умножение
x*y
деление
x/y
• нельзя опускать знаки операций, например писать 5b. Для записи произведения чисел 5 и b надо писать 5*b;
• аргументы функций (sin, cos и др.) как и аргументы вспомогательных алгоритмов, записываются в круглых скобках,
например sin(x), cos(4*x).
Порядок выполнения операций
Порядок выполнения операций при вычислении арифметических выражений можно регулировать при помощи скобок
по обычным правилам. Там, где скобки отсутствуют, ЭВМ выполняет операции в следующем порядке:
• вычисляет значение всех алгоритмов-функций и стандартных функций;
• выполняет справа налево все операции возведения в степень;
• выполняет слева направо все операции умножения и деления;
• выполняет слева направо все операции сложения и вычитания.
В нашем случае сначала переменной number1 присваивается значение равное 3 и переменной number2 присваивается
значение равное 4, затем вычисляется значение выражения (number1 + number2) и оно присваивается переменной rezult.
Сумма чисел посчитана.
Теперь надо вывести ее значение на экран. Для этого используют оператор Write – записать (вывести) на экран значение
переменной, записанной в скобках. В нашем случае значение переменной number1, затем символ + , далее значение
переменной number2, символ = и, наконец, значение результата rezult.
И, наконец, в конце раздела операторов стоит служебное слово End, после которого стоит точка.
Задание. Наберите текст программы на компьютере и выполните ее (для запуска программы воспользуйтесь
комбинацией клавиш Ctrl и F9).
Внимание! Не забывайте о порядке на дискете и в файле:
• имя программы должно соответствовать ее содержанию,
• имя файла должно быть таким же, как и имя программы,
• файлы, содержащие программы, относящиеся к одной теме, должны находиться в одном каталоге,
• название этого каталога должно отражать его содержание.
Задание. Измените программу так, чтобы она подсчитывала сумму четырех чисел.
Сохраните файл на дискете, для этого из меню F10-File выберите команду Save и в предложенной строке наберите путь
a:\Vvod\Summa (каталог Vvod должен быть уже организован для файлов, содержащих программы данной темы).
Основные определения. Типы данных.
Познакомимся с основными понятиями языка.
Алгоритм – четкая последовательность действий, необходимая для решения задачи.
Программа – алгоритм, записанный на языке программирования.
Алфавит языка – набор элементарных символов, используемый для составления программ. Алфавит содержит:
52 буквы латинского алфавита (строчные и заглавные);
арабские цифры (0-9);
специальные символы:
знаки математических действий (+ – * / ),
6
знаки пунктуации (. : , ; " ` ),
скобки ( [ ] ( ) { } ),
знак пробела,
знаки отношений (< > =)
Идентификатор (имя) – имя какого-либо элемента программы, которое должно удовлетворять следующим
требованиям:
•
длина имени не должна превышать 63 символа,
•
первым символом не может быть цифра,
•
переменная не может содержать пробел;
•
имя не должно совпадать с зарезервированным (служебным) словом,
•
прописные и строчные буквы воспринимаются одинаково.
Зарезервированные (служебные) слова – это слова, использующиеся только по своему прямому назначению. Их нельзя
использовать в качестве переменных, так как они выполняют определенную смысловую нагрузку.
Примеры зарезервированных слов: AND, GOTO, PROGRAM, ELSE, IF, RECORD, NOT, ARRAY, REPEAT, UNTIL,
BEGIN, IN, SET, END, CASE, CONST, USES, INTERFACE, STRING, LABEL, THEN, OF, DIV, TO, VAR, DO, TYPE, WHILE,
DOWNTO, FILE, FUNCTION, PROCEDURE и другие.
Переменные (Var) – вид данных, который может изменять свое значение в ходе программы, описывают переменные
после зарезервированного слова Var.
Константы (Const) – вид данных, который является постоянным на всем протяжении выполнения программы,
описывают константы после зарезервированного слова Const.
Комментарии – некоторая запись, служащая для пояснения программы, которая записывается в фигурных скобках.
Типы данных.
Для временного хранения информации в операторах памяти машины в языке Паскаль используются константы и
переменные. Они могут быть различных типов:

целых чисел (см. ниже);

действительных чисел (real);

символьный тип (char);

строковый (string);

логический (boolean);

сложные (комбинированный (record), множественный (set) и другие).
Целые типы:
Название
Длина в байтах
Диапазон значений
Byte
1
0 ... 255
ShortInt
1
-128 ... 127
Word
2
0 ... 65535
7 3
Integer
2
-32768 ... 32767
LongInt
4
-2147483648 ... 2147483647
6 2
div
Над целыми типами определены такие операции:
1
1. "+" - сложение;
2. " * " - умножение;
3. " - " вычитание;
mod
4. div - целочисленное деление;
5. mod - получение остатка от целочисленного деления.
Вещественные типы:
Вещественные типы представляются с некоторой точностью, которая зависит от компьютера. Вам необходимо знать,
что вещественный тип разделяется на несколько типов, но использовать мы будем вещественные данные только типа Real,
которые занимают 6 байт, имеют диапазон возможных значений модуля от 2.9Е-39 до 1.7Е+38 и точность представления
данных – 11...12 значащих цифр.
Примечание. Несмотря на то, что в Turbo Pascal имеется широкий выбор вещественных типов, доступ к некоторым из
них (single, double, extended) возможен при особых режимах компиляции. Особое положение в Turbo Pascal занимает тип
comp, трактующийся как вещественное число без экспоненциальной и дробной частей. Он сохраняет 19 - 20 значащих цифр
и знак числа. В то же время comp полностью совместим с любыми другими вещественными типами.
В языке Паскаль числа могут быть представлены в двух видах: с фиксированной точкой и плавающей запятой.
Числа с фиксированной точкой изображаются десятичным числом с дробной частью, которая может быть и нулевой.
Например, 27.9, 5.00
8
Такие большие числа как 137.000.000 можно записать в виде чисел с десятичным порядком 1.3710 . Такие числа
имеют вид mEp. Здесь m - мантисса; E - признак записи числа с десятичным порядком; p - степень числа 10. Получится
1.37Е+8. Такие числа, представленные с десятичным порядком и называются числами с плавающей точкой. Например,
Математическая запись:
Запись на Паскале:
4
4E -4
4 10
5
0.62E+5
0,62 10
10,881012
-10.88E12
7
Компьютер, по умолчанию, представляет действительные числа в виде чисел с плавающей точкой. Такое представление
чисел не очень нравится пользователям. Поэтому мы будем “заставлять” компьютер выдавать действительные числа в более
привычном варианте следующим образом:
R:m:n, где R – действительное число, m – количество позиций, отводимых для целой части, n – количество позиций,
отводимых для дробной части.
Например, если мы хотим вывести на экран число Chislo с фиксированной точкой, причем знаем, что для вывода целой
части этого числа достаточно 7 мест, а вывод дробной части ограничим сотыми, то мы запишем вывод так:
Write (Chislo:7:2)
Символьный тип (char)
Значениями данного типа является множество всех символов компьютера: русская или латинская большая или
маленькая буква, цифра, знак препинания, специальный знак (например, "+", "-", "*", "/", "", "=" и др.) или пробел " ".
Каждый из символов имеет уникальный номер от 0 до 255, т. е. внутренний код, который возвращает функция ORD.
Символьная константа или символьная переменная - любой символ языка, заключённый в апострофы. Например,
Var
Simvol : char;
Строковый тип (string)
Значением строковой величины является строка переменной длины (быть может пустая). Строковая константа или
строковая переменная представляет собой произвольную последовательность символов, заключенную в апострофы.
Например,
Var
Stroka : string;
Логический тип (boolean)
Логический тип данных часто называют булевым по имени английского математика Д. Буля, создателя математической
логики. В языке Паскаль имеются две логические константы TRUE и FALSE. Логическая переменная принимает одно из
этих значений и имеет тип Boolean. Для сравнения данных предусмотрены следующие операции отношений: <, <=, =, <>, >,
>=. А также существуют специфичные для этого типа логические операции OR - или; AND - и; NOT - не.
При проверке некоторых условий результат операции может быть истинным или ложным. Например, 3>5 ложь.
Более подробно этот тип данных мы рассмотрим при изучении условного оператора.
Сложные типы
К сложным или структурированным типам относятся массивы, записи, множества, которые требуют специального
изучения и здесь рассматриваться не будут.
Задание. Откройте новый файл. Создадим программу, в которой опишем несколько переменных разного типа, введем в
них значения и выведем на экран.
Program TipDann;
Uses
Crt
Var
Chislo1 : Integer;
Chislo2 : Real;
Simvol : Char;
Stroka : String;
Logika : Boolean;
Begin
ClrScr;
Chislo1:=12;
Chislo2:=Chislo1*2;
Chislo2:=Chislo2/5;
Simvol:=‘d’;
Stroka:=‘Строчка’;
Logika:= Chislo1> Chislo2;
WriteLn (‘Вывод значений:’);
WriteLn (‘Значение переменной Chislo1 : ’,Chislo1);
WriteLn (‘Значение переменной Chislo2 : ’,Chislo2:5:2);
WriteLn (‘Значение переменной Simvol : ’,Simvol);
WriteLn (‘Значение переменной Stroka : ’,Stroka);
WriteLn (‘Значение переменной Logika : ’,Logika);
End.
Внимательно рассмотрите каждую строчку программы. Обратите особое внимание на описание переменных: Chislo1 –
переменная целого типа, Chislo2 – действительного, Simvol – символьного, Stroka – строкового, Logika – логического. Далее
в основной программе идет присвоение переменной Chislo1 целого числа 12, переменной Chislo2 – целого числа 24. Обратим
внимание, что переменной действительного типа Chislo2 присвоено целое число; никакой ошибки нет, т. к. множество целых
чисел является подмножеством множества действительных чисел. Следующая строчка еще более интересная: переменной
Chislo2 присваивается значение той же переменной, только деленной на 5. Такое присваивание используют в программах,
если предыдущее значение этой переменной уже не понадобится и для более рационального использования описанных
переменных. Для того чтобы переменной символьного типа присвоить какой-либо символ (например, d), надо этот символ
записать в апострофах (знак «’»). Аналогично поступают с переменными строкового типа (смотри следующую строку
8
программы). А про переменные логического типа мы знаем, что им можно присваивать только два значения: True и False. В
этой программе мы присвоим значение результата сравнения двух переменных, здесь оно будет равно True. А теперь
выведем присвоенные значения на экран.
Задание. Измените значения переменных и проанализируйте результаты выполнения программы. Сохраните программу
на дискете под правильным именем в соответствующем каталоге. Распечатайте программу.
Занятие 2.
программы
Ввод - вывод. Операторы Read (Readln), Write (Writeln). Простейшие линейные
Решим задачу, прокомментировав каждое свое действие в фигурных скобках. Напомним, что комментарий не
воспринимается компьютером, а нам он нужен для того, чтобы лучше понять как работает программа.
Задача. Напишите программу, которая бы очищала экран и вычисляла произведение двух чисел, вводимых
пользователем.
Program Proizv2;
Uses
Crt;{Подключаем модуль Crt}
Var
number1, {переменная, в которой будет содержаться первое число}
number2, {переменная, в которой будет содержаться второе число}
rezult {переменная, в которой будет содержаться результат}
: integer;
Begin
ClrScr;{Используем процедуру очистки экрана из модуля Crt}
Write ('Введите первое число ');
{Выводим на экран символы, записанные между апострофами}
Readln (number1);
{Введенное пользователем число считываем в переменную number1}
Write ('Введите второе число ');
{Выводим на экран символы, записанные между апострофами}
Readln (number2);
{Введенное пользователем число считываем в переменную number2}
rezult := number1 * number2;
{Находим произведение введенных чисел и присваиваем переменной rezult}
Write ('Произведение чисел ', number1, ' и ', number2, ' равно ', rezult);
{Выводим на экран строчку, содержащую ответ задачи}
Readln;{Процедура задержки экрана}
End.
Чтобы лучше понять действие программы, наберите ее на компьютере и проверьте ее действие. Ответьте на вопросы:
• почему программу назвали Proizv2?
• зачем в раздел Uses поместили модуль Crt?
• какое назначение переменных number1, number2, rezult?
• какой тип у этих переменных? что это значит?
• если присвоить переменным number1 и number2 соответственно значение 5 и 7, то какую строчку выдаст компьютер
при исполнении последней процедуры Write? Запишите ее в тетрадь.
• в каких строчках у пользователя запрашиваются значения переменных?
• в какой строчке происходит умножение чисел?
• что делает оператор присваивания в этой программе?
Задание. Измените программу так, чтобы она запрашивала у пользователя еще одну переменную и выводила результат
произведения трех чисел.
Операторы Write и WriteLn
Мы уже использовали операторы Write и WriteLn, но нам необходимо подробнее остановиться на правилах
применения этих операторов.
Write (англ. писать) – оператор, который используется для вывода информации на экран. Оператор WriteLn
выполняет то же самое действие, но так как у него есть еще окончание Ln (line - англ. линия, строка), то после вывода на
экран нужного сообщения, он дополнительно переводит курсор на следующую строчку.
Общий вид:
Write (список выражений)
WriteLn (список выражений)
Процедуры Write и WriteLn используются не только для вывода результата, но и для вывода различных сообщений или
запросов. Это позволяет вести диалог с пользователем, сообщать ему, когда ему нужно ввести значения , когда он получает
результат, когда он ошибся и др.
Например, при выполнении процедуры WriteLn(‘Найденное число ‘,а), будет напечатана строчка, заключенная в
апострофы, а затем выведено значение переменной а.
Оператор WriteLn можно применить и без параметров. В этом случае напечатается строка, состоящая из пробелов, и
курсор будет переведен на другую строку. Это иногда нам нужно для лучшего восприятия ввода данных.
9
Операторы Read и ReadLn
Вспомним, что основное назначение ЭВМ – сэкономить человеческий труд. Поэтому необходимо обеспечить
возможность, однажды написав программу, многократно ее использовать, вводя каждый раз другие данные. Такая гибкость в
языке обеспечивается операторами Read и ReadLn. Этими операторами вводится информация с клавиатуры.
Общий вид:
Read(переменная, переменная...)
ReadLn(переменная, переменная...)
При выполнении процедуры Read ожидается ввод перечисленных в скобках значений. Вводимые данные нужно
отделить друг от друга пробелами. Присваивание значений идет по очереди.
Например, если вводятся значения 53 и Х, то при выполнении оператора Read(a,b) переменной а будет присвоено число
53, а переменной Х – буква Х. Причем, отметим, чтобы не было аварийной ситуации, нужно правильно определить тип
данных в разделе Var; в нашем случае а:integer, а b:char.
Особых различий при чтении и записи в использовании операторов Read и ReadLn нет. Часто процедуру ReadLn без
параметров применяют в конце программы для задержки: до нажатия на клавишу <Enter> результат выполнения программы
остается на экране. Это очень полезно делать для анализа результатов.
Примечание. Когда Вы ставите задержку экрана, обратите внимание на предыдущий ввод. Если данные запрашивались
процедурой Read задержки не будет.
Решим задачу, в которой рассмотрим все возможные употребления этих процедур.
Задача. Найти среднее значение трех чисел.
Примечание. Чтобы найти среднее значение нескольких чисел, нужно сложить эти числа и сумму разделить на
количество этих чисел.
Program Srednee;
Uses
Crt;
Var
First, Second, Third : integer;
Sum : real;
Begin
ClrScr;
Write (‘Введите первое число ‘);
ReadLn(First);
Write (‘Введите второе и третье числа через пробел ‘);
ReadLn(Second, Third);
Sum := First + Second + Third;
Sum := Sum/3;
Write (‘Среднее значение ‘, First, ‘, ‘,Second, ‘ и ‘, Third, ‘ равно ‘, Sum:5:2);
ReadLn;
End.
Наберите текст задачи и внимательно рассмотрите каждую строчку. Имя программы Srednee отражает содержание
задачи. Кстати, договоримся о том, чтобы имя программы и имя файла, который содержит эту программу, совпадали. Далее
идет подключение модуля Crt. В разделе Var описаны First, Second, Third как переменные целого типа, а Sum –
действительного типа. Раздел операторов начинается со стандартной процедуры очистки экрана ClrScr (Clear Screen),
которая находится в модуле Crt. Далее оператором Write мы выводим на экран сообщение ‘Введите первое число ‘, получив
которое пользователь должен ввести число. Теперь компьютер должен считать введенные символы и занести их в
переменную First, это произойдет при выполнении следующего оператора ReadLn(First). Затем с помощью оператора Write
запрашиваем значения еще двух чисел и считываем их в переменные Second и Third. Затем вычисляем их сумму и
присваиваем полученное число переменной Sum. Чтобы найти среднее, нужно теперь полученное число разделить на 3 и
сохранить результат в какой-либо переменной. Совсем не обязательно описывать еще одну переменную для сохранения
результата. Можно, как в нашей программе, значение переменной Sum разделить на 3 и результат опять присвоить той же
переменной Sum. Теперь можно вывести результат вычислений на экран с помощью процедуры Write. И, наконец, последняя
процедура ReadLn задержит наш вывод на экране до нажатия на клавишу.
Нажмите клавиши <Ctrl>+<F9>. Введите значения переменных 5, 7 и 12, на экране увидите следующее:
Среднее значение 5, 7 и 12 равно 8.00
Просмотрите внимательно эту строчку и сравните со строчкой вывода результата в нашей программе. Протестируйте
программу еще несколько раз для других значений переменных.
Выберите с учителем задачи для решения из следующего перечня:
1. Ввести два числа a и b. С помощью оператора присваивания обменять их значения:
а) с использованием промежуточной переменной (x:=a; a:=b; b:=x);
b) без использования промежуточной переменной (a:=a-b; b:=a+b; a:=b-a).
2. Составить программу, которая запрашивает у пользователя целое число, действительное число, произвольный символ
и строку, а затем все выводит в одной строчке.
3. Выведите на экран свою фамилию, имя и отчество, а через две строки – дату своего рождения.
4. Написать программу для печати звездочками одной из фигур:
а) елочки (нескольких елочек);
б) снежинки (нескольких снежинок);
в) домика.
10
Например,
*
*
*
*
*
**********
*
*
*
*
*
*
*
*
**********
5. Составить свою визитную карточку.
*******************************
*
Иванов Сергей *
*
Пролетарская 74 кв. 55 *
*
Телефон 45-72-88
*
*******************************
6. Составьте диалог пользователя с компьютером на произвольную тему.
Например, машина задает два вопроса “Как тебя зовут?” и “Сколько тебе лет?”; после введения имени (Антон) и числа
(15) выводит на экран “Да... Через 50 лет тебе уже будет 65 лет, а звать тебя будут не Антон, а дед Антон”
7. Запросить у пользователя два числа и вывести на экран результат суммы, разности, произведения и частного этих
чисел полным ответом.
8. Запросить у пользователя два числа и вывести на экран результат целочисленного деления и остаток от
целочисленного деления в виде таблицы. Например, при вводе чисел 5 и 3 на экране должна быть такая таблица:
**************************
* X * Y * div * mod *
**************************
* 5 * 3 * 1 * 2
*
**************************
9. Написать программу, которая запрашивает название животного и число, а затем выводит на экран фразу типа "Белка
съест 10 грибов" (при вводе слова "белка" и числа 10).
10. Организуйте диалог продавца (компьютер) и покупателя (пользователь) при покупке какого-либо товара по
следующей схеме: предложение товара по определенной цене, запрашивание количества покупаемого товара, определение и
вывод на экран денежной суммы, которую должен заплатить покупатель за покупку.
Занятие III
Тема: Стандартные функции и процедуры. Применение в простейших линейных программах
Для решения задач нам понадобятся стандартные функции и процедуры.
Функция – это такая организация преобразования переданного ей значения, при которой это измененное значение
передается обратно.
Процедура – это такая организация преобразования переданного ей значения параметра, при которой изменяется
значение этого параметра, и, в отличие от функции, не возвращает никакого значения.
Познакомимся с основными, наиболее часто используемыми.
I Арифметические функции
1) Abs(x), где аргумент и результат являются переменными целого или вещественного типа – вычисляет модуль
(абсолютную величину) числа х;
2) Cos(x), где аргумент и результат являются переменными вещественного типа – вычисляет косинус х;
3) Sin(x), где аргумент и результат являются переменными вещественного типа – вычисляет синус х;
4) Frac(x), где аргумент и результат являются переменными вещественного типа – выделяет дробную часть числа х;
5) Int(x), где аргумент и результат являются переменными вещественного типа – выделяет целую часть числа х;
6) Pi, где результат является переменной вещественного типа – вычисляет значение 
7) Random(x), где аргумент и результат являются переменными целого типа – генерирует случайное число в пределах
от 0 до х включительно. Если параметр х не задан, то формируется вещественное число от 0 до 1. Перед использованием
данной функции нужно инициализировать генератор случайных чисел при помощи процедуры Randomize (см. ниже);
2
x ;
9) Sqrt(x), где аргумент и результат являются переменными целого или вещественного типа – вычисляет x .
8) Sqr(x), где аргумент и результат являются переменными целого или вещественного типа – вычисляет
II Функции преобразования типов
1) Chr(x), где аргумент типа Byte, а результат типа Char– возвращает символ, у которого код в таблице ASCII равен х;
2) Ord(x), где аргумент может быть любого порядкового типа, а результат типа LongInt – возвращает порядковый
номер значения х при начале нумерации с нуля;
3) Round(x), где аргумент вещественного типа, результат типа LongInt – округляет число х до ближайшего целого;
4) Trunc(x), где аргумент вещественного типа, результат типа LongInt – выделяет целую часть числа х.
III Функции для порядковых типов
1) Odd(x), где аргумент типа LongInt, а результат логического типа – определяет, является ли число четным (результат
false) или нечетным (результат true);
2) Pred(x), где аргумент и результат любого порядкового типа – получает предшествующее значение;
3) Succ(x), где аргумент и результат любого порядкового типа – получает последующее значение;
11
4) Upcase(x), где аргумент и результат типа Char – преобразует букву латинского алфавита в соответствующую ей
заглавную (буква х может быть как строчной, так и заглавной).
IV Процедуры для порядковых типов
1) Dec(x), где аргумент любого порядкового типа – уменьшает значение переменной х на 1;
2) Dec(x,n), где х любого порядкового типа, а n типа LongInt – уменьшает значение переменной х на n;
3) Inc(x), где аргумент любого порядкового типа – увеличивает значение переменной х на 1;
4) Inc(x,n), где х любого порядкового типа, а n типа LongInt – увеличивает значение переменной х на n;
5) Randomize – инициализирует генератор случайных чисел.
Правила применения функций:
• чтобы воспользоваться функцией, нужно указать ее в правой части оператора присваивания;
• при обращении к функции необходимо в круглых скобках указать ее аргументы;
• в разделе описания переменных правильно указывайте типы переменных, которые хотите употребить в качестве
аргумента или результата функции;
• в одном выражении можно обратиться к нескольким функциям.
Правила применения процедур:
• для выполнения процедуры ее надо вызвать в программе в виде оператора;
• в разделе описания переменных правильно указывайте тип переменной, которую хотите употребить в качестве
аргумента процедуры.
Задача. Найти значения выражений:
a) (1+x)2
b)
c)
(1   ) * 5 |a+ bx|
Прежде чем приступить к
составлению программы, необходимо перевести данные выражения с
математического языка на язык Паскаль.
a) (1+x)2

sqr(1+x)
b) 
sqrt((1+A)*5)
(1   ) * 5  abs(A+b*x)
c)
|A+ bx|
Теперь уже можно переходить к составлению программы.
Program Primer;
Uses
Crt;
Var
A : word; {так как подкоренное выражение должно быть положительно}
b, x, Rezult : integer;
Begin
ClrScr;
Writeln(‘Введите значения переменных (A-положительно)’);
Write(‘A=’);
Readln(A);
Write(‘b=’);
Readln(b);
Write(‘x=’);
Readln(x);
Result := sqr(1+x);
Write (‘sqr(1+x)=’, Rezult);
Result := sqrt((1+A)*5);
Write (‘sqrt((1+A)*5)=’, Rezult);
Result := abs(A+b*x);
Write (‘abs(A+b*x)=’, Rezult);
Readln;
End.
Задание. Наберите программу, протестируйте, добавьте комментарий, сохраните файл и распечатайте листинг.
Занятие IV
Тема: Решение задач
Теперь Вы должны научиться применять в программах полученные Вами знания для решения определенных задач.
Выберите с учителем задачи из предложенного ниже списка. Старайтесь выполнять задание самостоятельно. Если возникают
проблемы, обращайтесь к учителю.
1. Найти значение арифметического выражения, запросив значения переменных у пользователя:
а)
R
x

4
8 0,5y  1
b) 3x 
4,2
2
c)
4
1
64a 
a12  a2
3k
2. По данным сторонам прямоугольника вычислить его периметр (P), площадь (S) и длину диагоналей (D) по формулам:
2
2
Р=2(a+b);
S=ab;
D= a  b
3. Запросите действительное число и найдите целую часть этого числа и округлите его до ближайшего целого.
4. Найти площадь круга (S) и длину окружности (L) заданного радиуса.
2
S=  R ,
L=2  R
12
5. Выполнить целочисленное деление натурального числа х на натуральное число у и вывести на экран частное q и
остаток r (см. формулы).
6. Составить программу вычисления площади произвольного треугольника, пользуясь любой из известных формул
(задав необходимые исходные данные):
1
ah , где а – основание треугольника, h – высота, проведенная к этому основанию;
2
abc
S= p(p  a)(p  b)( p  c) , где a, b, с – стороны треугольника, а р =
;
2
1
S=
ab sin С, где a, b – стороны треугольника,  С – угол между ними.
2
S=
7. Вычислить рациональным способом, то есть за минимальное количество операций:
5
x   x )
, (т.е. за три операции y= x  x  )
, (т.е. за три операции y= x   )
a) y=x , (т.е. за три операции y=
b) y=x
c) y=x
6
8
2 2
2
2
2
2 2
8. Найти значение выражения:
a) d= 3c
3
 c 2  4c  9 3c
b) d= x
 7  x 2  4x  9  3x
9.Вычислить объем (V) и площадь (S) полной поверхности прямоугольного параллелепипеда по длинам его ребер а, в, с.
V=abc; S=2ab+2bc+2ac
10. По данной высоте Н и диаметру основания D прямого кругового циллиндра вычислить его площадь полной
поверхности (S) и объем (V).
S= 2 R
2
 2
D
2
H ; V= R H
2
11. По известному радиусу вычислите объем и площадь поверхности шара.
S=4 R , V=
2
4 3
R
3
12. Составьте программу вычисления длин высот треугольника, у которого длины сторон a, b, c.
Примечание. Высотой треугольника называется перпендикуляр, опущенный из любой вершины треугольника на
противолежащую сторону или ее продолжение. Высота треугольника, опущенная на сторону а можно найти по формуле:
ha 
2 p(p  a)( p  b)( p  c)
a b c
, где p 
a
2
13. Составьте программу вычисления длин медиан треугольника, у которого длины сторон a, b, c.
Примечание. Медианой называется отрезок, соединяющий любую вершину треугольника с серединой противоположной
стороны. Медиану, соединяющую вершину треугольника А с серединой стороны а, можно найти по формуле:
ma 
1
2b 2  2c 2  a2
2
14. Составить программу вычисления давления столба жидкости плотностью
формулой P=g  H, где g=9,8
H


высотой H на дно сосуда, пользуясь
15. Составьте программу вычисления силы давления, действующей на пол со стороны стола массой m, если суммарная
2
площадь (S) опоры ножек стола 100 см , пользуясь формулой
P
gm
H
, где g=9,8
S

16. Составьте программу вычисления выталкивающей силы , действующей на тело объемом V, наполовину погруженное
в жидкость плотностью  , пользуясь формулой F=g  V.
17. Составьте программу вычисления потенциальной энергии тела массой м на высоте h относительно Земли, пользуясь
формулой E  =gmh.
18. Составьте программу вычисления механической работы, когда тело равномерно движется под действием
приложенной к нему силы, пользуясь формулой A=FS, где F – приложенная сила, а S – пройденный путь.
19. Ввести 4-значное число. Превратить его в 2-значное, отбросив первую и последнюю цифру.
20. С клавиатуры задается число К. Выбросить из записи К цифру, обозначающую сотни. Вывести полученное число на
экран.
Приготовьте для проверки файлы и листинги с вашими программами. Будьте готовы ответить на следующие вопросы:
1. Почему при записи формул на Паскале их "вытягивают" в линию? Почему знак умножения всегда выписывают явно?
2) Почему на Паскале аргумент функции всегда записывают в скобках (например, ln(5), а не ln5)
3) Укажите символы, буквы, составные символы:
^, Y, <>, +, *, R, k, $, !, ф
4) Что в списке можно рассматривать как идентификаторы:
FIO, ФИО, 33719, X, Y, >=, $, &, Summa, _Rezult
5) Какие идентификаторы удобнее использовать и почему:
13
klass1, Klass_1, summadohoda, SummaDohoda, nomerdoma, Nomer_Doma
6) Найдите в следующем списке зарезервированные слова:
X, Program, Y, Summa, MyMoney, Произведение, Vova, begin, end, if, repeat, Read.
7) В каких случаях надо использовать переменные:
• если в программе используется какое-то число,
• если в вычислениях какой-то операнд постоянно меняет свое значение,
• если операнд в выражении хотя бы раз меняет свое значение.
8) Какая структура программы правильна:
a) Program MyProgram;
b) Program MyFirst;
Begin
Begin
WriteLn(‘Привет!’);
X:=Y+100;
End.
End.
9) Какой из перечисленных разделов обязателен в программе?
• раздел Var
• раздел Const
• раздел Type
• раздел Begin ... End
• раздел Label
10) Для чего используется слово Uses?
11) В разделе процедур и функций описываются только стандартные процедуры?
• да,
• нет, только пользовательские,
• и стандартные, и пользовательские.
12) Найдите ошибки в программах:
a) Program Ошибки1;
Begin
Summa:=6+8;
End;
b) Program Ошибки2;
Begin
Var
X:integer;
X:=6+8;
Write(X);
End;
13) С чего начинается программа?
14) Как описываются переменные?
15) С чего начинается основная программа?
16) Как выглядит оператор вывода? Для чего он служит? Какое существует различие между выводом сообщения и
выводом значения переменной? Можно ли с помощью оператора вывода выполнить два действия? Если – да, то какие?
17) Что собой представляет оператор ввода? Для чего он служит? Как можно его использовать, чтобы осуществить
задержку экрана?
18) Как происходит присваивание переменной какого-либо значения? Как называется этот оператор?
19) Чем заканчивается программа?
20) Как сохранить программу на диске?
21) Как сохранить программу под другим именем? Зачем это бывает необходимо?
22) Как отрыть новый файл?
23) Как отрыть уже существующий файл?
24) Как выйти из программы?
25) Какие есть способы загрузки программы Турбо Паскаля в оперативную память?
26) Что такое процедура и чем она отличается от процедуры?
27) Что означает понятие "зарезервированное слово" ?
28) Какие имена можно использовать в языке TurboPascal?
29) Из каких частей состоит программа, написанная на языке TurboPascal?
30) Для чего необходим в программе раздел описаний?
31) Какие стандартные типы вам известны?
32) Какие типы относятся к порядковым.?
33) В чем различия между данными действительного и целого типов?
34) Назовите функции горячих клавиш F1-F10.
35) С помощью какой клавиши можно выйти в главное меню?
ГРАФИКА
Занятие 1: Графический режим. Инициализация графического режима. Построение точки, линии.
14
Стандартное состояние компьютера после запуска Турбо Паскаля – текстовый режим. Для того, чтобы использовать его
графические средства, программист должен "определенным образом инициировать режим работы дисплейного адаптера". В
графическом режиме работой дисплейного адаптера управляет графический драйвер.
Драйвер – это специальная программа, которая управляет техническими средствами компьютера. Для всех
существующих типов адаптеров фирма Borland разработала графические драйверы (они имеют расширение .bgi и находятся
на диске в одноименном подкаталоге).
Необходимые процедуры и функции для работы с графикой собраны стандартном модуле – Graph.
Инициализация графики производится с помощью процедуры InitGraph, которая имеет вид:
InitGraph(GraphDriver, GraphMode, Path);
где переменные GraphDriver и GraphMode имеют тип Integer, а переменная Path имеет тип String.
То, что записано в скобках, называется параметрами вызова процедуры (подробнее с данным вопросом мы ознакомимся
позднее в теме “Процедуры и функции”), а сейчас рассмотрим параметры GraphDriver, GraphMode и Path.
GraphDriver – целая переменная, определяющая тип драйвера. Процедура загружает драйвер в оперативную память и
переводит адаптер в графический режим работы. Тип драйвера должен соответствовать типу графического адаптера. Для
указания типа драйвера в модуле предопределены следующие константы:
CGA
1 EGA
3 EGAMono
5 HercMono
7 VGA
9
MCGA
2 EGA64
4 IBM8514
6 ATT400
8 PC3270
10
Detect = 0;
Целая переменная GraphMode задает режим работы графического адаптера. Многие адаптеры могут работать в
нескольких режимах. Например, переменная GraphMode в момент обращения к InitGraph может иметь одно из следующих
значений для адаптера VGA:
VGALo
= 0;
VGAMed
= 1;
VGAHi = 2;
Примечание: Более подробно о переменной Mode можно узнать в справочном руководстве по TurboPascal.
Теперь представьте такой вариант: Вам нужно написать программу на языке Pascal с использованием графических
возможностей компьютера. Хорошо, если это – программа для компьютера с известным адаптером. А если нет, как
действовать в этом случае? Выход один. Если нам неизвестен тип адаптера или программа должна работать с любым
адаптером, необходимо обращаться к InitGraph с запросом на автоматическое определение драйвера.
Это происходит следующим образом: переменной GraphDriver присваиваем значение detect. В этом случае компьютер
сам определит необходимый драйвер и подберет наилучший режим.
Program Primer1;
Uses
Graph;{Подключение модуля библиотеки графических процедур}
Var
GraphDriver,
GraphMode : integer;
Begin
GraphDriver := detect; {автоопределение типа драйвера }
InitGraph(GraphDriver, GraphMode, Path);
{Инициализация графического режима}
...
. . .СloseGraph;{Закрытие графического режима}
End.
Для получения графического изображения нужно заставить светиться заданным цветом определенную группу пикселей
(точек). Это можно делать в программе, но ваша работа тогда станет очень трудоёмкой. Чтобы облегчить труд программиста
существует модуль Graph, в котором содержиться 79 полезных процедур и функций, десятки стандартных констант и типов
данных (например, процедуры рисования линии, окружности и др.). Чтобы воспользоваться этим модулем нужно сначала его
подключить. Для этого в программе записывают строчку: Uses Graph.
Условно весь модуль Graph можно подразделить на несколько функциональных групп по выполняемым действиям.
Рассмотрим эти группы (внутри групп взяты основные функции, необходимые нам для первоначального ознакомления с
графикой):
1) Инициализация графики, подготовительные работы, управление цветом, закрытие режима:
InitGraph
установление (инициализация) графического режима работы
CloseGraph
завершение работы с графикой
DetectGraph
определение драйвера
FloodFill
заливка замкнутого контура выбранным типом и цветом палитры
RestoreCRTMode
возврат в текстовый режим
SetBkColor
выбор и установка нового цвета закраски фона
SetColor
выбор и установка нового текущего цвета
SetFillStyle
выбор и установка нового шаблона и цвета заполнения
2) Процедуры и функции для управления курсором и видеостраницами:
ClearDevice
очистка текущего устройства вывода
ClearViewPort
очистка текущего окна
GetMaxX
получение максимально доступной координаты по оси X
15
GetMaxY
GetPixel
GetX
GetY
MoveRel
MoveTo
получение максимально доступной координаты по оси Y
получение текущего цвета точки экрана
получить значение координаты X
получить значение координаты Y
переместить курсор из данной текущей точки на заданное приращение.
переместить курсор из данной текущей точки в заданную точку
3). Процедуры и функции для работы с "графическими примитивами":
Arc
Рисует дугу
Bar
Рисует полосу
Bar3D
Рисует трехмерную полосу
Circle
Рисует окружность
DrawPoly
Рисует многоугольник
Ellipse
Рисует эллиптическую дугу или эллипс
FillEllipse
Рисует заполненный эллипс
FillPoly
Заполняет многоугольник
Line, LineRel, LineTo
Рисует линию
Rectangle
Рисует прямоугольник
Sector
Рисует сектор эллипса
PutPixel
Рисует точку
4) Процедуры для работы с текстом
OutText
Вывод текста
OutTextXY
Вывод текста
Итак, для запуска графической системы нам необходимо:
1. Подключить модуль GRAPH – библиотеку графических процедур:
Uses Graph;
2. Установить графический режим с помощью двух переменных:
Var
GraphDriver, GraphMode: integer;
Begin
GraphDriver:=detect;
InitGraph(GraphDriver, GraphMode, '..\BGI');
{С этого момента все графические средства доступны пользователю}
{ тело программы }
CloseGraph;
End.
Задание. Наберите шаблон для программы, работающей в графическом режиме. Нам он понадобиться в дальнейшем.
Внимание! Прежде чем запустить программу на выполнение, необходимо на компьютере установить маршрут поиска
файлов каталога BGI. Для этого выполните следующее:
F10 – Options – Directories
В окне EXE&TPU directory набрать ..\BGI
Клавишей TAB перейти к окну Unit directories и набрать ..\BGI
Клавишей TAB перейти к ОК и нажать Enter.
Система координат в графическом режиме.
Любая информация при работе в графическом режиме на экране монитора представлена совокупностью светящихся
точек – пикселей, которые определяются цветом и координатами – положением относительно левого верхнего угла экрана с
координатами (0,0).
Дисплей может работать в нескольких графических режимах, каждому из которых соответствует свой формат
изображения, т. е. разрешающая способность (количество пикселей по горизонтали и вертикали) экрана и набор
используемых цветов.
Чтобы узнать максимальные координаты экрана в текущем режиме работы, воспользуемся стандартными функциями
GetMaxX и GetMaxY. Для этого наберите небольшую программу:
Uses Graph;
Var
GraphDriver, GraphMode: integer;
Begin
GraphDriver:=detect;
InitGraph(GraphDriver, GraphMode, ‘..\BGI’);
Writeln(GetMaxX, 'x', GetMaxY);
Readln;
16
CloseGraph;
End.
Примечание. Для нашего графического режима обычно значение максимальной координаты X равно 640 пикселям, а Y–
480 пикселям.
Чтобы точно строить изображение на экране, Вам нужно сначала нарисовать, как это должно выглядеть на бумаге. Для
этого начертите в тетради систему координат графического режима.
100
0
200
300
400
500
600 640
Ð
x
100
200
300
400
480
y
Итак, отсчет начинается с верхнего левого угла с координатами (0;0), значение Х – столбец, отсчет слева направо;
значение Y – строка, отсчет сверху вниз.
Чтобы строить изображение, нужно указать точку начала вывода. В графическом режиме нет видимого курсора, но есть
так называемый невидимый текущий указатель (Current Pointer). После инициализации графического режима указатель
стоит в точке (0;0). Чтобы переместить его в нужное место используют следующие процедуры:
MoveTo (X, Y), где переменные X, Y типа Integer – перемещает текущий указатель в точку с координатами (X,Y).
Например, MoveTo (200, 100)
MoveRel (dX, dY), где переменные dX, dY типа Integer – перемещает текущий указатель по горизонтали на расстояние,
равное dX пикселям, а по вертикали на расстояние, равное dY пикселям. (Relation (англ.) – относительно)
Например, если после выполнения предыдущей процедуры текущий указатель находится в точке (200, 100), то после
выполнения процедуры MoveRel (25, 150) он будет находится в точке с координатами (225, 250).
PutPixel(X, Y, Color), где переменные X, Y типа Integer, а Color типа Word – процедура выводит точку заданного цвета
Color в точку с координатами (X, Y).
Задание. Наберите в теле программы следующие процедуры PutPixel(300, 150, Red), PutPixel(45, 420, 9) и просмотрите
их действие.
Для задания цвета точки можно использовать как слово на английском языке, так и цифру из следующей таблицы:
Цвет
Цвет
Код
Black
черный
0
Blue
синий
1
Green
зеленый
2
Cyan
бирюзовый
3
Red
красный
4
Magenta
малиновый
5
Brown
коричневый
6
LightGray
светло-серый
7
DarkGray
темно-серый
8
LightBlue
ярко-голубой
9
LightGreen
ярко-зеленый
10
LightCyan
ярко-бирюзовый
11
LightRed
ярко-красный
12
LightMagenta
ярко-малиновый
13
Yellow
желтый
14
White
белый
15
Line (X1, Y1, X2, Y2), где переменные X1, Y1, X2, Y2 типа Integer – рисуется линия от точки (X1, Y1) до точки (X2, Y2).
LineTo (X, Y), где переменные X, Y типа Integer – рисуется линия из точки, где находится в данный момент курсор в
точку (X, Y).
LineRel (dX,dY), где переменные dX, dY типа Integer – рисуется линия из точки, где находится в данный момент курсор
(X, Y) в точку (X+dX,Y+dY).
Задание. Придумайте самостоятельно примеры с использованием всех процедур вычерчивания линий.
17
У Вас не получается нарисовать линии? В чем же причина? Если внимательно посмотреть на эти процедуры и сравнить
их с процедурой PutPixel, то можно заметить, что в них нет параметра, указывающего цвет рисования линии. В этом и других
аналогичных случаях цвет задается специальной процедурой.
SetColor (Color), где переменная Color типа Word - устанавливает текущий цвет для выводимых линий и символов.
Задания. 1. Исправьте свою программу так, чтобы процедуры рисовали линии различных цветов.
2. В начерченной ранее системе координат изобразите на чертеже точки:
А(150,450), В(100,350), С(350,350), D(300,450), E(200,350), F(200,50), L(250,40), K(200,20), M(300,250), X(175,400),
Y(225,400), Z(275,400).
3. Соедините точки, получая отрезки:
AB, BC, CD, AD, EK, KL, LF, FM, ME.
Какая фигура у Вас получилась?
4. Напишите программу, рисующую эту фигуру, по вашему рисунку.
Внимание! Следите за порядком на дискете. Организуйте каталог A:\GRAPHIKA, где будут находиться файлы всех
Ваших программ изучаемой темы.
Занятие 2: Построение дуги, окружности, прямоугольника, эллипса.
Рассмотрим подробнее процедуры и функции, с которыми мы будем работать.
Circle (X, Y, R), где переменные X, Y, R типа Word – Рисуется окружность в центре (X, Y) c радиусом R.
(X,Y)
R
Arc (X, Y, BegA, EndA, R), где переменные X, Y, BegA, EndA, R типа Word – Рисуется дуга (часть окружности) с
координатами центра (X, Y), с радиусом R, которая начинается от угла BegA до угла EndA в полярной системе координат.
Например, чтобы начертить дугу (смотри рисунок) от окружности радиуса 50 пикселей и координатами центра (100,
230) надо набрать команду: Arc (100, 230, 45, 135, 50)
90
0
135
0
180
0
45
0
3600
0
270
Нетрудно заметить, что если мы будем чертить дугу от 0 до 360, то начертим окружность.
Ellipse(X, Y, BegA, EndA , хR, yR), где переменные X, Y переменные типа integer, а BegA, EndA, хR, yR типа Word –
рисуется дуга эллипса, у которого центр находится в точке (X, Y), BegA – начальный угол, EndA – конечный угол, хR –
радиус по горизонтальной оси, yR – радиус по вертикальной оси.
Например, чтобы начертить дугу ABC от эллипса надо дать такую команду Ellipse(150, 200, 30, 240, 80, 50).
y
E
B
A
yR
xR
D
0
C
18
x
Вполне очевидно, чтобы начертить весь эллипс надо определить углы черчения дуги от 0 до 360. А также, чтобы
“вытянуть” эллипс вверх надо радиус по вертикальной оси сделать больше, чем по горизонтальной (если радиусы будут
равны, то будет начерчена дуга окружности или сама окружность).
Rectangle (X1, Y1, X2, Y2), где переменные X, Y переменные типа integer – рисуется прямоугольник, X1, Y1 –
координаты верхнего левого угла, X2, Y2 – координаты нижнего угла.
(X1,Y1)
(X2,Y2)
SetLineStyle (Type, Pattern, Thick), где переменные X, Y переменные типа Word – устанавливает стиль линий. Здесь
Type – тип линии, Pattern – образец линии, Thick – толщина линии. Тип линии может быть задан с помощью одной из
следующих констант:
0 – непрерывная линия
1 – линия из точек
2 – линия из точек и тире
3. – пунктирная линия
4 – линия,задаваемая пользователем
Параметр Pattern учитывается только для линий, вид которых определяет пользователь. Пользователь таким образом
может задать линии в виде отрезков длиной до 16 пиксель.
Толщина линий.
1 – толщина в один пиксель
3 – толщина в три пикселя
Задание. Теперь, пользуясь этими процедурами, дорисуйте кораблик (например, иллюминаторы, якорь и др.), а также
придумайте и нарисуйте предметы вокруг него, чтобы получилась картинка. Покажите результат работы в конце занятия
учителю для оценки.
Установка стиля и цвета закраски. Закрашивание фигур.
После того как Вы нарисовали картинку, у Вас, верно, возникло желание ее раскрасить. Для этого есть различные
способы. Познакомимся с одним из них – “заливкой” замкнутых площадей различными видами заполнения. Для этого
существуют две процедуры SetFillStyle и FloodFill.
SetFillStyle (Pattern, Color), где переменные Pattern, Color типа Word – определяет стиль заполнения и цвет заполнения.
Значения Pattern можно взять из следующей таблицы:
Стандартные стили заполнения
Константа
Код
Маска-заполнение
EmptyFill
0
цветом фона
SolidFill
1
текущим цветом
LineFill
2
символами - -, цвет – Color
LtSlashFill
3
символами //норм. толщины, цвет – Color
SlashFill
4
символами //удвоенной толщины, цвет – Color
BkSlashFill
5
символами \\удвоенной толщины, цвет – Color
LtBkSlashFill
6
символами \\норм. толщины, цвет – Color
HatchFill
7
вертикально-горизонтальная штриховка тонкими линиями, цвет – Color
XhatchFill
8
штриховка крест-накрест по диагонали “редкими” тонкими линиями, цвет –
Color
InterLeaveFill
9
штриховка крест-накрест по диагонали “частыми” тонкими линиями, цвет –
Color
WideDotFill
10
“редкие” точки
CloseDotFill
11
“частые” точки
Например, если мы употребили процедуру
SetFillStyle (WideDotFill, Red) или SetFillStyle (10, 4),
то выбрали стиль закраски “редкими” точками красного цвета
Теперь же, когда Вы указали компьютеру ЧЕМ Вы будете закрашивать (стиль и цвет), можно указать, ЧТО Вы будете
закрашивать. Для этого существует процедура
FloodFill(X, Y, ColorBorder), где X, Y переменные типа integer, а Border – переменная типа word -процедура, которая
позволяет заполнить замкнутую область выбранным стилем и цветом закраски. Необходимо только выполнить несколько
требований:
19
• первые два параметра (X, Y) являются координатами так называемой “затравочной” точки, т. е. точки, лежащей
обязательно внутри закрашиваемой области;
• ColorBorder – параметр, обозначающий цвет, которым нарисована закрашиваемая фигура (так называемый цвет
“бордюрчика”);
• фигура должна быть начерчена одним цветом;
• фигура должна быть замкнута.
Например, пусть следующая фигура начерчена синим цветом
180
200
Ä
(x,y
)
Чтобы закрасить ее выбранным стилем и цветом (“редкие” точки красного цвета, см. выше) нужно дать команду
FloodFill(180, 200, 1).
Нужно представить, как компьютер закрашивает фигуру. Первое, что он делает – это находит точку, от которой он
начинает заливку и заливает точку за точкой до тех пор, пока не встретит заданный цвет. Таким образом, если фигура
замкнутая, то, разливаясь во все стороны, он натыкается на “бордюрчик” и фигура становится закрашенной. Но, если в
контуре фигуры есть хотя бы один пиксель, закрашенный другим цветом, замкнутость фигуры нарушается и краска
выливается через эту дырочку и заливает не ту область, а иногда и весь экран.
Чтобы Вас уберечь от многих ошибок и, соответственно, сохранить Ваше время, хочу посоветовать относиться к
рисованию фигур и их закраске, как к аппликации. Т. е. если нарисовали фигуру, постарайтесь сразу же ее закрасить, а также
рисовать фигуры, начиная от самых больших и заканчивая самыми маленькими.
SetBkColor(Color), где переменная Color типа Word – процедура, устанавливающая цвет фона.
Примечание. После замены цвета фона на любой, отличный от черного, Вы не сможете более использовать цвет 0 как
черный, он будет заменяться на цвет фона, т.к. процедуры модуля Graph интерпретируют цвет с номером 0 как цвет фона.
ClеarDeviсe – процедура, которая очищает экран и устанавливает курсор в позицию (0,0).
GraphDefaults – cбрасывает заданные пользователем параметры графического режима и устанавливает исходные
(определяемые по умолчанию при запуске процедуры InitGraph).
Задание. Раскрасьте кораблик, используя различные стили и цвета. Покажите учителю полученную картинку и листинг
программы.
Занятие 3: Вывод текста.
Описываемые ниже стандартные процедуры подддерживают вывод текстовых сообщений в графическом режиме. Это
не одно и то же, что использование процедур Write и Writeln. Дело в том6 что специально для графического режима
разработаны процедуры, обеспечивающие вывод сообщений различными шрифтами в горизонтальном или вертикальном
направлении, с изменением размеров и т.д.
OutText('текст'), где переменная 'текст' типа String – выводит текстовую строку, начиная с текущего положения
указателя. При горизонтальном направлении вывода указатель смещается в конец выведенного текста, при вертикальном –
не меняет своего положения. Строка выводится в соответствии с установленным стилем и выравниванием.
Примечание. Если текст выходит за границы экрана, то при использовании штриховых шрифтов он отсекается, а в
случае стандартного шрифта не выводится.
OutTextXY(X, Y, 'текст'), где переменные X, Y типа Integer , а 'текст' типа String – выводит строку 'текст', начиная с
точки с координатами X, Y. Указатель не меняет своего положения.
Например, после применения процедуры OutTextXY(100, 50, 'Grafika in Turbo Pascal') на экране будет высвечена строка
Grafika in Turbo Pascal, начиная с точки с координатами (100,50).
SetTextStyle(Font; Direct; Size), где переменные Font и Direct типа word, а Size типа Integer – устанавливает стиль
текстового вывода на графический экран. Здесь переменная Font указывает на код (номер) шрифта, Direct – код направления,
а Size – код размера шрифта.
Для указания кода шрифта можно использовать следующие константы:
Номер
Описание
0
точечный шрифт 8х8
1
утроенный шрифт
2
уменьшенный шрифт
20
3
прямой шрифт
4
готический шрифт
5
“рукописный” шрифт
6
одноштриховый шрифт типа Courier
7
красивый наклонный шрифт типа Times Italic
8
шрифт типа Times Roman
9
шрифт типа Courier увеличенного размера
10
крупный двухштриховый шрифт
Cреди этих шрифтов только DefaultFont (код 0) является матричным шрифтом, т.е. его символы создаются из матриц 8х8
пикселей. Все остальные шрифты – векторные, их элементы формируются как совокупность векторов определенного
направления и размера.
Примечание. Русскоязычные сообщения можно выводить в графическом режиме с помощью шрифта DefaultFont.
Для задания направления выдачи текста используют следующие константы:
0 – слева направо
1 – снизу вверх
Размер выводимых символов задается параметром Size, который имеет диапазон от 1 до 10 (матричный шрифт от 1 до
32).
SetTextJustify (Horiz,Vert), где переменные Horiz и Vert типа word – задает выравнивание текста по отношению к
текущему положению указателя или к заданным координатам. Здесь Horiz – горизонтальное выравнивание, а Vert –
вертикальное выравнивание.
Выравнивание определяет как будет размещаться текст – левее или правее указанного места, выше, ниже или по центру.
Можно использовать следующие константы:
Для Horiz:
LeftText = 0 (указатель слева от текста);
CenterText = 1 (симметрично слева и справа);
RightText = 2 (указатель справа от текста);
Для Vert:
BottonText = 0 (указатель снизу от текста);
CenterText = 1 (симметрично снизу и сверху);
TopText = 2 (указатель сверху от текста);
Обратите внимание на неудачные имена констант. Если Вам надо расположить текст справа от заданных координат
(процедура OutTextXY), то нужно задать константу LeftText, что в переводе с английского означает “Левый текст”.
SetUserCharSize (X1, X2, Y1, Y2), где переменные X1, X2, Y1, Y2 типа word – изменяет размер выводимых символов в
соответствии с заданными пропорциями. Пропорции задают масштабный коэффициент, показывающий во сколько раз
увеличится ширина и высота выводимых символов по отношению к стандартно заданным значениям. Коэффициент по
горизонтали находится как отношение X1 к X2, по вертикали Y1, Y2. Например, чтобы удвоить ширину символов,
необходимо задать Х1=2 и Х2=1. Стандартный размер символов устанавливается процедурой SetTextStyle, которая отменяет
предшествующее ей обращение к SetUserCharSize.
GraphDefaults – cбрасывает заданные пользователем параметры графического режима и устанавливает исходные
(определяемые по умолчанию при запуске процедуры InitGraph).
Задание. Дайте название своему рисунку, используя изученные процедуры.
Решение задач.
Выберите с учителем задачи для решения из предложенного ниже списка:
1. Построить и подписать вершины
а) треугольника с вершинами (200,200), (250,200), (180,270);
б) прямоугольника с вершинами (80,80), (170, 80), (170, 50), (80,150);
2. Нарисовать человечка и подписать его части тела.
3. Составьте программу черчения на экране прямой, отрезка, луча и угла таким образом, чтобы каждый объект
появлялся после нажатия клавиши <Enter>. Предыдущий объект должен стираться. Подписывайте каждый раз выводимый
объект.
4. Составьте программу черчения на экране треугольника, прямоугольника и круга таким образом, чтобы каждый объект
появлялся после нажатия клавиши <Enter>. Предыдущий объект должен стираться. Подписывайте каждый раз выводимый
объект.
5. Написать на экране введенную строку пятью различными стилями.
6. Написать программу для вычерчивания на экране своего имени с помощью символа «*».
7. Построите на экране все виды углов и подпишите. (Углы бывают острыми, тупыми, прямыми и развернутыми.)
8. Начертить на экране все известные Вам графические объекты.
9. Построить снеговика, разукрасить его по своему вкусу. Дайте картинке название.
10. Нарисовать 3 карандаша разного цвета.
Занятие 4. Процедуры рисования закрашенных фигур.
Продолжим знакомиться с графическими процедурами.
21
Bar (x1,y1,x2,y2), где переменные X1, X2, Y1, Y2 типа Integer – рисуется закрашенный установленным ранее стилем и
цветом прямоугольник.Координаты точек указываются аналогично процедуре рисования незакрашенного прямоугольника.
Bar3D (x1,y1,x2,y2, Depth, Top), где переменные X1, X2, Y1, Y2 типа Integer, Depth типа Word, а Top типа Boolean –
рисуется параллелепипед, закрашенный текущим стилем и цветом. Здесь переменные X1, X2, Y1, Y2 являются координатами
левого верхнего и правого нижнего углов передней грани, Depth – ширина боковой грани (отсчитываются по горизонтали),
Top – признак включения верхней грани: TopОn = true – верхняя грань изображается, TopОff = false – верхняя грань не
изображается.
PieSlice (X, Y, BegA, EndA, R), где переменные X, Y типа Integer, а BegA, EndA, R типа Word – строит сектор круга,
закрашенный текущим стилем и цветом заполнения с учетом масштабов по осям. Здесь X, Y – координаты центра сектора
круга, BegA – начальный угол сектора, отсчитываемый против часовой стрелки от горизонтальной оси, направленной
вправо, EndA – конечный угол сектора, отсчитываемый против часовой стрелки от горизонтальной оси, направленной
вправо, R – радиус сектора.
FillEllipse (X, Y, Rx, Ry), где X, Y, Rx, Ry являются переменными типа Integer обводит линией и заполняет эллипс.
Здесь X, Y - координаты центра эллипса, Rx, Ry – горизонтальный и вертикальный радиусы эллипса. Эллипс обводится
линией, заданной процедурами SetLineStyle и SetColor, и заполняется с использованием параметров, установленных
процедурой SetFillStyle.
Sector (X, Y, BegA, EndA, Rx, Ry), где переменные X, Y типа Integer, а BegA, EndA, Rx, Ry типа Word – вычерчивает и
заполняет эллипсный сектор. Здесь X, Y - координаты центра эллипса, BegA, EndA - начальный и конечный углы эллипсного
сектора, Rx, Ry - горизонтальный и вертикальный радиусы эллипса.
Задачи на изученную тему:
1. Составьте программу рисования часов типа “кукушка”.
12
9
3
6
2. Нарисуйте детскую картинку. Постройте из закрашенных пересекающихся окружностей рисунок облака.
3. Выполните построение следующей картинки.
22
4. Составьте программу рисования скворечника.
5. Нарисовать новогоднюю елку.
6. Постройте избушку на курьих ножках.
7. Составьте программу рисования павлина.
8. Составьте программу рисования фотоаппарата.
9. Постройте домик, разукрасьте его по своему вкусу.
10. Составьте программу рисования компьютера.
11. Составьте программу рисования веера.
12. Составьте программу рисования предмета, придуманного Вами с использованием рассмотренных процедур.
Для любопытных. Окно в графическом режиме. Решение задач.
SetViewPort (X1, Y1, X2, Y2, ClipOn), где переменные X1, Y1, X2, Y2 типа Integer, а ClipOn типа Boolean –
устанавливает прямоугольное окно на графическом экране. Здесь X1, Y1 - координаты левого верхнего угла, X2, Y2 координаты правого нижнего угла прямоугольника, а ClipOn - выражение, определяющее “отсечку” не умещающихся в окне
элементов изображения. Если ClipOn имеет значение True, то элементы изображения отсекаются, в противном случае
границы окна игнорируются. Для управления этим параметром можно использовать уже определенные в модуле константы:
Const
ClipOn = True; {Включить отсечку}
ClipOff = False;
{Не включать отсечку}
ClipOff
ClipOn
ClearViewPort - очищает графическое окно, а если окно не определено к этому моменту, - весь экран. При очистке окно
заполняется цветом с номером 0 и указатель перемещается в левый верхний угол окна.
Задачи
1. Составьте программу, которая бы рисовала несколько графических объектов, затем устанавливала прямоугольное
окно (параметры процедуры задает пользователь) и очищала затем графическое окно.
2. Составьте программу, которая бы рисовала несколько графических объектов, затем устанавливала прямоугольное
окно по Вашему желанию.
3. Составьте программу, которая бы рисовала несколько графических объектов, затем устанавливала прямоугольное
окно и очищала весь экран кроме элементов, попавших в графическое окно.
4. Составьте программу, которая бы рисовала несколько графических объектов, затем устанавливала несколько
прямоугольных окон с параметрами по Вашему желанию. Прокомментируйте использованные процедуры в программе.
5. Составьте программу, которая бы рисовала несколько графических объектов, затем очищала графическое окно и
снова рисовала графические объекты.
6. Составьте программу, которая рисовала бы в графическом окне фигуру (окружность, квадрат, треугольник),
подписывала ей название и после нажатия на клавишу <Enter> выводила в окне другую фигуру с названием и т.д. (3-5 смен
фигур).
7. Запросите у пользователя ответ на вопрос: надо ли делать отсечку? Напишите программу рисования концентрических
окружностей и графического окна с учетом ответа пользователя.
23
8. Запросите у пользователя координаты для вывода на экран двух графических окон. Напишите программу рисования
вложенных квадратов и графических окон с учетом ответа пользователя.
Будьте готовы ответить на следующие вопросы:
1. Какие существуют команды для редактирования текста программы? Как ими пользоваться?
2. Что такое драйвер? Где они находятся?
3. Что значит инициализировать графический режим? Что для этого нужно сделать?
4. Что значит присвоить переменной типа драйвера значение Detect? Как в этом случае будет происходить
инициализация графики?
5. Где находятся стандартные графические функции и процедуры? Что нужно сделать, чтобы ими воспользоваться?
6. Какие известные Вам текстовые процедуры можно использовать в графическом режиме, а какие – нельзя?
7. Назовите процедуры очистки экрана в текстовом и графическом режиме.
8. Существует ли в графическом режиме курсор? Если существует, есть ли у него название?
9. С помощью какой процедуры можно поменять цвет рисования линии?
10. С помощью какой процедуры можно поменять стиль закраски? Что обозначают параметры этой процедуры?
11. Как Вы думаете, зачем нужны три процедуры рисования линии? Какой процедурой чаще всего пользовались Вы?
Попробуйте предположить, в каком случае Вам понадобятся другие?
12. Какие основные ошибки Вы допускали при инициализации графики?
13. Каким параметром в записи процедур всегда стоит радиус?
14. Какие параметры и в каком порядке нужно задать, чтобы нарисовать дугу?
15. Какие параметры и в каком порядке нужно задать, чтобы нарисовать окружность?
16. Какие параметры и в каком порядке нужно задать, чтобы нарисовать эллипс?
17. Какие параметры и в каком порядке нужно задать, чтобы нарисовать прямоугольник?
18. Какие параметры и в каком порядке нужно задать, чтобы нарисовать параллепипед?
19. Какие параметры и в каком порядке нужно задать, чтобы нарисовать сектор круга?
20. Какие параметры и в каком порядке нужно задать, чтобы нарисовать сектор эллипса?
21. Можно ли начертить пунктирную линию? Какие стандартные линии предоставляет Вам среда программирования?
Как называется эта процедура? Как к ней обратиться?
22. Можно ли нарисовать толстую линию? Если можно, то объясните как?
23. Какими процедурами и в каком порядке нужно воспользоваться, чтобы закрасить фигуру?
24. Каким требованиям должна соответствовать фигура, чтобы она закрасилась без ошибок?
25. Какие есть графические процедуры вывода текста на экран? Как можно изменить шрифт букв? Какие еще есть
процедуры, управляющие выводом текста? Для чего они нужны?
ОПЕРАТОРЫ УСЛОВИЯ И ВЫБОРА
Занятие 1. Разветвляющиеся алгоритмы. Оператор условия If.
Разветвляющиеся алгоритмы
До сих пор Вы использовали линейные алгоритмы, т.е. алгоритмы, в которых все этапы решения задачи выполняются
строго последовательно. Сегодня Вы познакомитесь с разветвляющимися алгоритмами.
Определение. Разветвляющимся называется такой алгоритм, в котором выбирается один из нескольких возможных
вариантов вычислительного процесса. Каждый подобный путь называется ветвью алгоритма.
Признаком разветвляющегося алгоритма является наличие операций проверки условия. Различают два вида условий –
простые и составные.
Простым условием (отношением) называется выражение, составленное из двух арифметических выражений или двух
текстовых величин (иначе их еще называют операндами), связанных одним из знаков:
<
- меньше, чем...
>
- больше, чем...
<=
- меньше, чем... или равно
>=
- больше, чем... или равно
<>
- не равно
=
- равно
Например, простыми отношениями являются следующие:
x-y>10;
k<=sqr(c)+abs(a+b);
9<>11;
‘мама’<>‘папа’.
В приведенных примерах первые два отношения включают в себя переменные, поэтому о верности этих отношений
можно судить только при подстановке некоторых значений:
если х=25, у=3, то отношение x-y>10 будет верным, т.к. 25-3>10
если х=5, у=30, то отношение x-y>10 будет неверным, т.к. 5-30<10
Проверьте верность второго отношения при подстановке следующих значений:
а) k=5, a=1, b=-3, c=-8
b) k=65, a=10, b=-3, c=2
Определение. Выражения, при подстановке в которые некоторых значений переменных, о нем можно сказать истинно
(верно) оно или ложно (неверно) называются булевыми (логическими) выражениями.
Примечание. Название “булевые” произошло от имени математика Джорджа Буля, разработавшего в XIX веке булевую
логику и алгебру логики.
24
Определение. Переменная, которая может принимать одно из двух значений: True (правда) или False (ложь), называется
булевой (логической) переменной. Например,
К:=True;
Flag:=False;
Second:=a+sqr(x)>t
Рассмотрим пример.
Задача. Вычислить значение модуля и квадратного корня из выражения (х-у).
Для решения этой задачи нужны уже знакомые нам стандартные функции нахождения квадратного корня - Sqr и модуля
- Abs. Поэтому Вы уже можете записать следующие операторы присваивания:
Koren:=Sqrt(x-y);
Modul:=Abs(x-y).
В этом случае программа будет иметь вид:
Program Znachenia;
Uses
Crt;
Var
x, y : integer;
Koren, Modul : real;
Begin
ClrScr;
write (‘Введите значения переменных х и у через пробел ‘);
read (x, y);
Koren:=Sqrt(x-y);
Modul:=Abs(x-y).
write (‘Значение квадратного корня из выражения (х-у) равно ‘);
write (‘Значение модуля выражения (х-у) равно ‘);
readln;
End.
Казалось бы задача решена. Но мы не учли области допустимых значений для нахождения квадратного корня и модуля.
Из курса математики Вы должны знать, что можно найти модуль любого числа, а вот значение подкоренного выражения
должно быть неотрицательно (больше или равно нулю).
Поэтому наша программа имеет свою допустимую область исходных данных. Найдем эту область. Для этого запишем
неравенство х-у>=0 и решив его получим х>=у. Значит, если пользователем нашей программы будут введены такие числа,
что при подстановке значение этого неравенства будет равно True, то квадратный корень из выражения (х-у) извлечь можно.
А если значение неравенства будет равно False, то выполнение программы закончится аварийно.
Задание. Наберите текст программы. Протестируйте программу со следующими значениями переменных и сделайте
вывод.
а) х=23, у=5;
б) х=-5, у=15;
в) х=8, у=8.
Каждая программа, насколько это возможно, должна осуществлять контроль за допустимостью величин, участвующих в
вычислениях. Здесь мы сталкиваемся с разветвлением нашего алгоритма в зависимости от условия. Для реализации таких
условных переходов в языке Паскаль используют операторы If и Else, а также оператор безусловного перехода Goto.
Рассмотрим оператор If.
Для нашей задачи нужно выполить следующий алгоритм:
если х>=у,
то вычислить значение квадратного корня,
иначе выдать на экран сообщение об ошибочном введении данных.
Запишем его с помощью оператора If. Это будет выглядеть так.
if x>=y
then
Koren:=Sqr(x-y)
else
write (‘Введены недопустимые значения переменных‘);
Теперь в зависимости от введенных значений переменных х и у, условия могут выполняться или не выполняться.
В общем случае полная форма конструкции условного оператора имеет вид:
if <логическое выражение>
then
<оператор 1>
else
<оператор 2>
Условный оператор работает по следующему алгоритму.
Сначала вычисляется значение логического выражения, расположенного за служебным словом IF. Если его результат
истина, выполняется <оператор 1>, расположенный после слова THEN, а действия после ELSE пропускаются; если
результат ложь, то, наоборот, действия после слова THEN пропускаются, а после ELSE выполняется <оператор 2>.
25
Управляющая структура if может показаться негибкой, так как выполняемые действия могут быть описаны только
одним оператором. Иногда может потребоваться выполнение последовательности операторов. В этом случае хотелось бы
заключить всю последовательность в воображаемые скобки. В Паскале предусмотрен этот случай.
Если в качестве оператора должна выполниться серия операторов, то они заключаются в операторные скобки begin-end.
Конструкция Begin ... End называется составным оператором.
if <логическое выражение>
then
begin
оператор 1;
оператор 2;
...
end
else
begin
оператор 1;
оператор 2;
...
end;
Определение. Составной оператор - объединение нескольких операторов в одну группу. Группа операторов внутри
составного оператора заключается в операторные скобки (begin-end).
begin
оператор 1;
оператор 2;
end;
С учетом полученных знаний преобразуем нашу программу.
Program Znachenia;
Uses
Crt;
Var
x, y : integer;
Koren, Modul : real;
Begin
ClrScr;
write (‘Введите значения переменных х и у через пробел ‘);
read (x, y);
if x>=y
then
begin
Koren:=Sqr(x-y)
Modul:=Abs(x-y)
write (‘Значение квадратного корня из выражения (х-у) равно ‘);
write (‘Значение модуля выражения (х-у) равно ‘);
end
else
write (‘Введены недопустимые значения переменных‘);
readln;
End.
Составным оператором является и такой оператор
begin
S:=0;
end.
Cимвол “;” в данном случае разделяет оператор присваивания S:=0 и пустой оператор.
Пустой оператор не влечет никаких действий и в записи программы никак не обозначается.
Например, составной оператор
begin
end.
включает лишь один пустой оператор.
Если Вы обратили внимание, программа на языке Паскаль всегда содержит один составной оператор – раздел
операторов программы.
Внимание! Перед служебным словом Else разделитель (точка с запятой) не ставится.
Отметим, что большинство операторов в программах на языке Паскаль заканчиваются точкой с запятой, но после
некоторых операторов точка с запятой не ставится. Сформулируем общие правила употребления точки с запятой:
1. Каждое описание переменной и определение константы заканчиваются точкой с запятой.
26
2. Каждый оператор в теле программы завершается точкой с запятой, если сразу за ним не следуют
зарезервированные слова End, Else, Until.
3. После определенных зарезервированных слов, таких, как Then, Else, Var, Const, Begin, никогда не ставится точка с
запятой.
Рассмотрим еще один пример.
Задача. Вывести на экран большее из двух данных чисел.
Program Example1;
Var
x, y : integer; {вводимые числа}
Begin
writeln(‘Введите 2 числа ‘); {вводим два целых числа через пробел}
readln(x,y);
if x>y
then
writeln (x) {если х больше y, то выводим х}
else
writeln (y) {иначе выводим y}
readln;
End.
Можно также использовать и сокращенную (неполную) форму записи условного оператора. Эта форма используется
тогда, когда в случае невыполнения условия ничего делать не надо.
Неполная форма условного оператора имеет следующий вид.
if <логическое выражение>
then
<оператор>
Тогда если выражение, расположенное за служебным словом IF. в результате дает истину, выполняются действия после
слова THEN, в противном случае эти действия пропускаются.
Задача. Составить программу, которая, если введенное число отрицательное меняет его на противоположное.
Program Chisla;
Var
x : integer; {вводимое число}
Begin
writeln(‘Введите число ‘); {вводим целое число}
readln(x);
if x<0
then
x:=-x;
writeln (x);
readln;
End.
Выберите из предложенного ниже списка задачи для самостоятельного решения.
1. Если целое число М делится нацело на целое число N, то вывести на экран частное от деления, в противном случае
вывести сообщение М на N нацело не делится.
2. Запишите условный оператор, в котором значение переменной с вычисляется по формуле a+b, если а – нечетное и a*b,
если а – четное.
3. Вычислить значение функции:
x 2  5, x  3
у= 
x  8,x  3
4. Написать программу для подсчета суммы только положительных из трех данных чисел.
5. Даны три числа. Написать программу для подсчета количества чисел, равных нулю.
6. Напишите программу, упростив следующий фрагмент программы:
if a>b then c:=1;
if a>b then d:=2;
if a<=b then c:=3;
if a<=b then d:=4.
7. Каким будет значение переменной а после выполнения операторов:
a:=3;
if a<4
then
begin
Inc(a,2);
27
Inc(a,3);
end;
8. Найти количество положительных (отрицательных) чисел среди четырех целых чисел A, B, C, D.
9. Составьте программу, которая уменьшает первое введенное число в пять раз, если оно больше второго введенного
числа по абсолютной величине.
10. Для данного значения X вычислить значение функции, которая определяется следующим образом:
Y=sin(x), если x >=1
Y=cos(x), если x < 1
11. Определить является ли введённое число чётным.
12. Компьютер спрашивает: "Что сегодня нужно всем?" и если получает ответ ЭВМ, то пишет "Ну, конечно ЭВМ!",
иначе "Это тоже нужно всем, но нужнее ЭВМ!"
13. Написать программу, по которой компьютер приветствовал бы только своего хозяина, а при попытке ввести какоелибо другое имя спрашивал бы: "А где (например) Вася?"
14. Написать программу, определяющую, есть ли в введенном числе дробная часть.
15. Написать программу, рисующую круг в случае введения пользователем числа 1 и квадрат во всех других случаях.
Занятие 2. Логический тип данных. Логические операции not, and, or. Нахождение значений
логических выражений. Самостоятельная работа.
Логический тип данных
Переменные логического типа описываются посредством идентификатора Boolean. Они могут принимать только два
значения – False (ложь) и True (истина). Описываются они также в разделе описания переменных.
Var
Flag : Boolean;
Переменные логического типа обычно получают значения в результате выполнения операций сравнения и
математических операций (рассматривались в предыдущем занятии), а также с помощью специфических булевых операций.
В языке Турбо Паскаль имеются логические операции, применяемые к переменным логического типа. Это операции not,
and, or и хor. В этой теме Вы рассмотрите три логические операции. Обозначения и результаты этих операций приведены в
таблице. Рассмотрите ее.
Значения операндов
Результат операции
X
Y
not X
X and Y
X or Y
False
False
True
False
False
False
True
True
False
True
True
False
False
False
True
True
True
False
True
True
Операция not (не) имеет один операнд и образует его логическое отрицание. Результат операции not есть False, если
операнд истинен, и True, если операнд имеет значение ложь. Так,
not True  False (неправда есть ложь)
not False  True (неложь есть правда)
Результат операции and (и) есть истина, только если оба ее операнда истинны, и ложь во всех других случаях.
Результат операции or (или) есть истина, если какой-либо из ее операндов истинен, и ложен только тогда, когда оба
операнда ложны.
Задание. Попробуйте определить значение булевых операций для высказываний:
1. Школьник на зимних каникулах остается дома или уезжает куда-либо отдыхать.
2. Филипп Киркоров является певцом и комбайнером.
3. Школьниками являются мальчики и девочки.
Придумайте и запишите в тетрадь три подобных высказывания.
Логические операции, операции отношения и арифметические операции часто встречаются в одном выражении. При
этом отношения, стоящие слева и справа от знака логической операции, должны быть заключены в скобки, поскольку
логические операции имеют более высокий приоритет. Вообще принят следующий приоритет операций:
• not
• and, *, /, div, mod
• or, +, • операции отношения.
Примечание. Логическую операцию and еще называют логическим умножением, а логическую операцию or - логическим
сложением.
Кроме того, порядок выполнения операций может изменяться скобками. Например, в логическом выражении расставим
порядок действий
4
3
2
1
A or B and not (A or B)
Сначала выполняется заключенная в скобки операция or, а затем операции not, and, or. Если подставить вместо
переменных А и В значения True и False, то, используя уже рассмотренный порядок действий, получим значение всего
выражения равное True.
Задание. Запишите в тетрадь и вычислите значения выражений при a=10, b=20, c=true, d=false:
28
а) (a>5) and (b>5) and (a<20) and (b<30);
b) not (a<15) or not (b<30);
c) c or d and (b=20);
Внимание! В языке Паскаль нет возможности ввода логических данных с помощью оператора read. Однако
предусмотрен вывод значений переменных логического типа с помощью оператора write.
Например, после выполнения оператора write (5>2) на экран будет выведено True.
Самостоятельная работа
Выберите с учителем задание для выполнения самостоятельной работы из ниже предложенных упражнений.
1. Вычислите значения выражения:
а) sqr(x)+sqr(y)<=4 при x=0.3, y=-1.6;
б) k mod 7 = k div5-1
при k=15;
в) odd(trunc(10*p)) при p=0.182;
г) not odd(n)
при n=0;
д) t and (p mod 3=0) при t=true, p=101010;
е) (x*y<>0) and (y>x)
при x=2, y=1;
ж) (x*y<>0) or (y>x)
при x=2, y=1;
з) a or (not b)
при a=False, b=True;
2. Записать на Паскале отношение, истинное при выполнении указанного условия и ложное в противном случае:
а) целое k делится на 7;
2
б) уравнение ax  bx  c  0,(a  0) не имеет вещественных корней;
в) точка (х, у) лежит вне круга радиуса R с центром в точке (1,0);
г) натуральное число N является квадратом натурального числа;
д) 0<x<1;
е) x=max(x,y,z);
ж) x  max(x, y,z) (операцию not не использовать)ж
з) хотя бы одна из логических переменных а и b имеет значение True;
и) обе логические переменные а и b имеют значение True.
3. Указать порядок выполнения операций при вычислении выражений:
а) a and b or not c and d;
б) (x>=0) or not c and d.
4. Вычислить следующие выражения при a=True, b=False:
а) a or b and not a;
б) (a or b) and not a;
в) not a and b;
г) not (a and b)
5. Записать на Паскале выражение, истинное при выполнении указанного условия и ложное в противном случае:
а) х принадлежит отрезку [0, 1];
б) х лежит вне отрезка [0, 1];
в)* х принадлежит отрезку [2, 5] или [-1, 1];
г)* х лежит вне отрезков [2, 5] и [-1, 1];
д) каждое из чисел х, у, z положительно;
ж) ни одно из чисел х, у, z не является положительным;
з) только одно из чисел х, у, z положительно;
и) логическая переменная а имеет значение True, логическая переменная b имеет значение False;
к)* год с порядковым номером у является високосным (год високосный, если его номер кратен 4, однако из кратных 100
високосными являются лишь кратные 400, например, 1700, 1800 и 1900 – невисокосные годы, 2000 – високосный).
6. Нарисовать на плоскости (х,у) область, в которой и только в которой истинно указанное выражение:
а)* (y>=x) and (y+x>=0) and (y<=1);
б) (sqr(x)+sqr(y)<1) or (y>0) and (abs(x)<=1);
в) (trunc(y)=0 and (round(x)=0);
г)* (abs(x)<=1)>(abs(y)>=1);
д) (sqr(x)+sqr(y)<=4)=(y<=x).
7) Имеется условный оператор:
if d<>10
then
writeln (‘ура!’)
else
writeln (‘плохо...’)
Можно ли заменить его следующими операторами:
а) if d=10
б) if not (d=10)
then
then
writeln (‘ура!’)
writeln (‘ура!’)
else
else
writeln (‘плохо...’);
writeln (‘плохо...’);
29
в) if not (d=10)
then
writeln (‘плохо...’)
else
writeln (‘ура!’);
г) if not (d<>10)
then
writeln (‘плохо...’)
else
writeln (‘ура!’);
8) Какими будут значения переменных j, k после выполнения условного оператора:
if j>k
then
j:=k-2
else
dec (k,2);
если исходные значения переменных равны:
а) j=3, k=5;
b) j=3, k=3;
c) j=3, k=2.
Примечание. В результате выполнения оператора dec (k,2) значение переменной k уменьшается на 2.
Занятие 3. Вложенные условные операторы. Решение задач.
При решении задач часто приходится рассматривать не два, а большее количество вариантов. Это можно реализовать,
используя несколько условных операторов. В этом случае после служебных слов Then и Else записывается новый условный
оператор. Рассмотрим пример.
Задача. Вычислить значение функции:
x  12, x  0

у= 5,x  0
 2
x ,x  0
Для решения этой задачи рассмотрим координатную прямую, на которой отметим промежутки, на которые разбиваются
все значения переменной х.
x<0
x=0Ð=0
Ð<0
x>0
Ð>0
x
Начнем записывать условный оператор:
если х>0
то
вычислить у по формуле у=х-12
иначе
Что же должно выполниться в случае иначе? На эту ветку оператора попадают все не положительные значения х. Если
бы для этих чисел нужно было бы выполнить один и тот же оператор (или группу операторов), то проблемы бы не стояло. Но
нам нужно этот промежуток разделить еще на две части (отрицательные и ноль), и для части выполнить свой оператор.
Поэтому ветка Иначе будет содержать еще один условный оператор и наш вложенный условный оператор будет иметь вид:
если х>0
то
у вычислить по формуле у=х-12
иначе
если х=0
то
у вычислить по формуле у=5
иначе
у вычислить по формуле у=sqr(x);
Тогда фрагмент программы для решения этой задачи будет выглядеть так:
if х>0
then
у := х-12
else
if х=0
then
у := 5
30
else
у := sqr(x);
Итак, когда оператор if появляется внутри другого оператора if, они считаются вложенными. Такое вложение
используется для уменьшения числа необходимых проверок. Этот метод часто обеспечивает большую эффективность,
однако одновременно он уменьшает наглядность программы. Не рекомендуется использовать более одного-двух уровней
вложения if. За вторым уровнем вложения становится трудно восстановить последовательность проверки условий каждым
условным оператором.
Если часть else используется во вложенных if, то каждое else соответствует тому if, которое ему непосредственно
предшествует. Таким образом, при определении последовательности выполнения фрагментов нет двусмысленности.
Рассмотрите еще один пример.
Задача. Даны целые числа a, b, c. Если a  b  c, то все числа заменить их квадратами, усли a>b>c, то каждое число
заменить наибольшим из них, в противном случае сменить знак каждого числа.
Для решения этой задачи перепишем условие задачи следующим образом:
a:=a2, b:=b2, c:=c2, если a  b  c
b:=a, c:=a, если a>b>c
a:=-a, b:=-b, c:=-c, в остальных случаях
Программа для решения этой задачи представлена ниже.
Program Example3;
Var
a, b, c : integer;
Begin
writeln(‘Введите числа a, b, c’);
readln(a,b,c);
if (a<=b) and (b<=c)
then
begin
a:=sqr(a);
b:=sqr(b);
c:=sqr(c);
end
else
if (a>b) and (b>c)
then
begin
b:=a;
c:=a;
end
else
begin
a:=-a;
b:=-b;
c:=-c;
end
writeln(a,b,c);
readln;
End.
Задание. Найдите в этой программе (если есть) условный оператор, вложенный условный оператор, составной оператор,
булево условие.
Внимание! Подчеркнем еще раз один тонкий момент: поскольку каждый из операторов может быть оператором любого
типа (в том числе и условным), и в то же время не каждый из "вложенных" условных операторов может иметь часть else, то
возникает неоднозначность трактовки условий. Turbo-Pascal решает эту проблему таким радикальным способом: любая
встретившаяся часть else соответствует ближайшей к ней части then.
I Выберите с учителем задачи для самостоятельного решения из предложенного списка:
1. Найти наибольшее из трех данных чисел.
2. Вывести на экран номер четверти, которой принадлежит точка с координатами (x,y), при условии, что (x<>0) и (y<>0).
3. Даны три различных числа, найти среднее из них. Средним назовем число, которое больше наименьшего из данных
чисел, но меньше наибольшего.
4. Составьте программу нахождения произведения двух наибольших из трех введенных с клавиатуры чисел.
5. Запросить стороны треугольника и определить, является ли он разносторонним, равнобедренным или
равносторонним.
Учесть условие : третья сторона не должна превышать сумму двух других, иначе треугольник не существует.
6. Составьте программу для вычисления выражения
31
а) max (x+y+z,xyz)+3;
b) min (x2+y2,y2+z2)-4;
Значения переменных x, y, z вводятся с клавиатуры.
7. Составьте программу, в которой из трех введенных с клавиатуры чисел возводятся в квадрат положительные, а
отрицательные остаются без изменения.
8. Даны действительные числа a, b, c. Вычислить корни уравнения
2
ax  bx  c  0
9. Найти минимальное из трёх чисел.
10. Составить программу вычисления функции
( Sin(x), если х<=a;
z= ( Cos(x), если a<x<b;
( Tg(x), если x>=b.
11. Предложите пользователю ввести число с клавиатуры. Если число равно нулю, выведите слово “ноль”; если число
положительное, выведите слово “положительное”; если число отрицательное, выведите слово “отрицательное”.
12. Напечатать программу вывода дней недели по номеру.
II Выберите с учителем задачи для самостоятельного решения из предложенного списка:
1. Определить, попадает ли точка "A" с координатами (х,у) внутрь круга радиуса R. Центр круга совпадает с началом
координат.
2. Напишите программу "Угадай число". Компьютер "загадывает" число, а пользователь его отгадывает. ( random и
постепенное угадывание)
3. Найти сумму положительных чисел, больших 20, меньших 100 и кратных 3.
4. Составьте программу для упорядочения трёх чисел a, b, c по возрастанию таким образом, чтобы имени а
соответствовало наименьшее число, имени b- среднее, имени с - наибольшее.
5. Запрограммируйте шуточный тест "Проверь свои возможности". Пользователю предлагается ответить на 7 вопросов:
1) Профессор лёг спать в 8 часов, а встал в 9 часов. Сколько часов проспал профессор?
(1)
2) На двух руках 10 пальцев. Сколько пальцев на 10?(50)
3) Сколько цифр в дюжине?(2)
4) Сколько нужно сделать запилов, чтобы распилить бревно на 12 частей? (11)
5) Врач сделал три укола в интервале 30 минут. Сколько времени он затратил? (30)
6) Сколько цифр 9 в интервале 1 100? (1)
7) У пастуха было 30 овец. Все кроме одной разбежались. Сколько овец осталось? (1)
Оценка ответов пользователя:
- если 7 правильных, то печатается "Гений";
- если 6 правильных, то печатается "Эрудит";
- если 5 правильных, то печатается "Нормальный";
- если 4 правильных, то печатается "Способности средние";
- если 3 правильных, то печатается "Способности ниже среднего";
- если <2 правильных, то печатается "Вам надо отдохнуть!".
12. Cоставить программу для вычисления значения функции
3
Z=x /y, где y=Sin(nx)+0.5.
6. Составьте программу для упорядочения трех чисел a, b,c по возрастанию таким образом, чтобы имени а
соответствовало наименьшее число, имени b - среднее, имени c - наибольшее.
7. Составить программу, которая запрашивает пароль и выводит сообщение правильно ли он введен.
8. Напишите программу, которая преобразовывает римские числа в натуральные числа.
Примечание. Римские числа могут состоять только из символов "X", "V" и "I". Наибольшее число которое может
воспринять программа, -это XXXIX, т.е. 39.
9. Дано действительное число а. Вычислить f(a), если
а) f(a)=х2 при -2<=х<2,
f(a)=4 в противном случае;
б) f(a)=х2+4х+5 при х<=2
f(a)=1/(х2+4х+5) в противном случае;
в) f(a)=0 при х<=0,
f(a)=х при 0<х<=1,
f(a)=х4 в остальных случаях;
г) f(a)=0 при х<=0,
f(a)=х2-х при 0<х<=1,
f(a)=х2-sinПх2 в остальных случаях.
10. Даны действительные положительные числа a, b, c, d. Выяснить, можно ли прямоугольник со сторонами a и b
уместить внутри прямоугольника со сторонами c и d так, чтобы каждая из сторон одного прямоугольника была
а) параллельна каждой стороне второго прямоугольника;
б) перпендикулярна каждой стороне второго прямоугольника.
32
11. Даны действительные положительные числа a, b, c, х, у. Выяснить, пройдет ли кирпич с ребрами a, b, c в
прямоугольное отверстие со сторонами х, у. Просовывать кирпич в отверстие разрешается только так, чтобы каждое из его
ребер было параллельно или перпендикулярно каждой из сторон отверстия.
12. Дано действительное число а. Для функций f(x), графики которых представлены на рисунках, вычислить f(a)
y
y=-x
y
y=4
y=x
y=-1/x
0
2
2
0
x
y=-x
a)
-1
2
x
2
·)
б)
y
y
1
1
0
0
-2
-1
1
2
1
x
-1
‚)
в)
2
3
x
a)
г)
Занятие 4. Оператор выбора case. Решение задач.
Ранее Вы познакомились с условным оператором If, который позволяет программе выполнять переходы на ту или иную
ветвь по значению булева условия. Используя несколько операторов If, можно производить ветвление по
последовательности условий. В приведенном фрагменте показано, как при помощи ряда операторов If можно преобразовать
целое число (в диапазоне 0-9) к его словесному представлению:
if Ziphra = 0
then
write (‘Нуль‘);
if Ziphra = 1
then
write (‘Единица‘);
if Ziphra = 2
then
write (‘Два‘);
и т.д.
Вы уже, наверное, представили, насколько этот подход однообразный и утомительный. Язык Паскаль предоставляет для
этих целей другую управляющую структуру (оператор выбора case), которая позволяет построить ветвление по ряду условий
в форме, более удобной для чтения программ.
Оператор выбора позволяет выбрать одно из нескольких возможных продолжений программы. Параметром, по
которому осуществляется выбор, служит так называемый ключ выбора (или селектор) – выражение любого типа (кроме
типов REAL и STRING).
Общая форма записи следующая:
case выражение of
значение1 : оператор (группа операторов);
значение2 : оператор (группа операторов);
. . . . . . . . . . . . . . . . . . . . . .
значениеN : оператор (группа операторов)
else оператор (группа операторов);
end;
33
Оператор выбора работает следующим образом. Сначала вычисляется значение выражения, стоящее после
зарезервированного слова case, а затем выполняется оператор (или составной оператор), соответствующий результату
вычисления выражения.
Может случиться, что в списке выбора не окажется константы равной вычисленному значению ключа. В этом случае
управление передается оператору, стоящему за словом ELSE.
Например,
case NUMBER mod 2 of
0 : writeln (NUMBER, ‘- число четное‘)
else : writeln (NUMBER, ‘- число нечетное‘);
end;
Если один оператор выполняется при нескольких значениях, то их можно перечислить через запятую.
case MONTH of
1, 2, 3 : writeln (‘Первый квартал‘);
4, 5, 6 : writeln (‘Второй квартал‘);
7, 8, 9 : writeln (‘Третий квартал‘);
10, 11, 12 : writeln (‘Четвёртый квартал‘);
end;
Оператором может являться не только простой оператор, но также составной и пустой операторы.
case CODE of
1 : for i := 1 to 5 do
writeln (‘*******‘);
2 : begin
{составной оператор}
x:=sqr(y-1);
writeln (x);
end;
3:
{пустой оператор}
end;
Любому заданному значению селектора соответствует лишь один вход в списке операторов. Константы должны
принадлежать тому же типу, что и селектор. Если селектор принимает значение, которому не соответствует ни один вход, то
будет выполняться оператор, следующий за словом else. Если же этого оператора нет, то никакие альтернативы не будут
выполняться.
Если оператор должен выполняться при нескольких значениях селектора следующих друг за другом, образуя некоторый
промежуток, то это можно записать в более сжатой форме. Например,
case Chislo of
0..9 : write (‘Это число является цифрой‘);
Посмотрите, в каких вариантах еще можно использовать оператор выбора при решении задачи.
Задача. Написать программу преобразования цифр в слова.
Program Number1;
Var
a, b, c : integer;
Begin
writeln(‘Введите цифру ‘);
readln(a);
if (a<0) or (a>9)
then
writeln (‘Это число не является цифрой‘)
else
case a of
0 : writeln (‘ноль‘);
1 : writeln (‘один‘);
2 : writeln (‘два‘);
3 : writeln (‘три‘);
4 : writeln (‘четыре‘);
5 : writeln (‘пять‘);
6 : writeln (‘шесть‘);
7 : writeln (‘семь‘);
8 : writeln (‘восемь‘);
9 : writeln (‘девять‘);
end;
readln;
End.
Program Number2;
Var
a, b, c : integer;
34
Begin
writeln(‘Введите цифру ‘);
readln(a);
case a of
0 : writeln (‘ноль‘);
1 : writeln (‘один‘);
2 : writeln (‘два‘);
3 : writeln (‘три‘);
4 : writeln (‘четыре‘);
5 : writeln (‘пять‘);
6 : writeln (‘шесть‘);
7 : writeln (‘семь‘);
8 : writeln (‘восемь‘);
9 : writeln (‘девять‘)
else writeln (‘Это число не является цифрой‘);
end;
readln;
End.
Выберите с учителем задачи для самостоятельного решения.
1. Написать алгоритм, позволяющий получить словесное наименование школьных оценок.
2. Написать алгортм, классифицирующий треугольники (остроугольные, прямоугольные, тупоугольные), если даны
углы.
3. Написать алгоритм, который по номеру дня недели - целому числу от 1 до
7 выдавать в качестве результата количество уроков в классе в соответствующий день.
4. Написать алгоритм нахождения числа дней в месяце, если даны: Номер месяца n - целое число а, равное 1 для
високосного года и равное 0 в противном случае.
5. По номеру дня недели вывести его название.
6. В зависимости от того введена ли открытая скобка или закрытая, напечатать "открытая круглая скобка" или "закрытая
фигурная скобка". (Учитывать круглые, квадратные, фигурные скобки).
7. В зависимости от введённого символа L, S, V программа должна вычислять длину окружности; площадь круга; объём
цилиндра.
8. По введенному числу от 0 до 15 вывести название цвета, соответствующего этому коду.
9. Определить, является ли введенная буква русского алфавита гласной.
10. Написать программу, которая бы предлагала меню для вывода графических объектов, и рисовала бы
соответствующий выбору.
11. Придумайте шуточный тест с выдачей шуточных результатов.
12. Напишите программу, которая по введенному числу из промежутка 0..24, определяет время суток.
13. Напишите программу, которая по введенному номеру месяца високосного или невисокосного года, выводит
количество дней в месяце.
14. Вычислить значение функции по одной из формул:
x  a, x  10;
x  a,10   x   20

y= sqr(x),20  x  30
sqr(a)  x,30  x  60


sqr(x)  sqr(a), x  60
15. Придумайте программу на использование оператора выбора сase.
Занятие 5. Оператор безусловного перехода Goto. Решение задач.
В языке принят естественный порядок выполнения программы: последовательный. Рассмотренные выше операторы
if и case осуществляют переход к выполнению соответствующего оператора в зависимости от выполнения условия или
предложенного выбора. Однако в практике программирования задач возникает необходимость безусловного перехода для
выполнения нужной последовательности операторов. Например, необходимо обойти участок программы, а вернуться к нему
позже. Для этого предназначен оператор безусловного перехода, который имеет следующую форму записи:
goto метка;
Метка представляет собою число без знака в диапазоне 1-9999 либо последовательность латинских букв и цифр.
Перед использованием метка должна быть объявлена в разделе описания меток, который срузу следует за разделом
описания используемых модулей:
Uses
Crt, Graph;
Label
35
Metka1,
Metka2;
Const
P=3.14;
Var
x : integer;
После описания метки ее можно использовать в программе. Метка записывается перед помечаемым оператором и
отделяется от него двоеточием. А оператор goto должен помещен в то место программы, откуда выполняется переход.
Оператор goto передает управление на оператор с заданной меткой. Оператор goto можно вставлять в любое место
программы, где могут располагаться операторы языка. Например,
Begin
. . .
if Alpha = 360
then
goto Metka1
else
writeln (‘Эта фигура – не окружность‘);
. . .
Metka1 : Arc(X,Y,0,Alpha,R);
. . .
End.
Приведём пример уже знакомой Вам программы, применив в ней оператор безусловного перехода.
Program Number2;
Label
Metka;
Var
a, b, c : integer;
Begin
Metka : writeln(‘Введите цифру ‘);
readln(a);
case a of
0 : writeln (‘ноль‘);
1 : writeln (‘один‘);
2 : writeln (‘два‘);
3 : writeln (‘три‘);
4 : writeln (‘четыре‘);
5 : writeln (‘пять‘);
6 : writeln (‘шесть‘);
7 : writeln (‘семь‘);
8 : writeln (‘восемь‘);
9 : writeln (‘девять‘)
else
begin
writeln (‘Это число не является цифрой‘);
goto Metka;
end;
end;
readln;
End.
Теперь в этой программе мы заставляем пользователя правильно ввести цифру. Сколько бы раз пользователь ни вводил
числа не из промежутка 0..9, программа будет выдавать сообщение об ошибочном вводе и снова просить ввести цифру.
Задание. Наберите программу и протестируйте ее.
В простых программах этот оператор не вызывает затруднений. При написании сложных и объёмных программ могут
быть затруднения, поэтому программисты стараются не использовать этот оператор. Возникает вопрос: где должен
использоваться безусловный переход? На этот вопрос следует ответить – “нигде”. Любая программа, написанная с goto,
может быть запрограммирована без этого оператора.
Следует ли вообще использовать оператор перехода? Ответить трудно. В основном применение оператора безусловного
перехода оправдано в двух случаях: при преждевременном завершении цикла или программы. Но даже в этих случаях можно
обойтись некоторой стандартной управляющей структурой.
Не будет ничего удивительного в том, что в Ваших программах не будет применяться безусловный переход. В общем
случае рекомендуется избегать использования этого оператора для обеспечения лучшего понимания работы программы.
Бесконтрольное применение оператора goto может усложнить программу настолько, что разобраться в ней будет
невозможно. Поэтому программисты считают применение оператора безусловного перехода плохим стилем
программирования.
36
Задание. Выберите произвольно из решенных Вами задач две и дополните их решение использованием оператора
безусловного перехода goto.
Занятие 6. Контрольная работа
1) Есть ли в следующих текстах пустые операторы? (Если есть, то отметьте в тетради под какими буквами.)
а) if x>0 then x:=2 else; y:=x+1;
б) if odd(k) then else k:=0;
в) begin x:=2; y:=5; end;
г) begin a:=true; ; b:=b or a end;
д) begin if x=0 then goto 1; y:=x; 1:end
2) Если n=3, то какое значение будет иметь переменная f после выполнения следующего составного оператора?
Запишите в тетрадь.
begin f:=1; i:=2;
1: if i>n then goto 9;
f:=f*i; i:=i+1; goto 1;
9: end
3) Найдите ошибки в программе, записав уже исправленную программу в тетрадь:
Program Errors;
Const L=18;
Label 18,8;
Var x, y:integer;
Begin y:=0;
8: read(x); if x<0 then goto L;
y:=y+x; goto 18;
L:writeln(y)
End.
4) Найти ошибки в следующих операторах, запишите исправленные операторы в тетрадь:
а) begin 77: if |x|<1 then goto 5
begin x:=x/2; goto 77; 5: y:=sin(x) end
end;
б) 34:if 0<x<2
then if y<1 then goto 34 else goto 15
else 15: y:=sqr(y)
в) if 1<x<2
then
x:=x+1; y:=0;
else
x:=0; y:=y+1;
г) if 1<x and x<2
then begin x:=x+1; y:=0 end;
else begin x:=0; y:=y+1 end
5) Запишите в тетрадь, какое значение будет иметь переменная z после выполнения операторов
z:=0
if x>0 then if y>0 then z:=1 else z:=2
при следующих значениях переменных х и у:
а) х=у=1; б) х=1, у=-1;
в) х=-1, у=1.
Сдайте свою тетрадь на проверку учителю.
Творческое задание. Придумайте и решите задачу с применением графического режима, предлагая для выбора
пользователю некоторое меню.
Для любознательных
Рассмотрим решение таких задач, в которых требуется выполнить группу операторов определенное количество раз.
Задача. Дано 10 вещественных чисел. Найти величину наибольшего из них.
Program Maximum;
Uses
Crt;
Label
Metka1;
Var
Kolich : integer;
Max,
x : real;
Begin
37
ClrScr;
Kolich:=0;
Max:=-32768;
Metka1 : write (‘Введите число ‘);
readln (x);
if x>Max
then
Max:=x;
Kolich:=Kolich+1;
if Kolich<10
then
goto Metka1;
writeln (‘Наибольшее число равно ‘,x);
readln;
End.
Рассмотрим подробнее действие операторов. После очистки экрана (ClrScr) мы присвоим переменной Kolich, которая
определена для подсчета введенных чисел, первоначальное значение равное нулю. Переменной Мах мы будем присваивать
наибольшее значение из вводимых чисел. Так как переменная Мах типа integer, то присвоим ей первоначальное значение
равное наименьшему из диапазона этого типа, т. е. числу -32768. Далее выделен целый блок. Он будет повторяться при
запуске программы 10 раз, т.е. столько сколько чисел нам нужно запросить у пользователя и исследовать их. Просмотрим
действие этого блока. Сначала мы запрашиваем у пользователя первое число и считываем его в переменную х. Затем идет
анализ этого числа. Если введенное число х оказалось больше числа, находящегося в переменной Мах, то происходит пере
присваивание: переменной Мах присваиваем значение х. Итак, считано одно число, поэтому счетчик введенных чисел
(Kolich) увеличиваем на 1. Проверяем условным оператором, может быть уже достаточно введено и проанализировано
чисел? Если Kolich меньше 10, то еще недостаточно, а значит надо вернуться для того чтобы снова запросить и
проанализировать следующее число, что и выполнено с помощью оператора goto. Этот оператор не пропустит нас дальше
выполнять программу пока не выполниться условие, при котором переменная Kolich будет равна 10. А такой момент
обязательно наступит, потому что в результате выполнения блока переменная Kolich увеличивается на 1. В результате
выделенный блок повториться 10 раз, будет запрошено 10 чисел и среди них постоянным сравнением с предыдущим числом
будет выявлено наибольшее, которое будет содержаться в переменной Мах. После выхода из блока останется только вывести
это число на экран.
Задание. Решите подобную задачу с использованием выше описанного метода.
1) Дано n вещественных чисел. Определить, сколько среди них отрицательных.
2) Дано n вещественных чисел. Определить, сколько среди них положительных чисел.
3) Дано n вещественных чисел. Найти их сумму.
4) Дано n вещественных чисел. Найти их среднее арифметическое.
5) Дано n вещественных чисел. Определить сумму чисел, стоящих на четных местах в этой последовательности.
6) Дано n вещественных чисел. Определить сумму положительных чисел.
7) Дано n вещественных чисел. Определить сумму отрицательных чисел.
8*) Дано целое k от 1 до 180. Определить, какая цифра находится в k-ой позиции последовательности
10111213...9899,
в которой выписаны подряд все двузначные числа.
9*) Дано натуральное k. Определить k-ую цифру в последовательности
110100100010000...,
в которой выписаны подряд степени 10.
10*) Вычислить с – наибольший общий делитель натуральных чисел а и b.
Приготовьте файлы и листинги с решенными задачами, а также проверьте, все ли задания выполнены в тетради.
Дополнительно
Выберите с учителем задачу для решения.
1) Написать программу для решения указанной задачи: для заданного числа а найти корень уравнения f(x)=0, где
2ax|a  1|, a  0,

f(x)=  x
 1,a ]0,[

 1  a 2
2) Дано число х. Напечатать в порядке возрастания числа x, 1+|x| и (1+х 2).
3) Даны числа a1, b1, c1, a2, b2, c2. Напечатать координаты точки пересечения прямых, описываемых уравнениями
a1х+b1у=c1 и a2х+b2у=c2, либо сообщить, что прямые совпадают, не пересекаются или вовсе не существуют.
4
2
4) Даны числа a, b и с (а  0 ). Найти вещественные корни уравнения ах +bx +c=0. Если корней нет, сообщить об этом.
5) Даны произвольные числа a, b и с. Если нельзя построить треугольник с такими длинами сторон, то напечатать 0,
иначе напечатать соответствующее сообщение в зависимости от того, равносторонний это треугольник, равнобедренный или
какой-либо иной.
Контрольные вопросы
1. Какой алгоритм называется разветвляющимся?
38
2. Что такое ветвь алгоритма?
3. Какое условие называется составным?
4. Верно ли, что в качестве метки можно использовать любое положительное целое число?
5. Обязательно ли описывать все метки, которыми помечены операторы программы?
6. Верно ли, что в разделе меток все описываемые метки должны быть перечислены по возрастанию?
7. Допустимы ли в Паскале следующие составные операторы?
а) begin end;
б) begin x:=0 end;
в) begin; end
8. Какое выражение называется булевым? Почему?
9. Какая форма условного оператора называется полной? Краткой?
10. Какие условные операторы называются вложенными? Как они применяются?
11. Как применяется оператор выбора? Когда он особенно необходим?
12. Для чего нужен оператор безусловного перехода? Почему он так называется?
ЦИКЛЫ
Занятие 1. Циклические алгоритмы. Цикл с предусловием.
Очень многие алгоритмы, выполнение которых поручается компьютеру, по своей природе являются циклическими. И
это не случайно, потому что человек обычно поручает машине рутинную работу, где нужно много считать, и счет
производится по некоторым одинаковым правилам.
Определение. Цикл – это последовательность операторов, которая может выполняться более одного раза.
Определение. Циклический алгоритм – это алгоритм, содержащий один или несколько циклов.
Возьмем для примера задачу: найти сумму некоторого количества чисел, задаваемых пользователем.
Исходными данными в этом случае являются переменная N - количество чисел и сами эти числа. Значение очередного
числа обозначим переменной Х. Результатом работы алгоритма станет сумма этих чисел, которую обозначим переменной S.
S=x1+x2+x3+...+xn
Допустимые значения переменной N должны удовлетворять условию n>0, так как количество слагаемых не может быть
числом отрицательным.
Как же мы должны решать эту задачу? Сначала нужно запросить, сколько чисел нужно будет сложить и считать это
число в переменную N. Затем нужно так организовать операторы, чтобы программа запрашивала очередное число и каждый
раз складывала его с предыдущими; и повторяла эту группу операторов N раз.
На предыдущих занятиях при изучении оператора безусловного перехода мы знакомились с решением подобных задач.
Но в языке Паскаль существуют более удобные конструкции для организации циклов:
• цикл с предусловием;
• цикл с постусловием;
• цикл со счетчиком.
Познакомимся с первым из них – оператором цикла с предусловием while.
Циклы с предусловием используются тогда, когда выполнение цикла связано с некоторым логическим условием.
Оператор цикла с предусловием имеет две части: условие выполнения цикла и тело цикла.
При выполнении оператора while определенная группа операторов выполняется до тех пор, пока определенное в
операторе while булево условие истинно. Если условие сразу ложно, то оператор не выполнится ни разу.
Общая форма записи следующая
while <булево выражение> do
begin
группа операторов
end;
На русском языке это звучит примерно так:
пока выполняется это условие делай
от начала
группа операторов
до конца;
Вполне понятно, что операторные скобки ставят, чтобы отделить от остальной программы ту группу операторов,
которую нужно повторить в цикле. Если в цикле нужно выполнить только один оператор, то операторные скобки не ставят.
При использовании цикла с предусловием надо помнить следующее:
1) значение условия выполнения цикла должно быть определено до начала цикла;
2) если значение условия истинно, то выполняется тело цикла, после чего повторяется проверка условия. Если условие
ложно, то происходит выход из цикла;
3) хотя бы один из операторов, входящих в тело цикла, должен влиять на значение условия выполнения цикла, иначе
цикл будет повторяться бесконечное число раз.
Вернемся к нашей задаче вычисления суммы чисел. При вычислении суммы используем следующий прием: вначале,
когда еще не задано ни одно слагаемое, сумму полагают равной нулю (S:=0), а затем, получая очередное слагаемое,
прибавляют его к сумме (S:=S+x) (см. программу ниже).
Очень важное значение в операторе цикла имеет так называемая переменная цикла. В нашей программе она называется
i. С ее помощью мы обращаемся к пользователю за очередным числом (write (‘Введите ‘,i,’-ое число ’)) и считаем количество
39
уже введенных чисел (i:=i+1), чтобы не запросить лишнее. Одновременно переменная цикла участвует в булевом выражении
(i<=N).
Рассмотрите внимательно программу, решающую нашу задачу.
Program Summa;
Uses
Crt;
Var
i,
N : integer;
x, S : real;
Begin
ClrScr;
write (‘Сколько чисел для сложения? ‘);
readln (N);
S:=0;
i:=1;
while i<=N do
begin
write (‘Введите ‘,i,’-е число ’);
readln (x);
S:=S+x;
i:=i+1;
end;
write (‘Сумма введенных чисел равна ‘,s:5:2);
readln;
End.
Хотелось бы, чтобы Вы смогли представить работу этой программы. Давайте попробуем вместе.
Пусть нам требуется сложить следующие числа: 5, 7, -4, 0, 8, 20. Посчитаем, сколько их всего – шесть. Это число мы
введем, когда программа задаст вопрос: Сколько чисел для сложения? Теперь наша программа запросит ввести 1-ое число, т.
к. на первом шаге переменная i равна 1. Мы введем число 5. Программа считает его в переменную х. Теперь число 5 сложим
с числом 0 и результат присвоим переменной S (оператор S:=S+x). В этот момент S становится равной 5. Чтобы перейти к
следующему числу, увеличим значение переменной i на 1 (оператор i:=i+1). Выполнение операторов тела цикла закончено.
Теперь программа переходит опять к анализу условия вхождения в цикл (i<=N). Переменная цикла i=2, переменная N=6,
поэтому значение логического условия 2<=6 равно True. Значит снова выполняется тело цикла:
while i<=N do
{2<=6}
begin
write (‘Введите ‘,i,’-ое число ’);
{Введите 2-е число}
readln (x);
{Считали число 7}
S:=S+x;
{S:=5+7}
i:=i+1;
{i:=2+1}
end;
Итак, мы сложили два числа и переходим опять к проверке условия. Ответим на вопрос: 3<=6? Да. Поэтому снова
начинаю работать операторы тела цикла и мы переходим к третьему числу:
while i<=N do
{3<=6}
begin
write (‘Введите ‘,i,’-ое число ’);
{Введите 3-е число}
readln (x);
{Считали число -4}
S:=S+x;
{S:=12 + (-4)}
i:=i+1;
{i:=3+1}
end;
Аналогично, мы сложим и остальные числа. Но когда же операторы цикла выполнятся последний раз и остановится
работа цикла? Когда сложим последнее число. Проверим это.
while i<=N do
{6<=6}
begin
write (‘Введите ‘,i,’-ое число ’);
{Введите 6-е число}
readln (x);
{Считали число 20}
S:=S+x;
{S:=16+20}
i:=i+1;
{i:=6+1}
end;
Проверяется опять условие 7<=6. Значение этого условия равно False, а значит тело цикла выполняться не будет. Цикл
закончил свою работу. А мы получили результат: посчитали сумму всех шести чисел S=32.
В этом примере известно заранее количество повторений - N раз. Но чаще всего этот вид цикла используется тогда,
когда количество повторений заранее не известно и зависит от выполнения какого-либо условия. Рассмотрим еще один
пример.
40
Отвлечемся от цифр и вспомним окружающую жизнь. Сколько циклических алгоритмов можно увидеть вокруг, если
внимательно посмотреть на события: чередование времен года, посещения магазинов, школы или секции, получение за
контрольные оценок и др. Попробуем записать их.
Например, рассмотрите следующие циклические алгоритмы
а) Пока не сдал выпускные экзамены делай
начало
готовь уроки;
посещай школу;
конец;
б) Пока есть желание, возможность и здоровье делай
посещай занятия спортом
Задание. Выберите самостоятельно сказку из предложенных (или придумайте другой циклический алгоритм из жизни
или произведений известных авторов) и напишите программы, с помощью которых можно в шутливой форме проверить
знания первоклассников.
а) “Репка”. “Дед тянет-потянет, вытянуть не может. Позвал бабку. Бабка за дедку , дедка за репку, тянут потянут,
вытянуть не могут. Позвала бабка внучку... И вытянули репку”.
б) “Курочка ряба”. “Снесла курочка яичко. Дед бил, бил, не разбил. Баба била, била, не разбила. Мышка бежала,
хвостиком задела, яичко упало и разбилось”.
в) “Колобок”. “... Катится колобок по лесу. От зайца ушел, от медведя ушел, от волка ушел. Встретил лису, она его и
съела”.
г) “Волк и лиса”. “... Сидит волк у проруби, хвост в воду опустил и приговаривает: “Ловись, ловись, рыбка, большая и
маленькая”. Пришла за водой баба. Прогнала волка.
д) “Горшочек каши”. “... Варит горшок кашу, варит. Каша из дома на улицу потекла. Не знает мать девочки, что надо
горшочку сказать. Пришла девочка, сказала: “Горшочек, не вари”. Перестал горшок кашу варить”.
Цикл с предусловием.
Продолжим изучение цикла с предусловием на примере решения следующей задачи.
Задача. Найти сумму чисел в непустой последовательности.
Рассмотрим алгоритм решения. Пусть нам дана такая последовательность чисел:
3, -4, 0, 5, 19, -20, 6, 2
Для работы нам нужно организовать обращение к каждому элементу последовательности. Нетрудно догадаться, что это
будет происходить через порядковый номер каждого члена последовательности. Пронумеруем эти числа:
1 2 3 4 5
6 7 8
3, -4, 0, 5, 19, -20, 6, 2
Получилось, что всего у нас чисел восемь, на первом месте стоит число 3, на втором - число (-4), на третьем - число 0 и
т.д. Тогда переменная цикла i будет пробегать числа от 1 до 8, становясь на каждом шаге больше на 1 и запрашивая каждый
раз очередное число. Поэтому общая схема цикла будет выглядеть так:
i:=1;
while i<=N do
begin
write (‘Введите ‘,i,’-ое число’);
readln (x);
. . .
i:=i+1;
end;
Здесь N - количество чисел последовательности (в нашем случае 8), х - член последовательности, i - порядковый номер
очередного члена последовательности. Просмотрим, как будет работать этот цикл.
1 шаг
i:=1;
while i<=N do {Проверяется условие 1<=8? Да. Значит выполняем тело цикла}
begin
write (‘Введите ‘,i,’-ое число’);{Вывод на экран “Введите 1-ое число”}
readln (x); {Считываем число 3 в переменную х}
. . .
i:=i+1; {Переходим к следующему по порядку числу: i=2}
end;
2 шаг
i:=1;
while i<=N do {Проверяется условие 2<=8? Да. Значит выполняем тело цикла}
begin
write (‘Введите ‘,i,’-ое число’);{Вывод на экран “Введите 2-ое число”}
readln (x); {Считываем число (-4) в переменную х}
. . .
i:=i+1; {Переходим к следующему по порядку числу: i=3}
41
end;
3 шаг
i:=1;
while i<=N do {Проверяется условие 3<=8? Да. Значит выполняем тело цикла}
begin
write (‘Введите ‘,i,’-ое число’);{Вывод на экран “Введите 3-ое число”}
readln (x); {Считываем число 0 в переменную х}
. . .
i:=i+1; {Переходим к следующему по порядку числу: i=4}
end;
и т. д.
8 шаг
i:=1;
while i<=N do {Проверяется условие 8<=8? Да. Значит выполняем тело цикла}
begin
write (‘Введите ‘,i,’-ое число’);{Вывод на экран “Введите 8-ое число”}
readln (x); {Считываем число 2 в переменную х}
. . .
i:=i+1; {Переходим к следующему по порядку числу: i=9}
end;
9 шаг
i:=1;
while i<=N do {Проверяется условие 9<=8? Нет. Значит цикл закончил свою работу и компьютер переходит к
обработке следующего за end оператора}
Итак, у нас уже организован цикл считывания чисел. Осталось только вписать в тело цикла оператор, который бы
суммировал все эти числа. Для этого опишем переменную Summa в разделе описания переменных и присвоим ей нулевое
значение перед выполнением цикла. Тогда при каждом шаге нашего цикла значение этой переменной должно быть изменено
на х. Это произойдет при выполнении оператора
Summa:=Summa+x;
Если Вам не совсем понятно, что происходит при выполнении этого оператора, Вам нужно вспомнить, как происходит
присваивание значение переменной: сначала вычисляется значение выражения в правой части (в нашем случае Summa+x, т.е,
значение переменной Summa увеличиваем на х), а затем присваиваем это значение переменной с именем, записанным в
левой части (Summa). Таким образом, в переменной Summa собирается сумма всех считанных чисел.
Задание. Напишите полный текст программы, находящей сумму N чисел последовательности. Дополните программу
нахождением среднего арифметического этих чисел.
Примечание. Средним арифметическим чисел называется сумма этих чисел, деленная на их количество.
Задачи для самостоятельного решения
1. Построить и записать в виде программы алгоритм вычисления суммы квадратов десяти произвольных чисел, водимых
с клавиатуры в процессе выполнения программы.
2. Вводятся 15 чисел. Определить, сколько среди целых чисел.
3. Вывести все чётные числа начиная с числа N и до числа M. Числа N и M задает пользователь.
4. Составить программу, проверяющую, является ли последовательность из 10 целых чисел, вводимых с клавиатуры,
возрастающей.
5. Составить программу, печатающую все делители целого числа в порядке возрастания.
6. Составить программу нахождения суммы чётных чисел, находящихся в промежутке от 26 до 88.
7. Найти наибольший общий делитель двух натуральных чисел a и b.
8. Спортсмен в первый день пробежал 10 км. Каждый следующий день он увеличивал норму на 10% от нормы
предыдущего дня.
а) Определить через сколько дней спортсмен пробежит суммарный путь более 100 км.
б) Определить через сколько дней спортсмен будет пробегать более 20 км.
в) Какой путь пробежит спортсмен на 7-й день.
9. Вводятся 14 чисел. Определить, сколько среди них положительных (включая 0) и сколько отрицательных. (Числа
вводятся в одну переменную в цикле)
10. Запросите 16 чисел и выведите на экран для каждого, делится ли оно нацело на 11. Спросите у пользователя, сколько
нужно проанализировать чисел, а затем запросите эти числа и сделайте для каждого вывод, является ли оно четным или
отрицательным.
12. Найдите сумму следующей последовательности
а1+а2-а3+а4-...+аn, где n - количество элементов, задаваемых пользователем.
13. Составить программу, печатающую все делители целого числа в порядке убывания.
14. Вывести на экран числа, кратные К из промежутка [А,В]. Числа А, В, К задает пользователь.
15. Запросите у пользователя положительное число А и найдите сумму всех натуральных чисел из промежутка [1, А].
42
Занятие 2. Цикл с предусловием в графике.
Задача. Построить множество концентрических окружностей (с общим центром), удовлетворяющих следующим
условиям:
а) радиус следующей окружности на m меньше предыдущей;
б) процесс построения должен завершиться, когда радиус меньшей окружности станет меньше или равным данному
числу а.
Итак, для решения задачи в программе мы должны запросить у пользователя значения переменных m и а, затем
инициализировать графический режим и в цикле выполнять построение окружностей, меняя при этом радиус. Для наиболее
красочного построения окружностей применим процедуру установки текущего цвета с применением случайных чисел.
Program Krugi;
Uses
Crt, Graph;
Var
i,
m,
R,
a,
DV,
DM : integer;
Begin
ClrScr;
Randomize;
write (‘Введите шаг изменения радиуса окружностей ‘);
readln (m);
write (‘Введите радиус большей окружности ‘);
readln (R);
write (‘Введите радиус меньшей окружности ‘);
readln (а);
write (‘Введите координаты центра ‘);
readln (X, Y);
DV:=detect;
InitGraph (DV, DM, ‘..\BGI’);
SetBkColor (7);
while R>=a do
begin
SetColor (Random(15));
Circle (X, Y, R);
R:=R-m;
end;
readln;
CloseGraph;
End.
Примечание. Здесь применена процедура Randomise, которая инициализирует генератор случайных чисел. Значения же
случайных чисел можно получить с помощью функции Random (Х), где Х - параметр, указывающий диапазон значений
случайного числа. Оно изменяется в пределах [0,Х[. Результат в этом случае будет типа Word. Если параметр Х не задан, то
результат буде типа real в пределах [0.0,1.0[.
Задачи для самостоятельного решения
1. Составить программу, перемещающую отрезок заданной длины слева направо. Имитация движения осуществляется
закраской цветом фона линии на предыдущем шаге и построением ее по новой координате Х на следующем шаге.
2. Составить программу, перемещающую отрезок заданной длины сверху вниз.
3. Составить программу, перемещающую отрезок заданной длины из левого верхнего угла в правый нижний, постепенно
его увеличивая.
4. Нарисовать веер, состоящий из секторов круга, разукрашенных разным цветом.
5. Нарисовать окружность, меняющую цвет заданное число раз.
6. Изобразить движущуюся окружность заданного радиуса и цвета.
7. Изобразить движение выбранной Вами фигуры.
8. Изобразить движение грузовика.
9. Используя процедуру очистки экрана, постройте изображение надувающегося мыльного пузыря, который должен
лопнуть, когда его радиус станет в 3 раза больше первоначального.
10. Нарисуйте последовательность вложенных квадратов с общим центром в центре экрана так, чтобы расстояние между
сторонами уменьшалось до тех пор, пока не стало меньше трех точек.
11. Составьте программу “Растущая ель”. Рост ели имитируется добавлением к нижнему основанию треугольника
(кроне ели) линии на одну точку шире основания как слева, так и справа. К основанию ствола добавляется прямая линия.
Программа прекращает работу при увеличении высоты дерева вдвое.
12. Составьте программу “Рост лиственного дерева”. Рост кроны изображается добавлением окружностей.
43
13. Нарисуйте действующую модель часов с кукушкой. Часы должны тикать, кукушка куковать.
14. Нарисуйте движение маятника.
15. Нарисуйте движение фигуры, используя уже имеющийся файл с программой из темы “Операторы графики”.
Занятие 3. Контрольная работа
1. Запишите конструкцию цикла с предусловием. В каких случаях применяется цикл с предусловием?
2. Запишите правильную структуру последовательности операторов:
a:=1; b:=1;
while a+b<8 do begin a:=a+1; b:=b+2 end; s:=a+b
Сколько раз будет повторен цикл и какими будут значения переменных a, b, s после его завершения?
3. Запишите правильную структуру последовательности операторов. Какими будут значения переменных а и b после
выполнения операторов:
a:=1; b:=1;
while a<=8 do а:=a+1; b:=b+1
4. Запишите правильную структуру последовательности операторов. Определите значение переменной s после их
выполнения.
а) s:=0; i:=0; while i<5 do Inc(i);s:=s+100 Div i;
b) s:=0; i:=0; while i>1 do begin s:=s+100 Div i; Dec(i) End;
5. Дана последовательность операторов, вычисляющих факториал f числа n, которая содержит пять ошибок. Найдите эти
ошибки, предварительно записав операторы в правильном виде.
k:=1; f:=0;
while k<n do f=f*k
k:=k+1,
Примечание. Факториалом натурального числа называется произведение всех натуральных чисел от 1 до этого числа,
т.е. n!=1*2*3*...*(n-2)*(n-1)*n
6. Найдите и исправьте ошибки в следующем фрагменте программы, определяющей для заданного натурального числа n
число, записанное цифрами числа n в обратном порядке.
p:=n;
while p>=0 do
begin
a:=a+p Mod 10;
p:=p Div 10
end;
7. Ниже представлен фрагмент программы вычисления количества цифр в заданном натуральном числе. Найдите и
исправьте в нем ошибки.
8. Каким условиям должны удовлетворять значения переменной k, чтобы следующие циклы были бесконечны:
while c<0 do c:=c+k;
while k<>0 do k:=1+k;
while k<>0 do k:=k-2;
Подготовьтесь объяснить учителю их решения.
Занятие 4. Цикл с постусловием repeat.
Вы уже умеете организовать цикл при помощи оператора while. Напомним, что при выполнении этого оператора
компьютер вычисляет значение условия. Если условие истинно, то исполнительная часть оператора while будет выполняться
до тех пор, пока это условие не примет значение False. Если значение условия есть False в самом начале, то исполнительная
часть оператора while вообще не будет выполняться.
Иногда при решении задач возникает необходимость выполнить тело цикла хотя бы один раз, а потом исследовать
условие повторять ли его еще раз. Эту задачу выполнит другой вид цикла Repeat.
repeat
повторяй
операторы
операторы
until <условие>;
до тех пор, пока условие не будет верным
Есть небольшое отличие в организации цикла repeat по сравнению с while: для выполнения в цикле repeat нескольких
операторов не следует помещать эти операторы в операторные скобки begin ... end. Зарезервированные слова repeat и until
действуют как операторные скобки.
Конструкция repeat ... until работает аналогично циклу while. Различие заключается в том, что цикл while проверяет
условие до выполнения действий, в то время как repeat проверяет условие после выполнения действий. это гарантирует хотя
бы одно выполнение действий до завершения цикла.
Например,
a) repeat
b)
repeat
read (Number);
i := i+1;
Sum := Sum+Number;
writeln (Sqr(i))
until Number=-1
until Number=-1
Задача. Определить, является ли введенное число простым.
Алгоритм решения этой задачи будет следующий. При помощи операции mod проводим проверку всех целых чисел от 2
до введенного числа Number . Мы проверяем является ли очередное проверяемое число делителем нашего числа (значит,
44
остаток от деления введенного числа на проверяемое число равен нулю). Если такой делитель найден, значит, цикл досрочно
завершает свою работу на некотором i-том шаге. Если делитель не найден, значит цикл проверил все числа и значение
переменной цикла i будет равно конечному значению, т.е. Number. Поэтому, после записи цикла следует анализ значения
переменной i и выводится соответствующее сообщение.
Примечание. Напомним, что простым называется число, которое не имеет делителей кроме 1 и самого себя.
Цикл не может продолжаться бесконечно, так как любое число всегда делится само на себя.
Program Prostoe;
Uses
Crt;
Var
i,
{возможный делитель}
Number : integer;
{исследуемое число}
Begin
ClrScr;
writeln (‘Какое число должно быть проверено? ‘);
read (Number);
i := 1;
repeat
i := i+1;
until Number mod i = 0;
if Number=i
then
writeln (Number,’ является простым‘)
else
writeln (Number,’ делится на ‘,i);
readln;
End.
При построении циклов нужно быть очень аккуратным: следить за отсутствием ошибок как в фазе входа в цикл, так и в
фазе завершения цикла.
Задание. Выберите две задачи, решенных Вами с помощью цикла с предусловием, и решите их с помощью цикла с
постусловием.
Задачи для самостоятельного решения
1. Составьте программу для определения N!-M!
N! = 1*2*3*4*.........*n
2. Запросить имя пользователя и напечатать "Привет, Вася!" 10 раз. (если Вася – имя пользователя)
3. Программа должна вычислять произведение двух чисел и спрашивать завершать программу или нет, если нет то
продолжать запрашивать данные вычислять произведение и печатать его.
4. Вывести на печать все трёхзначные натуральные числа, сумма цифр которых равна заданному числу N. (Операции div
и mod не использовать.)
5. Составить программу, печатающую все простые числа, не превосходящие данного числа.
6. Население города увеличивается на 3% каждый год. В 1983 году население города составляло 65000. Напишите
программу, которая выведет на экран предсказываемую численность населения города в каждом году вплоть до 1999г.
7. Найдите все натуральные числа от 1 до 1000, кратные 3.
8. Составить программу планирования закупки товара в магазине на сумму, не превышающую заданную величину.
9. Составить программу запроса пароля пока не будет введен пароль верно. В программе предусмотреть счетчик
неправильных вводов пароля.
10. Произведение N первых нечетных чисел равно р. Сколько сомножителей взято?
11. Числа Фибоначчи (fn) определяются формулами:
f0=f1=1; fn=fn-1+fn-2 при n=2,3,...
Cоставить программу:
а) определения f - 40-е число Фибоначчи;
б) поиска f - первого числа Фибоначчи, большего m (m>1);
в) вычисления S - суммы всех чисел Фибоначчи, которые не превосходят 1000.
12. Самостоятельно придумать и решить задачу на применение цикла с постусловием.
Занятие 5. Работа с клавиатурой. Стандартные процедуры read и readLn. Стандартные функции
readKey и KeyPressed; их применение в циклах.
Это занятие мы посвятим вопросам программированию обменов с клавиатурой компьютера. Турбо Паскаль содержит
несколько простых и ясных средств, которые позволяют организовать эффективное управление программы посредством
клавиатуры.
Самая простая и часто применяемая техника организации приема информации основывается на использовании уже
знакомых Bам процедур read и readln. Расширим знания о них. Эти процедуры работают со стандартным входным файлом,
который отождествлен с “консолью”, т. е. с клавиатурой и экраном дисплея. На практике это означает, что информация,
введенная с клавиатуры, помимо обработки процедурами, будет отображаться на экране.
45
Удобством указанных процедур является автоматическое преобразование ими вводимой цепочки символов в значение
заданного типа. Так, если в разделе описания переменных имеется описание вида
Var
Chislo : integer;
то выполнение оператора readln (Chislo) будет происходить следующим образом. Программа будет приостановлена в
ожидании ввода с клавиатуры символов, изображающих целое число. После ввода этих изображений они будут
автоматически преобразованы в соответствующие двоичные значения и присвоены переменной Chislo. Аналогично
организован прием значений действительного, символьного и строкового типа. Если read(readln) не может выполнить
преобразования, то генерируется ошибка № 106 – Invalid numeric format (Неверный формат числовых данных) и выполнение
программы прекращается. Это является стандартной реакцией, которую выполняет программа, взявшая на себя обработку
ошибок. Мы вернемся еще к обработке ошибок, вызванных некорректным вводом, в теме “Процедуры и функции”, где
научимся правильно составлять и использовать вспомогательные подпрограммы. А пока приведем пример применения этих
процедур ввода при организации циклов.
Program Useread;
Var
X, Y : Byte;
Stop : String;
Begin
TextBackGround;
Randomize;
repeat
X:=Random (76);
Y:=Random (23);
GoToXY (X, Y);
TextColor (Random(15));
write(‘***’);
X:=1;
Y:=24;
write (‘Для остановки программы наберите “Стоп“‘);
write (‘Для продолжения – любую клавишу ‘);
readln(Stop);
until (Stop=‘Стоп‘) or (Stop =‘стоп‘);
readln;
End.
Примечание. Здесь использованы следующие процедуры:
GoToXY (X, Y:Byte) - перемещает курсор к элементу экрана с заданными координатами, учитывая, что размер экрана в
текстовом режиме 25 строк по 80 символов.
TextBackGround (Color : Byte) – задает цвет фона.
TextColor (Color : Byte) – задает цвет символов.
Однако, несмотря на простоту и удобство, стандартные процедуры read и readln не обеспечивают всеж потребностей,
возникающих при работе с клавиатурой. Их важнейший недостаток в том, что вместе с приемом символов они выполняют их
отображение на экран (так называемое “эхо на монитор”). В большинстве случаев это либо не нужно, либо недопустимо.
Например, если программа реализует некоторый оконный интерфейс, то вывод вводимых символов испортит изображение.
Кроме того, они рассчитаны только на ввод относительно небольшого подмножества символов (буквы, цифры, знаки
препинания) и частичного использования специальных клавиш (например, Backspace для отмены только что введенного
символа). Эти процедуры не могут распознать нажатие функциональных или редактирующих клавиш и их сочетаний с
управляющими клавишами Ctrl, Alt, Shift. В силу указанных причин процедуры read и readln редко используются в серьезных
программах.
Стандартная функция readKey
Более универсальным средством взаимодействия с клавиатурой является стандартная функция readKey из системного
модуля Crt. Функция вызывается без параметров, возвращает значение символьного типа и работает следующим образом.
Организуется задержка выполнения с ожиданием нажатия клавиши. После того, как нажатие произведено, функция
завершает работу, возвращая код нажатой клавиши. Полученное значение можно использовать далее в программе.
Тривиальный пример работы с функцией readKey, не требующий комментариев, может выглядеть так:
Program UsereadKey;
Uses
Crt;
Var
Sym : Char;
Begin
ClrScr;
while true do
begin
write (‘Введите букву - ‘);
Sym := readKey;
46
writeln (‘Вы ввели букву - ‘, Sym);
if Sym = ‘q’
then
Exit
end
End.
Примечание. Здесь использована процедура Exit, которая позволяет досрочно выйти из программы. Применение этой
процедуры является плохим стилем программирования.
Функция readKey не отображает введенный символ на экран, благодаря чему она широко используется для организации
управления в различных диалоговых программах. В дополнение к этому readKey позволяет отслеживать нажатие более
широкого множества клавиш, опознавая функциональные и редактирующие клавиши и их сочетания с управляющими
клавишами Ctrl, Alt, Shift.
Если говорить более подробно, функция readKey исходит из того, что все множество клавиш и их сочетаний с
управляющими клавишами разбито на два подмножества, которые обычно называют основным и расширенным наборами.
В основной набор входят клавиши букв, цифр, разделителей и знаков препинания, их комбинации с клавишей Shift (или,
что то же самое, при включенном переключателе CapsLock), а также клавиши Tab, BackSpace, Enter и Esc. Если нажата одна
из перечисленных клавиш, то readKey возвратит обычный ASCII-код соответствующего символа.
В расширенном наборе содержатся некоторые (не все) клавиши из основного набора в комбинации с клавишами Ctrl и
Alt, а также функциональные и редактирующие клавиши. Если нажимается одна из клавиш расширенного набора, то
функция readKey возвращает символ с кодом 0 (его представление в программе – chr(0) или #0). В этом случае повторное
обращение к readKey вернет код клавиши из расширенного набора.
Коды клавиш из основного и расширенного наборов в виде, удобном для включения в Турбо Паскаль-программы,
приведены в приложении.
Схема использования функции readKey для общего случая может выглядеть так:
Program UsereadKey2;
Uses
Crt;
Var
Sym : Char;
Begin
ClrScr;
while true do
begin
write (‘Нажмите клавишу‘);
Sym := readKey;
if Sym <> #0
then
begin
{основной набор}
case Sym of
#8 : writeln (‘Вы нажали BackSpace‘);
#9 : writeln (‘Вы нажали Tab‘);
#13 : writeln (‘Вы нажали Enter‘);
#27 : writeln (‘Вы нажали Esc‘);
else
writeln (‘Вы ввели символ ‘,Sym);
end;
if Sym = #27
Then
Exit
end
else
begin
{расширенный набор}
Sym := readKey;{повт. чтение: берем расширенный код}
writeln (‘Вы нажали клавишу с кодом ‘, Ord (Sym)));
end
end
End.
Большинство прикладных диалоговых программ использует описанную технику взаимодействия с клавиатурой. Однако
встречаются случаи, когда возможностей функции readKey оказывается недостаточно. На самом деле функция readKey
воспринимает нажатия не всех клавиш: достаточно попробовать, запустив вышеприведенную программу, нажать клавиши
F11, F12, ввести комбинацию Alt+Esc и т.д. Тому, кто желает более детально изучить работу этой функции, предлагаем
самостоятельно найти в книгах по Турбо Паскалю этот материал. А мы ограничимся вышесказанным.
Стандартная функция KeyPressed
Второй базовой функцией взаимодействия с клавиатурой является функция KeyPressed. В отличие от readKey, она
предназначена не для приема кода нажатой клавиши, а для простой проверки, была ли нажата какая-либо клавиша. Эта
47
функция вызывается без параметров и возвращает значение булевого типа: True, если было нажатие, и False в противном
случае.
Важно понять, что KeyPressed не производит никаких действий с кодом нажатой клавиши, но код может быть далее
прочитан функцией readKey, например,
. . .
if KeyPressed
then
S := readKey;
. . .
Cоотношение этих функций станет более понятным, если рассмотреть их внутреннюю организацию несколько
подробнее. В системной области DOS имеется небольшой буфер, в который операционная система помещает коды нажатых
клавиш. буфер организован в виде очереди, причем помещение кодов производится в ее хвост, а считывание из головы.
Таким образом, каждое обращение к функции readKey извлекает из головы очереди один содержащийся там код. Если буфер
пуст, то организуется задержка выполнения до тех пор, пока в нем не появится код ( появление кода соответствует нажатию
клавиши). Если же к моменту вызова readKey нажатие уже произошло, то есть буфер содержит хотя бы один код, то никакой
задержки не будет. Буфер очень невелик и рассчитан на хранение максимум 15 кодов, что соответствует 15 нажатиям. Кстати
говоря, иногда встречается такая ситуация, когда та или иная программа “не успевает” выбирать коды клавиш из буфера (то
есть нажатия производятся чаще). Ситуация переполнения буфера индицируется звуковым сигналом, после чего коды вновь
нажимаемых клавиш будут пропадать.
Функция KeyPressed не извлекает код из буфера, а только проверяет , пуста ли очередь, и возвращает соответствующее
булево значение. Более подробно рассмотрение системных аспектов работы с клавиатурой смотрите в соответствующей
литературе.
Используя полученные знания решите выбранные с учителем задачи из нижеприведенного перечня.
1. Составьте программу движения круга вверх, вниз, влево, вправо в зависимости от нажатия клавиш управления
курсором.
2. Составьте программу движения заданного слова сверху вниз и обратно, для остановки движения запрограммируйте
нажатие какой-либо клавиши.
3. Составьте программу движения человечка, для остановки движения запрограммируйте нажатие какой-либо клавиши..
4. Составьте программу движения маятника, для остановки движения запрограммируйте нажатие какой-либо клавиши.
5. Составьте программу движения бегущей строки.
6. Составьте программу вывода слова на экран и поочередное мерцание его букв.
7. Составьте программу падания букв из введенного слова.
8. Составьте программу случайного вывода звездочек разного цвета на экран, для вывода запрограммируйте нажатие
какой-либо клавиши.
9. Составьте программу рисования надувающихся пузырей и их лопания по достижению заданного радиуса.
10. Составить программу для вывода на экран бегущей надписи, например: "Для остановки нажми Ctrl+Stop".
11. Самостоятельно придумайте и решите задачу с применением знаний этого занятия.
Занятие 6. Цикл со счетчиком.
Циклы со счетчиком составляют такой класс, в которых выполнение исполнительной части должно повторяться заранее
определенное число раз. Циклы со счетчиком используются довольно часто, и поэтому в языке Паскаль для этих целей
имеется специальная конструкция.
Можно, конечно, циклы со счетчиком моделировать при помощи операторов while и Repeat, но структура цикла со
счетчиком проще.
Общая форма записи цикла со счетчиком
for i := A to B do
for i := A downto B do
begin
begin
...
...
end;
end;
Здесь переменная i - управляющая переменная или переменная цикла,
А - начальное значение переменной цикла,
В - конечное значение переменной цикла.
При переходе к обработке оператора цикла for управляющей переменной присваивается заданное начальное значение.
Затем в цикле выполняется исполнительный оператор (или составной оператор). каждый раз при выполнении
исполнительного оператора управляющая переменная увеличивается на 1 (для for...to) или уменьшается на 1 (для
for...downto). Цикл завершается при достижении управляющей переменной своего конечного значения.
Например,
1) for i := 1 to ListSize do
begin
readln (Number):
S := S +Number;
end;
2) for Dlina := 15 downto 1 do
48
writeln (Sqr(Dlina));
3) for x := 1 to 10 do
for y := 1 to 10 do
writeln (x,’*’,y,’=‘,x*y);
4) for Range := Number+1 to Multi*3 do
writeln (Sqrt(Range));
При использовании цикла for компьютер выполняет за программиста черновую работу по инициализации управляющей
переменной и по ее увеличению (уменьшению) при каждом повторении цикла. Единственное ограничение заключается в
том, что тип управляющей переменной не должен быть real. Переменная цикла не должна изменяться какими-либо
операторами внутри цикла. К ней можно обращаться и использовать в вычислениях, но нельзя присваивать новое значение.
Присваивания могут выполняться только механизмом самого цикла. Таким образом, следующий цикл является
некорректным:
for i := 1 to 10 do
begin
...
i := i-1;
...
end;
Управляющая переменная должна описываться, как и любая другая переменная. Обычно переменная цикла имеет тип
integer, но позднее Вы рассмотрите другие типы данных, которые могут указываться в цикле for.
Внимание! Следует помнить, что управляющая переменная не может быть типа real.
Исполнительная часть цикла может быть либо простым, либо составным оператором. Если начальное значение цикла for
...to больше конечного значения, то никакие операции не выполнятся. Таким образом, следующий оператор не приведет ни к
каким действиям
for j := 1 to 0 do
writeln (j);
Однако цикл, представленный в такой форме, распечатает целые числа от единицы до десяти:
for j := 1 to 10 do
writeln (j);
Как можно догадаться, следующий цикл выполняет счет в обратном порядке
for j := 10 downto 1 do
writeln (j);
Часто исполнительная часть одного из циклов For является новым оператором цикла For. Структуры такого рода
называются вложенными циклами. При завершении внутреннего цикла управляющая переменная внешнего цикла
увеличивается. Повторение этих действий будет продолжаться до вавершения внешнего цикла. Приведенный ниже
вложенный цикл печатает пары чисел, начиная от (1,1), (1,2),... и кончая (10,10):
for х:= 1 to 10 do
for у:= 1 to 10 do
writeln (‘(‘,х,’,’,y,’), ’);
Задание. Выполните две, уже решенные Вами задачи с помощью других видов цикла, используя цикл со счетчиком.
Занятие 7-8. Самостоятельное решение задач.
Выберите с учителем задачи для решения из предложенного ниже списка.
1. Найдите количество точек с целочисленными координатами попадающих в круг радиуса R.
2. Составить программу, которая распечатывает на экране таблицу умножения.
3. Найдите все трёхзначные числа, равные сумме кубов своих цифр. Учтите, что abc=100a+10b+c
4. Составить программу вывода всех трёхзначных чисел, сумма цифр которых равна данному целому числу. Программа
должна печатать именно числа, а не набор цифр.
5. Имитировать на экране работу электронных часов.
6. Напишите программу отгадывания буквы.
7. Задано n троек чисел a,b,c. Определить, сколько из предложенных троек можно использовать для построения
треугольника, если a,b,c - длины его сторон. (Известно, что a  b  c .)
8. Найти сумму целых положительных чисел, больших 20, меньших 100 и кратных 3.
9. Укажите все целые числа, которые увеличатся на 20%, если их цифры записать в обратном порядке.
10.Составьте программу взвешивания продавцом 2,5 кг муки.
11. Составить программу, в которой среди двухзначных чисел печатаются те числа, которые равны сумме своих цифр.
12. Замените буквы цифрами так, чтобы равенство ФАКТ+ФАКТ=НАУКА стало верным. Одинаковым буквам должны
соответствовать одинаковые цифры, разным - разные.
13. Написать программу для создания на экране зигзага, бегущего снизу вверх звездочками.
49
*
** *
*
*
**
**
*
*
***
*
*
** **
*
*
** * *
*
*
* * **
*
*
* ** *
*
*
*
**
*
*
**
*
*
14. В бригаде, работающей на уборке сена, имеется N косилок. Первая из них работала m ч., а каждай следующая на 10
мин. больше, чем предыдущая. Сколько часов проработала вся бригада?
15. В компьютер вводятся по очереди данные о росте N учащихся класса. Определить средний рост учащихся класса.
16. Составьте программу вычисления степени числа а с натуральным показателем n.
17. Каждая бактерия делится на две в течение одной минуты. В начальный момент имеется одна бактерия. Составьте
программу, которая рассчитает количество бактерий на заданное Вами целое значение момента времени.
18. Дана последовательность из N целых чисел. Определить произведение максимального и минимального элементов
этой последовательности.
19. Для двух последовательностей из N и M элементов соответственно найти произведение максимального элемента
первой последовательности и минимального элемента второй последовательности.
20. Дано целое n>0 и последовательность из n действительных чисел, среди которых есть хотя бы одно отрицательное
число. Найти величину наибольшего из отрицательных чисел этой последовательности.
Проверьте себя, ответив на вопросы:
1. Что называется циклом? Приведите пример.
2. Какой алгоритм называется циклическим? Приведите примеры.
3. Какие виды циклов Вы знаете? Почему они имеют такие названия?
4. В теле какого цикла не нужно ставить операторные скобки, даже если выполняется составной оператор?
5. Каким должно быть условие, чтобы тело цикла while ни разу не выполнилось? Почему?
6. Каким должно быть условие, чтобы тело цикла repeat выполнилось один раз? Почему?
7. Каким должно быть условие, чтобы тело цикла for ни разу не выполнилось? Почему?
8. Чему равен шаг изменения параметра цикла в операторе for?
9. Укажите отличительные особенности каждой из конструкций циклов.
10. Будет ли выполняться циклическая часть программы, если логическое выражение в конструкции REPEAT истинно с
самого начала?
11. Что такое стоп-код? Когда его применяют?
12. Какие условия предъявляются к переменной цикла?
13. Какого типа должна быть переменная цикла?
14. Может ли переменная цикла использоваться в вычислениях?
15. Что называется шагом? Что означает выражение “шаг равен пяти”?
16. Что происходит на каждом шаге выполнения тела цикла при выполнении оператора Summa:=Summa+Chislo?
17. Какой цикл Вы применяете чаще? Каковы его достоинства и недостатки?
18. Функция ReadKey и ее применение в программах.
19. Функция KeyPressed и ее применение в программах.
20. Какие клавиши входят в основной набор?
21. Какие клавиши входят в расширенный набор? Как обратится к этим клавишам в программе?
22. Что обозначает слово downto в операторе цикла for?
50
ПРОЦЕДУРЫ И ФУНКЦИИ
Занятие 1. Понятие подпрограммы. Процедуры и функции. Стандартные подпрограммы.
Примеры употребления подпрограмм в решении задач.
Определение. Подпрограмма – это отдельная функционально независимая часть программы. Любая подпрограмма
обладает той же структурой, которой обладает и вся программа.
Подпрограммы решают три важные задачи:
•
избавляют от необходимости многократно повторять в тексте программы аналогичные фрагменты;
•
улучшают структуру программы, облегчая ее понимание;
• повышают устойчивость к ошибкам программирования и непредвидимым последствиям при модификациях
программы.
Очень важно понимать, что в подпрограммы выделяется любой законченный фрагмент программы. В качестве
ориентиров просмотрите следующие рекомендации.
1. Когда Вы несколько раз перепишите в программе одни и те же последовательности команд, необходимость
введения подпрограммы приобретает характер острой внутренней потребности.
2. Иногда слишком много мелочей закрывают главное. Полезно убрать в подпрограмму подробности, заслоняющие
смысл основной программы.
3. Полезно разбить длинную программу на составные части – просто как книгу разбивают на главы. При этом
основная программа становится похожей на оглавление.
4. Бывают сложные частные алгоритмы. Полезно отладить их отдельно в небольших тестирующих программах.
Включение программ с отлаженными алгоритмами в основную программу будет легким, если они оформлены как
подпрограммы.
5. Все, что Вы сделали хорошо в одной программе, Вам захочется перенести в новые. Для повторного использования
таких частей лучше сразу выделять в программе полезные алгоритмы в отдельные подпрограммы.
Подпрограммы могут быть стандартными, т.е. определенными системой, и собственными, т.е. определенными
программистом.
Стандартная подпрограмма (процедура или функция) - подпрограмма, включенная в библиотеку программ ЭВМ,
доступ к которой обеспечивается средствами языка программирования. Вызывается она по имени с заданием фактических
параметров с типом описанным при описании данной процедуры в библиотечке процедур и функций.
Из набора стандартных процедур и функций по обработке одного типа информации составляются модули. Каждый
модуль имеет своё имя (мы уже хорошо знакомы с модулями Crt, Graph). Доступ к процедурам и функциям модуля
осуществляется при подключении этого модуля (Uses Crt, Graph).
Help содержит подробные описания предусмотренных средой программирования процедур и функций. Для вызова
помощи при работе со стандартными процедурами и функциями нужно поставить на имя подпрограммы курсор и нажать
клавиши <Ctrl+F1>. Описание процедур и функций в Help строится по стандартному принципу.
Задание. Вызовите помощь по функции Cos и рассмотрите предоставленную информацию.
Сначала идет краткое описание подпрограммы (в одну фразу). Далее под словом Declaration (Объявление) следует
интерфейсная часть процедуры или функции, которая особенно часто необходима для определения типа переменных при
обращении к ним. Далее под словом Target приводятся платформы, на которых может использоваться подпрограмма:
Windows, real (реальный режим DOS), protected (защищенный режим DOS). После слова Remarks следуют заметки,
содержащие необходимые детали использования. В разделе See Also приведены имена подпрограмм, связанных с данной по
смыслу или по совместному применению. Если перемещать курсор по этим именам (они выделяются курсорной рамкой), то
выбрав одно из них (нажать клавишу <Enter>), можно получить справку по следующей функции. Каждая процедура и
функция сопровождается примером применения, переключение к которому дает последняя строка программы. Любой текст
из Help может быть скопирован в редактируемый файл обычными приемами копирования через буфер. Копирование
примеров или заголовков функций облегчает работу.
Существует другой способ получения помощи по процедурам и функциям. Для этого нужно использовать пункт меню
Help/Reserved words (зарезервированные слова) или Help/Standard units (стандартные модули).
Задание. Рассмотрите список процедур и функций, выберите какие-либо и просмотрите предлагаемую информацию.
В стандартных модулях содержится большое количество стандартных подпрограмм, но невозможно создать модуля,
который бы содержал все нужные программисту подпрограммы. Поэтому большую роль в создании программ играют
собственные подпрограммы, которые создает программист для решения конкретной задачи.
Существует два способа объединения программ и подпрограмм:
1. Текст подпрограмм может быть приведен в разделе описания использующей их программы.
51
2. Подпрограммы группируются в отдельных файлах, имеющих специальную структуру – модулях. Для того чтобы
основная программа могла использовать модуль, он должен быть подключен к основной программе.
Первый способ применяется тогда, когда программа в целом не очень большая, а ее подпрограммы, скорее всего, не
будут использоваться в других программах. Второй способ желателен, в частности, для той программы, которую Вы будете
создавать в качестве курсовой работы при завершении учебы в городской школе юного программиста.
Структура текста подпрограммы соответствует структуре текста основной программы за двумя исключениями:
• подпрограмма начинается с заголовка, содержащего имя подпрограммы, передаваемые в нее и возвращаемые от нее
периметры, запись заголовка подпрограммы отличается от заголовка программы;
•
подпрограмма кончается не точкой, а точкой с запятой.
Вызов подпрограммы происходит при каждом употреблении ее имени в основной (или вызывающей ) программе. При
вызове подпрограммы выполнение основной программы приостанавливается, и управление передается в подпрограмму, где
выполняются команды, заданные в ней. Подпрограмма завершается, если выполнены все ее процедуры до завершающего
слова End или по специальной команде выхода из подпрограммы Exit. По окончании работы подпрограммы управление
возвращается основной программе, иначе говоря, к первой команде, следующей за обращением к этой подпрограмме.
В языке Pascal определяются два типа подпрограмм – процедуры и функции. Основное различие между процедурой и
функцией состоит в том, что процедура только выполняет какую-либо законченную последовательность действий, не
возвращая результата работы в основную программу, а функция и выполняет действия, и возвращает результат.
Например, вызов функции
M:= MIN (X, Y)
вернет в основную программу значение наименьшего из двух чисел и это значение будет присвоено переменной M.
Любая подпрограмма должна быть описана до того, как она будет вызвана в программе или в другой подпрограмме. Все
переменные, которые использует подпрограмма, могут быть либо глобальные либо локальные.
Определение. Глобальными называются переменные, объявленные в основной программе и доступные как программе,
так и всем ее подпрограммам.
Определение. Локальными называются переменные, объявленные внутри подпрограммы и доступные только ей самой.
Обмен информацией между основной программой и подпрограммой может осуществляться только с помощью
глобальных переменных.
Подпрограмма может использовать любые глобальные переменные кроме тех, которые имеют те же имена, что и
локальные переменные. Переменные с совпадающими именами, которые могут быть описаны в основной программе или
других подпрограммах, не имеют ничего общего с локальными переменными. если переменная описана. Если переменная
описана в основной программе и не переопределена в подпрограмме, она может использоваться в подпрограмме. Память для
локальных (т.е. описанных в подпрограмме) переменных выделяется на время исполнения данной подпрограммы в
специальной области, называемой стеком. При завершении работы подпрограммы память освобождается, поэтому все
внутренние результаты работы подпрограммы не сохраняются от одного обращения к другому.
Если говорить о плюсах использования в программировании подпрограмм, то можно назвать следующие:
• Программы с использованием подпрограмм позволяют реализовать один из самых прогрессивных методов
программирования – структурное программирование.
•
Программа становится более читаемой.
• Экономия памяти, которая получается из-за того, что память для хранения переменных, используемых в
подпрограммах, выделяется только на время работы подпрограммы.
В языке Паскаль выделяют два вида подпрограмм: процедуры (Procedure) и функции (Function). Любая программа может
содержать несколько процедур и функций. Структура любой подпрограммы аналогична структуре всей программы.
Подпрограмма должна быть описана до того, как будет использована в программе или другой подпрограмме.
Процедуры и функции объявляются в разделе описания вслед за разделом переменных.
Тогда общая структура программы выглядит так:
Рrogram hh;
Label;
{описание меток}
Const;
{описание констант}
Type;
{описание типов}
Var;
{описание переменных}
Procedure;
{описание процедур}
Function; {описание функций}
52
Begin
. . .
. . .
end.
Выполнение программы начинается с операторов основной программы. При необходимости вызывается подпрограмма
и начинают действовать её операторы. Затем управление передаётся в основную программу, которая продолжает
выполняться.
Обращение к подпрограмме - переход к выполнению подпрограммы с заданием информации, необходимой для ее
выполнения и возврата.
Подпрограмма вызывается по своему имени с указанием необходимых параметров.
На этом занятии рассмотрим примеры организации наиболее простого вызова подпрограмм.
Задание. Рассмотрите решение предложенных задач, наберите на компьютере, проверьте работоспособность, внесите
свои изменения и дополните своими комментариями.
Задача 1. Написать программу, состоящую из трех подпрограмм и основной программы. Подпрограммы должны
организовывать ввод чисел, вычисление их суммы и вывод результата.
Program AkulovE;
Uses
Crt;
Var
x, y : LongInt;
Procedure Input;
Begin
TextColor(12);
writeln('По вызову активизировалась процедура "Input"',#10);
TextColor(7);
writeln('Введите два числа через пробел - ');
readln(x, y);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Summa;
Begin
TextColor(14);
writeln('Для сложения подключилась процедура "Summa"',#10);
x:=x+y;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Output;
Begin
TextColor(10);
writeln('Заключительная часть. Процедура "Output"',#10,#13);
TextColor(7);
writeln('Их сумма - ',x);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
ClrScr;
Input;
Summa;
Output;
readln;
End.
Задача 2. Найти среднее арифметическое двух чисел.
Program Fadeev;
Uses
Crt;
Var
A, B : integer;
Rez :real;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function SredArif(A, B:integer):real;
53
Begin
SredArif:=(A+B)/2;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
ClrScr;
write('Введите два числа ');
readln(A,B);
Rez:=SredArif(A,B);
write('Cреднее арифметическое этих чисел равно ',Rez:5:3);
readln;
End.
Занятие 2. Формальные и фактические параметры. Вызов по ссылке и по значению. Локальные и
глобальные переменные и подпрограммы
Формальные и фактические параметры
Формальные параметры подпрограммы указывают, с какими параметрами следует обращаться к этой программе
(количество примеров, их последовательность, тмпы). Они задаются в заголовке подпрограммы в виде списка формальных
параметров, разбитого на группу формальных параметров включаются однотипные параметры одной категории.
Все формальные параметры можно разбить на четыре категории:
•параметры значения (эти параметры в основной программе подпрограммой не меняются );
•параметры - переменные ( эти параметры подпрограмма может изменить в основной программе );
•параметры-константы ( используются только в версии 7.0);
•параметры-процедуры и параметры-функции (т.е. процедурного типа).
Для каждого формального параметра следует указать имя и, как правило, тип, а в случае параметра-переменной или
параметра-константы - его категорию. Имена параметров могут быть любыми, в том числе и совпадать с именами объектов
программы. Необходимо лишь помнить, что в этом случае параметр основной программы с таким именем становится
недостурным для непосредственного использования подпрограммой. Тип формального параметра может быть практически
любым, однако в заголовке подпрограммы нельзя вводить новый тип. Например, нельзя писать
function Max( A: array[ 1..100 ] of real ): real;
Чтобы правильно записать этот заголовок, следует в основной программе ввести тип-массив, а затем использовать его в
заголовке:
type tArr =array [ 1..100 ] of real;
function Max ( A: tArr ) : real;
При обращении к подпрограмме формальные параметры заменяют на соответствующие фактические вызывающей
программой или подпрограммы.
Вызов по ссылке и по значению
Список параметров, задаваемый в заголовке процедуры и функции, обеспечивает связь подпрограммы с вызывающей
программой. Через него в подпрограмму передаются исходные данные и возвращается результат. При этом предусмотрено
два принципиально отличающихся механизма передачи параметров – по значению и по ссылке. Синтаксически эти два
способа отличаются употреблением слова Var перед соответствующей переменной в заголовке подпрограммы. Если это
слово имеется, то переменная передается по ссылке, а если нет – по значению.
При вызове по значению в подпрограмме создаются переменные в соответствии с объявлениями в заголовке
подпрограммы. Эти переменные существуют только на время выполнения подпрограммы. В вызывающей программе в
качестве аргумента подпрограммы может использоваться не только переменная, но и выражение. В начале выполнения
подпрограммы значение этой переменной или выражения присваиваются внутренней временной переменной подпрограммы.
Когда подпрограмма завершается, используемые подпрограммой переменные не сохраняют своего значения, поэтому
передачу данных по значению можно использовать только для передачи данных в подпрограмму, но не для получения от нее
результатов.
Приведем примеры:
1. Передачу данных по значению использует процедура установки даты в операционной системе, заголовок которой
Procedure SetDate (Year, Month, Day : Word);
имеет три передаваемых в подпрограмму величины. Ее вызов в основной программе может иметь различные формы:
54
• SetDate (MyYear, MyMonth, MyDay); где MyYear, MyMonth, MyDay – переменные типа Word, которые описаны в
основной программе и должны иметь при обращении к процедуре определенные значения. При вызове процедуры эти
значения присваиваются внутренним переменным процедуры Year, Month, Day.
• SetDate (MyYear+1, MyMonth div 2, MyDay); при вызове процедуры используются арифметические выражения,
которые вычисляются при вызове. В подпрограмму поступает результат вычислений.
•
SetDate (1999, 1, 31); где в подпрограмму передаются значения констант.
При вызове по ссылке в подпрограмме память под передаваемые переменные не отводится. Основная программа
передает в подпрограмму не значение переменной, а ссылку на место в памяти основной программы, где расположена
некоторая переменная. Подпрограмма, поизводя некоторые действия с этой переменной, в действительности производит
действия с переменной основной программы, поэтому после выполнения процедуры изменения, совершенные с
переменными основной программы, сохраняются. Этот механизм используется для получения от подпрограммы результатов
ее выполнения. Понятно, что при вызове подпрограмм с передачей данных по ссылке невозможно использовать в качестве
аргументов выражения или константы, так как они не имеют адреса для передачи.
Приведем пример.
Для получения от операционной системы даты используется процедура, имеющая заголовок
Procedure GetDate (Var Year, Month, Day : Word);
Она имеет три переменные, передаваемые по ссылке. Если мы аналогично предыдущему случаю, вызовем эту
процедуру из основной программы командой
Procedure GetDate (MyYear, MyMonth, MyDay);
процедура разместит свои переменные Year, Month, Day в тех же ячейках памяти, что и переменные основной
программы MyYear, MyMonth, MyDay. После завершения подпрограммы эти переменные сохраняют полученные в
процедуре значения.
В 7 версии Borland Pascal предусмотрен новый механизм передачи в подпрограмму параметров по значению. Этот
механизм используется, если значение параметра не должно изменяться – это параметры-константы.
Объявление параметра-константы в заголовке подпрограмм имеет вид
const <имя константы>:<тип константы>
Попытка изменить данный параметр в подпрограмме обнаруживается компилятором как ошибка. При вызове из
основной программы подпрограммы с таким параметром могут использоваться те же способы, что и при передачи
параметров по значению:
•
константа может быть задана в явном виде;
•
может быть указана переменная или выражение совместимого с константой типа.
Например, Procedure Primer (Const x : byte).
Внимание! При вызове процедур необходимо следить за соответствием типов данных в вызывающей программе и
подпрограмме.
Параметры-значения
Параметры-значения передаются основной программой в подпрограмму через стек в виде их копий и, следовательно,
собственный параметр программы подпрограммой измениться не может.
Параметр-значение указывает в заголовке подпрограммы своим именем и через двоеточие - типом. Тип параметразначения может быть любым за исключением файлового.
Если параметров - значения одного типа несколько, их можно объединить в одну группу, перечислив их имена через
запятую, а затем уже указать общий тип. Как отмечалось выше, отдельные группы параметров отделяются друг от друга
точкой с запятой.
Пример.
procedure Inp ( Max, Min: real ; N: Word );
function Mult (X, Y: integer): real;
В качестве фактичного параметра на месте параметра-значения при вызове подпрограммы может выступать любое
выражение совместимого для присваивания типа, не содержащее файловую компоненту, например:
Inp(Abs (Z), - Abs (T), 2 * K);
M:=Mult(X + Y, X - Y);
MA:=MAX( B, 5 );
55
Локальные и глобальные переменные и подпрограммы.
Если переменная или константа описана в основной программе, она считается глобальной, и ее могут использовать
любые процедуры и функции данной программы. Переменные, описанные внутри подпрограммы, называются локальными и
могут быть использованы только внутри данной подпрограммы. Локальные переменные могут быть описаны как в заголовке
программы, так и в разделе описания переменных. при совпадении имен глобальных и локальных переменных, локальные
определения в пределах своего действия отменяют действия глобальных, и эти переменные никак не связаны между собой.
Рассмотрим две почти одинаковые программы.
Program Variant1;
Var
X : real;
Program Variant2;
Var
X : real;
Procedure writeX;
Var
x : real;
Begin
write(x)
End;
Procedure writeX;
Begin
X := Pi;
writeX
End.
Begin
write(x)
End;
Begin
X := Pi;
writeX
End.
Нетрудно догадаться о решаемой задаче: присвоить глобальной переменной х некоторое значение, а затем напечатать
это число через специальную процедуру.
Во втором варианте программы переменная с именем Х описана только в основной программе, поэтому она, как
глобальная переменная, доступна в подпрограмме. В результате будет напечатано значение числа П.
В первом варианте переменная х переопределена в подпрограмме, таким образом, в подпрограмме имеется локальная
переменная х, ничем не связанная с переменной Х основной программы. Поскольку этой локальной переменной не
присвоено значение, будет напечатано случайное число, содержащееся в соответствующей ячейке памяти.
Возникает вопрос, какова роль локальных переменных, нельзя ли все переменные описать как глобальные?
Процедура должна быть, по возможности, независима от основной программы, поэтому все переменные, нужные только
в пределах процедуры, должны описываться как локальные. Общение основной программы с подпрограммой должно, как
правило, идти через список параметров процедуры, что придает подпрограммам необходимую гибкость. Вместе с тем,
излишне большое число параметров, передаваемое в подпрограмму при ее вызове, замедляет работу программы, поэтому не
следует пренебрегать использованием в подпрограммах глобальных переменных.
Кроме локальных переменных, в программах могут быть и локальные подпрограммы. Это подпрограммы, текст которых
размещен внутри текста подпрограммы более высокого уровня. Использование таких подпрограмм, как и локальных
переменных, ограничивается подпрограммой, к которой они принадлежат.
Локальность или глобальность являются понятиями относительными. Программа с вложенными в нее подпрограммами
представляет собой иерархическое дерево. Объект, локальный по отношению к более высокому уровню иерархии, ведет себя
как глобальный по отношению к подпрограммам более низкого уровня.
Задание. Найдите в приведенных выше примерах локальные и глобальные переменные, формальные и фактические
параметры, какие параметры переданы по ссылке, а какие – по значению.
Занятие 3. Процедуры.
Структура процедуры имеет следующий вид:
Procedure <имя процедуры>(формальные параметры : их тип);
Var
(локальные переменные)
begin
. . .
end;
Процедура вызывается по имени:
<имя процедуры> (фактические параметры);
56
Значение каждого фактического параметра при вызове процедуры передаётся формальному параметру. Временно
управление передаётся процедуре. После завершения работы процедуры управление возвращается в основную программу.
Каждый формальный параметр указывается вместе со своим типом. Соответствующий ему фактический параметр
указывается без типа. Между формальными и фактическими параметрами должно быть соответствие по количеству
параметров, по их типу и порядку следования.
Заголовок процедуры может выглядеть так:
PROCEDURE GG(a,b,c:integer);
вызываться так: GG(3,n,m)
Здесь a,b,c–формальные параметры, а 3, n, m–фактические параметры
Таким образом в процедуру передаются значения: a=3, b=n, c=m
Переменные описанные в процедуре после слова Var, являются внутренними переменными процедуры или
промежуточными, они не являются данными для операций внутри процедуры и не являются результатом её выполнения, а
нужны лишь для промежуточных действий. Данные и результаты описываются в круглых скобках после имени процедуры.
Перед описанием переменных–результатов пишут служебное слово var.
Например :
Procedure express(a,b,c : real; var x,y:real);
Var
z : real;
begin
z:=a+ b+ c;
x:=sqr(z);
y:=sqrt(z);
end ;
Эту процедуру можно вызвать следующим образом:
express(7.6, 6.8, 9.5, x1, x2);
Формальные входные параметры a, b, c принимают значения соответствующих фактических параметров a=7.6; b=6.8;
c=9.5.
При этих значениях выполняется процедура. Результатом выполнения процедуры являются x, y, которые передают
свои значения соответствующим фактическим параметрам x1, y1. Таким образом в основной программе будем иметь x1=20,
y1=22.
В качестве фактических параметров могут быть константы, переменные, выражения, массивы. В качестве формальных
параметров могут быть только переменные(константы и выражения недопустимы).
Рассмотрите примеры решения задач.
Задача 1. Описать пpоцедуpу "аналитического" сложения обыкновенных дpобей, вычисляющую по числам P1,Q1,P2,Q2,
являющимися числителями и знаменателями дробей и последняя дpобь несокpатима. Результат вывести в виде
P1 P2
P
---- + ---- = --Q1 Q2 Q
Program Kudashev_Artem;
Uses
Crt;
Var
P1, Q1, P2, Q2, P, Nod_2, Celaya : Longint;
Dop_1, Dop_2 : integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Nod(A,B : Longint;Var Nod_2 : Longint);
Begin
Nod_2:=A*B;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Vivod_Otveta(Celaya,P1,Q1,P2,Q2,P,Nod_2,X,Y:integer);
Var
i : integer;
Begin
if P > Nod_2
then
begin
Celaya:=P div Nod_2;
P:=P mod Nod_2;
end
57
else
begin
Gotoxy(X+1,Y);
write(P1);
Gotoxy(X+10,Y);
write(P2);
if P = 0
then
begin
Gotoxy(X+1,Y+1);
write('---- + ---- = ',Celaya,'');
Gotoxy(X+1,Y+2);
write(Q1);
Gotoxy(X+10,Y+2);
write(Q2);
end
else
begin
for I:=10 downto 2 do
begin
if ((P mod I) = 0) and ((Nod_2 mod I) = 0) then
begin
P:=P div I;
Nod_2:=Nod_2 div I;
end;
end;
Gotoxy(X+19,Y);
write(P);
Gotoxy(X+1,Y+1);
write('---- + ---- = ',Celaya,' ------');
Gotoxy(X+1,Y+2);
write(Q1);
Gotoxy(X+10,Y+2);
write(Q2);
Gotoxy(X+19,Y+2);
write(Nod_2);
end;
end;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Podshet(P1, Q1, P2, Q2 : Longint);
Begin
Nod(Q1,Q2,Nod_2);
Dop_1:=Nod_2 div Q1;
Dop_2:=Nod_2 div Q2;
P:=(Dop_1*P1)+(Dop_2*P2);
if P > Nod_2
then
begin
Celaya:=P div Nod_2;
P:=P mod Nod_2;
end;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
Clrscr;
Q1:=0;
Q2:=0;
Textcolor(LightCyan);
writeln(' P1 P2 P');
writeln('---- + ---- = ---');
writeln(' Q1 Q2 Q');
writeln;
write('Введите P1 -> ');
readln(P1);
while Q1 = 0 do
58
begin
write('Введите Q1 -> ');
readln(Q1);
if Q1 = 0
then
writeln('Число Q1 не должно pавнятся 0');
end;
write('Введите P2 -> ');
readln(P2);
while Q2 = 0 do
begin
write('Введите Q2 -> ');
readln(Q2);
if Q2 = 0
then
writeln('Число Q2 не должно pавнятся 0');
end;
Podshet(P1,Q1,P2,Q2);
Vivod_Otveta(Celaya,P1,Q1,P2,Q2,P,Nod_2,2,10);
readkey;
End.
Задача 2. Для заданного N составить алгоритм вычисления значения выражения:
(1*1)
(2*2)
(3*3)
(N*N)
----------- * ------------ * ----------- * * ----------(1+(3*3))
(2+(3*3))
(3+(3*3)) ... (N+(3*3))
Program Kudashev_Artem;
Uses
Crt;
Var
N, Ch, Zn, Celaya : Longint;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Podshet(N : Longint; Var Chislitel, Znamenatel : Longint);
Var
A, Z : integer;
Begin
Chislitel:=1;
Znamenatel:=1;
for A:=1 to N do
begin
Chislitel:=Chislitel*(A*A);
Znamenatel:=Znamenatel*(9+A);
for Z:=2 to 10 do
begin
if ((Chislitel mod Z) = 0) and ((Znamenatel mod Z) = 0)
then
begin
Chislitel:=Chislitel div Z;
Znamenatel:=Znamenatel div Z;
end;
end;
end;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
Clrscr;
TextBackground(Black);
Textcolor(Yellow);
write('Введите N -> ');
read(N);
Podshet(N,Chl,Zn);
Celaya:=Ch div Zn;
Chislitel:=Ch mod Zn;
writeln('Ответ');
writeln(' ',Ch);
59
writeln('',Celaya,' ---------');
writeln(' ',Zn);
readkey;
End.
Задание. Приготовьтесь объяснить решение задач учителю.
Задачи для самостоятельного решения
1. Написать программу подсчета суммы М введенных с клавиатуры чисел.
2. Составить программу поиска большего из трёх чисел, с использованием процедуры поиска большего из двух чисел.
3. Напишите программу (процедуру), которая будет возвращать значение среднего арифметического двух своих
параметров а и b.
4. Написать процедуру, меняющую значения двух переменных а и b местами.
5. Используя процедуру обмена значений двух переменных, упорядочьте по возрастанию переменные a, b, c.
6. Определить длину окружности L и площадь круга S. Радиус окружности задается с клавиатуры. Вычисление S и L
оформить в виде процедуры.
7. Постройте диалоговой алгоритм, позволяющий выводить несколько графиков по выбору в одной системе координат.
Для построения графиков используйте подпрограммы.
8. Напишите подпрограмму, которая будет вычислять сумму правильных делителей заданного числа n. Правильными
делителями числа n, являются все делители этого числа, за исключением его самого.
Занятие 4. Процедуры в графическом режиме.
Творческое задание. Составьте программу движения какого-либо объекта с использованием процедур рисования этого
объекта по переданным в процедуру координатам, смещающихся с помощью цикла в основной программе.
Примечание. Если у Вас появилась идея применения процедуры в графическом режиме для решения задачи другого
типа, то - дерзайте!
Занятие 5. Функции.
Другой вид подпрограммы–функция–оформляется аналогично процедуре. Отличительные особенности функции: она
имеет только один результат выполнения (но может иметь несколько входных параметров); результат обозначается именем
функции и передаётся в основную программу.
Функция оформляется в следующем виде:
Function <имя функции>(формальные параметры: тип): тип значения функции;
Var
. . .
Begin
. . .
End ;
Вызывается функция по её имени с указанием фактических параметров.
Вызов функции можно делать непосредственно внутри выражения. При вызове функции тип не указывается.
Пример. Пусть требуется найти (x!-y!)*d!.
Напомним, что х! представляет собой произведение n чисел натурального ряда : х! = 1*2*3*......*х
Function fac(n:integer): integer;
Var
p,i: integer;
Begin
p:=1;
for i:=2 to n do
p:=p*i;
fac:=p;
End ;
Вызвать можно так: f:=(fac(x)-fac(y))*fac(d).
60
Внимание! В теле функции обязательно должен быть хотя бы один оператор присваивания, где в левой части стоит имя
функции, а в правой – ее значение. Иначе, значение не будет определено.
Различие между процедурами и функциями.
Функции – это процедуры особого характера, результатом работы которых является некоторое значение, подобное
переменной.
Функция, как и процедура, может иметь список параметров, следующих за именем функции в круглых скобках. Но если
имя процедуры используется только для ее вызова, то с именем функции связывается ее значение. На примере сложения
двух целых чисел проиллюстрируем возможности Турбо Паскаля 7.0 по оформлению программ при помощи процедур и
функций, а также рассмотрим различия между этими двумя подходами.
Program ProcedureAndFunction;
Uses
Crt;
Var
a, b, SumNumbers : integer;
Procedure Summa1(Var Sum: integer; a, b : integer);
Begin
Sum:= a+b;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Sum(a, b : integer) : integer;
Begin
Sum:= a+b;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
ClrScr;
a := 12;
b := 15;
Summa1(SumNumbers, a, b);
writeln ('С помощью процедуры сумма чисел равна ',SumNumbers);
writeln ('С помощью функции сумма чисел равна ',Sum(a, b));
End.
Вызов процедуры производится по ее имени. Наряду с параметрами-значениями a и b, которые подлежат сложению, в
списке параметров присутствует параметр-переменная Sum, который содержит возвращаемое процедурой значение – сумму.
Функция же имеет только два параметра. Это связано с тем, что само имя функции представляет собой идентификатор
параметра, значение которого после окончания работы функции равно результату вычисления. Этот параметр соответствует
параметру-переменной Sum процедуры. При объявлении функции ей в соответствие ставят определенный тип данных – тип
возвращаемого функцией значения.
Объявление функции
Function Sum(a, b : integer) : integer;
внешне похоже на объявление переменной Sum типа integer. Тип функции объявляется следом за списком параметров –
после закрывающейся скобки этого списка и двоеточия.
Процедуры и функции в Турбо Паскале отличаются не только описанием, но и способом их вызова. Так вызов функции
Sum можно произвести в следующей форме
SumNumbers:= Sum(a,b);
Если не обращать внимания на наличие списка параметров, то этот оператор выглядит как присвоение переменной
SumNumbers значения переменной Sum. Компилятор, кончно же, знает, что Sum – это имя функции (т.к. определение
предшествует использованию) и организует вычисления соответствующим образом. Точно так же, как константа или
переменная, вызов функций может использоваться в списках параметров оператора write (см. программу), что для процедур
невозможно.
Последнее отличие процедур от функций заключается в необходимости присваивания результата вычисления в теле
функции переменной, имя которой совпадает с именем функции. Если такое присваивание в теле функции не выполнено, то
функция не возвратит никакого результата (точнее возвратит произвольный результат).
Итак, из вышесказанного возьмите на заметку следующее.
Оформлять подпрограмму как функцию целесообразно только в том случае, если ожидается результат работы
подпрограммы. Если же последовательность команд ориентирована на выполнение некоторого действия (выдача
информации на экран и т.п.), целесообразно оформлять ее как процедуру.
61
Задачи для самостоятельного решения
1. Найти сумму цифр числа.
2. Найти первую цифру числа.
3. Найти количество делителей числа.
4. Найти числа из промежутка от А до В, у которых больше всего делителей.
5. Найти сумму всех делителей числа.
6. Определить, является ли число совершенным, то есть равно ли оно сумме своих делителей, кроме самого себя.
7. Определить, является ли число простым.
8. Среди чисел из интервала от А до В найти все простые.
9. Составьте программу, проверяющую, является ли число палиндромом (например, число 12421 – палиндром).
10. Определить, является ли число автоморфным, то есть квадрат этого числа заканчивается этим же числом, например,
числа 6 и 25, т.к. их квадратами являются числа 36 и 625.
Занятие 6. Решение задач
Выберите с учителем задачи . Для их решения используйте как пройденный материал, так и материал ниже следующих
занятий.
1. Даны координаты вершин четырехугольника ABСВ. Найти сумму длин его диагоналей. Данные для ввода: A(0,1),
B(2,5), C(4,8), D(2,0).
2. Найти сумму площадей треугольников ABC и МНР, заданных координатами вершин. Данные для ввода: А(0;1),
В(3;1), С(4;2), М(6;7), Н(4;3), Р(3;8).
3. Найти сумму периметров треугольников ABC и МНР, заданных координатами вершин. Данные для ввода: А(0;1),
В(3;1), С(4;2), М(6;7), Н(4;3), Р(3;8).
4. Вычислить 1!+2!+3!+......+N! . Вычисление факториала организовать как функцию fact(var r:integer):longint.
5. Составить программу поиска большего из трёх чисел, с использованием процедуры поиска большего из двух чисел.
6. Определить длину окружности С и площадь круга S, удаление L центра окружности от начала координат О.
Координаты центра окружности равны X и Y, радиус R.
Вычисление С, S, L оформить в виде процедуры.
7. Составьте функцию для определения значений n!, m!,(n-m)!
8. Напишите функцию CUBЕ, которая возвращает куб ее числового параметра.
9. Напишите функцию, которая возвращает объем сферы, радиус которой передается как параметр.
10. Для заданного х составить алгоритм вычисления значения выражения:
1
x
1!

x
2
2!

x
3
3!
....
x
n
n!
11. Для заданного х составить алгоритм вычисления значения выражения:
12
22
32
42
n2
*
*
*
*...
*
1 + 32 2  32 3  32 4  32
n  32
12. Напишите функцию CUBЕ, которая возвращает куб ее числового параметра.
13. Составьте программу для определения значений n!, m!,(n-m)!
14. Вычислить 1!+2!+3!+......+N! . Вычисление факториала организовать как функцию fact (var r:integer) : longint.
15. Напишите функцию, которая возвращает объем сферы, радиус которой передается как параметр.
16. По координатам вершин двух треугольников, определите их площадь и выведите на печать площадь максимального
треугольника. Вычисление длины стороны, площади треугольника оформите в виде функций.
17. Дана отрезки а, b, c, d. Для каждой тройки отрезков, из которых можно построить треугольник, напечатайте площадь
данного треугольника. Воспользуйтесь функциями определения возможности создания треугольника и вычисления площади.
18. С клавиатуры вводятся числа, до тех пор, пока не будет введено первое отрицательное число. Определите, сколько
чисел из входного потока, равно сумме кубов своих цифр. При решении задачи используйте функцию, которая будет
проверять, равно ли натуральное число сумме кубов своих цифр.
62
19. Напишите функцию логического типа, проверяющую, являются ли все цифры, входящие в натуральную запись,
числа N различными.
20. Даны два натуральных числа. Проверить, является ли второе число перевертышем первого.
21. Составьте программу подсчета числа всех натуральных чисел, меньших М, квадрат суммы цифр которых равен Х.
22. Составьте программу подсчета числа всех натуральных чисел, меньших М и делящихся на каждую из своих цифр.
23. Составьте программу нахождения наименьшего натурального N-значного числа Х (X>=10), равного утроенному
произведению своих цифр.
24. Дано натуральное число. Определите, сколько четных цифр используется в записи этого числа.
25. Дана последовательность К чисел. Определите, сколько чисел этой последовательности содержит в своей записи все
цифры больше некоторого числа n введенного с клавиатуры.
26. Для последовательности вводимых с клавиатуры чисел, выведите суммы цифр каждого введенного числа. Признак
конца ввода - число -1.
Для любознательных. Особенности использования процедур и функций.
Опережающее описание процедуры (директива Forward)
Описание процедуры, содержащее вместо блока операторов директиву Forward, называют опережающим описанием.
С помощью этой директивы Вы можете объявить заголовок некоторой процедуры или функции, не описывая при этом
основной блок подпрограммы.
Возможность создавать "опережающее описание" для процедур позволяет решать проблемы следующего рода:
предположим, в некоторой программе Вы используете две процедуры с именами Proc1 и Proc2, причем процедура Proc1
использует вложенную процедуру Proc2, а процедура Proc2 в свою очередь использует процедуру Proc1. Т.к. Вы не можете
использовать необъявленную ранее процедуру, то у Вас возникает проблема, связанная с необходимостью развязать
"зацикленные" друг на друге процедуры Proc1 и Proc2. Использование директивы Forward при объявлении процедуры Proc1
позволяет решить эту проблему.
Program Primer;
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Proc1 (список формальных параметров); Forward;{заголовок первой процедуры}
Procedure Proc2 (список параметров); {заголовок второй процедуры}
Begin{Основной блок процедуры Proc2}
. . .
Proc1 (список фактических параметров); {Вызов процедуры Proc1}
. . .
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Proc1 (список параметров);
Begin{Основной блок процедуры Proc1}
. . .
Proc2 (список фактических параметров); {Вызов процедуры Proc2}
. . .
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
. . . {Тело основной программы}
End.
Процедуры с ближним и дальним адресом вызова
Турбо Паскаль поддерживает две модели вызова процедур – ближнюю Near и дальнюю Far. Между этими двумя
моделями существует ряд различий.
Процедуры, созданные с использованием модели Near, получаются более
быстродействующими, но могут быть вызваны только из модуля, в котором они описаны.
Процедуры, созданные с использованием модели Far, могут быть вызваны из любого места программы. Недостатком
этих процедур является их медлительность.
Компилятор на основе составленного описания процедуры может автоматически выбирать оптимальную модель вызова.
Если же при разработки программы возникла необходимость задать данной процедуре конкретную модель вызова, то в
описании данной процедуры перед ее основным блоком необходимо указать директиву Near или Far.
Параметры-процедуры и параметры-функции
Турбо Паскаль позволяет рассматривать функции и процедуры как объекты, которые можно присвоить переменным и
которые могут выступать в качестве параметров.
Как только процедурный тип определен, можно объявлять переменные этого типа. Такие переменные называются
процедурными переменными. Они могут быть использованы в качестве формальных параметров при вызове процедур и
63
функций. Подобно тому, как целочисленной переменной можно присвоить целочисленное значение, процедурной
переменной можно присвоить процедурное значение.
Как и во всех других операциях присваивания, переменная в левой части и переменная в правой части оператора
присваивания должны быть совместимыми по присваиванию. для того чтобы считаться совместимыми по присваиванию,
процедурные типы должны иметь одинаковое число параметров, параметры в соответствующих позициях должны быть
тождественных типов; наконец, типы результатов функций должны быть идентичны.
Процедуры и функции должны быть объявлены с директивой Far (использование дальнего типа вызова подпрограмм) и
откомпилированы в состоянии {$F+}. А также они не должны быть:
стандартной подпрограммой;
вложенной подпрограммой;
Inline процедурой или функцией (п/программы, записанные в машинных кодах);
Interrupt процедурой или функцией (п/программы обработки прерываний).
При использовании параметров-процедур или параметров-функций в списке перед соответствующими формальными
параметрами указывается зарезервированное слово Procedure или Function.
Например,
Procedure Exampl(k,l : integer; Var M : real; Procedure Prob; Function Step : real);
В списке формальных параметров процедуры Exampl:
k, l – параметры-значения;
M – параметр-переменная;
Prob – параметр-процедура;
Step – параметр-функция.
При вызове подпрограммы на место формальных параметров-процедур и параметров-функций осуществляется
подстановка соответствующих фактических процедур или функций.
Параметры процедурного типа особенно полезны в ситуациях, когда над множеством процедур или функций
выполняются общие действия.
Например, посмотрите программу, которая с помощью одной и той же процедуры печати таблицы выводит на экран три
таблицы арифметических функций (сложения, умножения и произведения суммы на разность чисел), каждая из которых
выполняется отдельной функцией.
Program ProcType;
Type
Func=Function(x, y : integer) : integer;{Описание процедурного типа}
{$F+};{Директива компилятору на использование дальнего типа вызова п/программ}
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Add(x, y :integer) : integer;
Begin
Add := x+y;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Mult(x, y :integer) : integer;
Begin
Mult := x+y;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Funny(x, y :integer) : integer;
Begin
Funny := (x+y)*(x-y);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
{$F-};
Procedure Tab(w,h : integer; Operation : Func);
Var
x, y : integer;
Begin
for y := 1 to w do
begin
for x := 1 to w do
write(Operation(x,y):5);
writeln;
end;
End;
64
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
Tab(10,10,Add);
Tab(10,10,Mult);
Tab(10,10,Funny);
End.
В данной программе процедура Tab представляет собой общее действие, выполняемое над параметрами-функциями
Add, Mult, Funny. После запуска программы сначала вызывается процедура Tab для фактических параметров 10, 10 и Add, в
результате чего формальным параметрам х и y присваиваются значения чисел 10 и 10, а формальному параметру Operation
процедурного типа Func присваивается имя фактической функции Add. В результате этого на экран будет выведена таблица
сложения от 1 до 10. Затем процедура Tab вызывается к исполнению для фактических параметров 10, 10 и параметрафункции Mult, в результате этого на экран будет выведена таблица умножения от 1 до 10. Аналогично вызов процедуры Tab
с параметрами 10, 10 и Funny даст в результате на экране таблицу произведения суммы на разность чисел от1 до 10.
Задание. Введите текст этой программы, запишите полученный файл на диск и откомпилируйте его. после того как
компиляция выполнится успешно, исполните программу в пошаговом режиме с заходом в процедуры и пронаблюдайте за
вызовом функций вычисления суммы, произведения двух чисел или произведения их суммы и разности. Обратите внимание
на исполнение оператора write(Operation(x,y):5), как в зависимости от фактического значения параметра-функции Operation
процедурного типа Func осуществляется вызов различных функций Add, Mult или Funny. Попробуйте удалить строку с
директивой компилятору об использовании дальнего типа вызова или возьмите в фигурные скобки описание процедурного
типа Func и пронаблюдайте за результатом. В случае появления ошибок нажатием клавиши F1 получите справку о причинах
ошибки и рекомендацию на коррекцию.
Модули, созданные программистом.
Программы, написанные Вами и оформленные в виде готовых к употреблению процедур и функций, можно применять в
других программах. Основная концепция такого подхода заключается в объединении своих процедур и функций в
собственные библиотеки, которые могут подключаться к разрабатываемым программным продуктам.
Таким образом мы подошли к понятию модуля Unit. До сих пор Вы имели дело с встроенными модулями. Теперь Вы
научитесь подключать к программе библиотеки, которые были созданы Вами.
Использование модулей считается прогрессивным подходом в программировании, т.к. модуль компилируется
независимо от программы, а поэтому время компиляции для больших программ может существенно сократиться, что очень
важно при отладке программ.
Модуль (Unit) – программная единица, текст которой компилируется независимо. Модуль включает в себя определения
констант, типов данных, переменных, процедур и функций, доступных для использования в вызывающих программах.
Однако внутренняя структура модуля скрыта от пользователя.
Модуль модно разделить на несколько разделов: заголовок, интерфейсная часть, реализационная часть,
инициализационная часть.
Заголовок модуля
Unit<Имя модуля>;
{$N+}
<Глобальные директивы компилятора>;
Интерфейсная часть
Interface
Uses<список подключаемых модулей>;
Const<описания констант, определенных в данном модуле и доступных для других модулей>;
Type<описания типов, определенных в данном модуле и доступных для других модулей>;
Var<описания переменных, определенных в данном модуле и доступных для других модулей>;
Procedure<Заголовки процедур, определенных в данном модуле и доступных для других модулей>;
Function<Заголовки функций, определенных в данном модуле и доступных для других модулей>;
Реализационная часть
Implementatoin
Uses<список подключаемых модулей>;
Const<описания констант, определенных в данном модуле и недоступных для других модулей>;
Type<описания типов, определенных в данном модуле и недоступных для других модулей>;
Var<описания переменных, определенных в данном модуле и недоступных для других модулей>;
Procedure<реализация процедур, определенных в данном модуле и доступных для других модулей>;
Function<реализация функций, определенных в данном модуле и доступных для других модулей>;
Procedure<реализация процедур, определенных в данном модуле и недоступных для других модулей>;
65
Function<реализация функций, определенных в данном модуле и недоступных для других модулей>;
Инициализационная часть
Begin<Слово Begin необходимо, если имеются операторы в следующей части программы>
<часть модуля, исполняемая при его подключении (необязательна)>
End.
Заголовок модуля
Заголовок модуля мало чем отличается от заголовка программы. В модуле вместо зарезервированного слова Program
используется слово Unit. Здесь же могут присутствовать директивы компилятору, дающие общие установки для всего
модуля.
При выборе имени модуля необходимо учитывать одну особенность: имя модуля должно совпадать с именем файла, в
котором он хранится, а значит имя модуля не может состоять более чем из 8 символов. А также не забывайте, что имя не
должно совпадать с именами объектов (процедур, функций и др.).
Интерфейсная часть
В этой части описываются все константы, типы данных и переменных, процедуры и функции, доступные в этом модуле
для использования внешними программами.
Интерфейсная часть модуля несет всю информацию, необходимую для использования процедур и функций,
определенных в модуле.
Указав в операторе Uses имена уже существующих готовых модулей, можно сделать их доступными для использования.
Аналогично здесь описываются доступные из вне и необходимые для описанных процедур и функций определения типов
данных, констант и переменных.
Все процедуры и функции, доступные для общего пользования и определенные в данном модуле, должны быть описаны
в интерфейсной части своей строкой-заголовком с указанием типов параметров. Сам текст программы этих процедур и
функций находится (с дубликатом их заголовка) в реализационной части.
Примечание. Интерфейсная часть может быть пуста.
Реализационная часть
Реализационная часть – это часть, в которой определяются процедуры и функции. Точно так же, как и внутри обычной
программы, Вы можете определить здесь глобальные (для модуля) переменные, типы данных и константы наряду с
определением процедур и функций. Определенные здесь типы данных и структуры данных недоступны извне и могут
использоваться для своих нужд только программами, входящими в реализационную часть.
Реализационная часть также может быть пустой.
Инициализационная часть
Инициализационная часть представляет собой основной блок модуля. Приведенные в ней операторы выполняются
первыми, т.е. они выполняются перед операторами основного блока главной программы, в которую включен данный модуль.
Примечание. Создание собственного модуля не является обязательным для учащегося.
РЕКУРСИЯ
Занятие 1. Понятие рекурсии.
Рекурсия (от латинского recursio - возвращение) – это такой способ организации вычислительного процесса, при
котором процедура или функция в ходе выполнения составляющих ее операторов обращается сама к себе.
Для того, чтобы такое обращение не было бесконечным, в тексте подпрограммы должно быть условие, по достижению
которого дальнейшего обращения не происходит. таким образом, рекурсивное обращение может включаться только в одну
из ветвей подпрограммы.
В языке Паскаль нет никаких ограничений на рекурсивные вызовы подпрограмм, необходимо только понимать, что
каждый очередной рекурсивный вызов приводит к образованию новой копии локальных объектов подпрограммы и все эти
копии, соответствующие цепочке активизированных и не завершенных рекурсивных вызовов, существуют независимо друг
от друга
Рекурсия достаточно широко применяется в программировании, что основано на рекурсивной природе многих
математических алгоритмов. А также Вы должны знать, что любой рекурсивный алгоритм можно преобразовать в
эквивалентный итеративный (то есть использующий циклические конструкции).
В больших и сложных программах иногда приходится заменять рекурсию на итерацию. Дело в том, что рекурсия
связана с многократными вызовами процедур, а это несколько менее эффективно при выполнении по сравнению с
использованием циклов. Однако рекурсивные версии программ, как правило, гораздо короче и нагляднее.
Хорошей иллюстрацией механизма рекурсии является функция для вычисления факториала натурального числа.
Вспомним, что факториалом числа называется произведение всех натуральных чисел от 1 до этого числа включительно:
N! = 1*2*3* . . . *(N-2)*(N-1)*N
1! = 1
0! = 1
66
Сначала покажем обычную не рекурсивную функцию для вычисления факториала, которая реализует итеративный
алгоритм вычисления:
Function NonRecFact(N:integer) : LongInt;
Var
i : integer; {переменная цикла }
Res : LongInt;
{результат}
Begin
Res := 1;
for i := 1 to N do
res := Res*i;
NonResFact := Res;
End;
Вторая функция использует рекурсивные обращения, что делает ее гораздо компактнее, и основана на очевидном
соотношении:
N! = (N-1)!*N
Иными словами, чтобы получить значение факториала от числа N, достаточно умножить на N значение факториала от
предыдущего числа:
Function RecFact(N:integer) : LongInt;
Begin
if N <= 1
then
ResFact := 1
else
ResFact := N*ResFact(N-1);
End;
Полностью программа, вычисляющая факториал числа, будет выглядеть так:
Program Rekurs;
Var
N : integer;
F : Longint;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function RecFact(N:integer) : LongInt;
Begin
if N <= 1
then
ResFact := 1
else
ResFact := N*ResFact(N-1);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
writeln('Введите число N > ';
read(N);
F := RecFact(N);
writeln('Для числа ',N,' значение факториала равно ',F);
End.
После запуска программы на экран выводится запрос "Введите число N > ", затем с клавиатуры считывается введенное
значение и в выражении F:=RecFact(N) вызывается функция RecFact с параметром-значением N. В подпрограмме-функции
проверяется условие N<=1. Если оно выполняется, то функции ResFact присваивается значение 1 и на этом выполнение
подпрограммы завершается. Если условие N<=1 не соблюдается, то выполняется вычисление произведения N*ResFact(N-1).
Вычисление произведения носит рекурсивный характер, так как при этом осуществляется вызов функции ResFact(N-1),
значение которой вычисляется, в свою очередь, через вызов функции ResFact, параметром которой также будет функция
ResFact, и т.д., до тех пор пока значение формального параметра N не будет равно 1. Так как базовая часть описания
рекурсивной функции ResFact определяет значение ResFact для N=1, равным единице, то рекурсивные вызовы функции
ResFact больше не выполняются, а наоборот выполняется вычисление функции ResFact для чисел, возрастающих от 1 до N ,
причем функция ResFact всякий раз возвращает значение, равное произведению очередного числа на факториал от
предыдущего числа. Последнее возвращение результата вычисления функции ResFact присвоит переменной F значение
произведения всех чисел от 1 до N, т.е. факториал числа N.
Итак, при выполнении рекурсивной подпрограммы осуществляется многократный переход от некоторого текущего
уровня организации алгоритма к нижнему уровню последовательно до тех пор, пока не будет получено тривиальное решение
поставленной задачи. В нашем примере решение при N=1 тривиально, т.е. ResFact=1. Затем осуществляется возврат на
верхний уровень с последовательным вычислением значения функции ResFact.
67
Задание. Введите текст рассмотренной выше программы и запишите файл на диск под соответствующим именем, а
затем откомпилируйте его. После того, как компиляция закончится успешно, задайте для просмотра в окне отладчика
переменные N, F. Установите видимыми одновременно окна редактора с текстом программы и окно просмотра. Исполните
программу в пошаговом режиме с заходом в функцию и пронаблюдайте за изменением значения переменной N при
рекурсивных вызовах функции ResFact.
Задание. Напишите программы, демонстрирующие выполнение рекурсивного и итеративного алгоритма для задач:
1. На печать выводится сказка “О попе и его собаке” определенное число раз. ("У попа была собака, он ее любил. Она
съела кусок мяса – он ее убил. В землю закопал, надпись написал ...)
2. Напишите рекурсивный алгоритм нахождения степени числа.
ах=ах-1*а, а0=1
Занятие 2. Примеры задач рекурсивного решения в текстовом и графическом режимах.
Задача 1. Нахождение n-го члена арифметической прогрессии
(an=a1+d*(n-1)-формула n-го члена арифметической прогрессии).
Program Progressiy;
Var
a1, d, k: real;
n: integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Arif (a1, d: real; n: integer): real;
Begin
if n = 1
then
Arif := a1
else
Arif := Arif(a1, d, n - 1) + d;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
writeln('Задайте первый член прогрессии');
readln(a1);
writeln('Задайте разность арифметической прогрессии');
readln(d);
writeln('Арифметическая прогрессия ', Аrif(a1, d, n) : 4 : 2);
End.
Задание. Составьте программу
a) нахождения n-го члена геометрической прогрессии,
б) нахождения суммы членов арифметической прогрессии,
в) нахождения суммы членов геометрической прогрессии,
г) нахождения n-го члена ряда Фибоначчи.
Задача 2. Вложенность квадратов.
Program KaparovS;
Uses
Crt, Graph;
Var
x, y, x1, y1, x2, y2, x3, y3, n, d, a, b : integer
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Pic(x, y, x1, y1, x2, y2, x3, y3, n, d : integer);
Var
k, j : integer;
Begin
if n >=1
then
begin
Line(x, y, x1, y1);
Line(x1, y1, x2, y2);
Line(x2, y2, x3, y3);
Line(x3, y3, x, y);
j := x;
68
k := y;
x := (x1-x) div 2 + x;
y := (y1-y) div 2 + y;
x1 := (x2-x1) div 2 + x1;
y1 := (y2-y1) div 2 + y1;
x2 := (x3-x2) div 2 + x2;
y2 := (y3-y2) div 2 + y2;
x3 := (j-x3) div 2 + x3;
y3 := (k-y3) div 2 + y3;
Pic(x, y, x1, y1, x2, y2, x3, y3, n-1, d);
end;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
ClrScr;
write ('Введите количество повторений: ');
readln (n);
x := 0;
y := 0;
x1:= 400;
y1 := 0;
x2:= 400;
y2 := 400;
x3:= 0;
y3 := 400;
a : Detect;
InitGraph(a, b, 'D:\TP7\BGI');
ClearDevice;
Setcolor(Green);
Pic(x, y, x1, y1, x2, y2, x3, y3, n, d);
readln;
CloseGraph;
End.
Задание. Наберите программу и просмотрите ее действие. Дополните программу комментарием. По желанию улучшите
алгоритм.
Творческое задание. Придумайте и решите задачу на демонстрацию рекурсии в графическом режиме.
Занятие 3. Косвенная рекурсия.
Рассмотренные выше программы использовали так называемую прямую рекурсию, когда в теле некоторой процедуры
содержался непосредственный вызов самой себя. В языке Паскаль допускается также и косвенная рекурсия, когда, например,
процедура, процедура А вызывает процедуру В, а та, в свою очередь,– процедуру А. Длина таких цепочек вызовов может
быть произвольной, однако при разработке программы необходимо тщательно следить за тем, чтобы рекурсивный алгоритм
был сходимым, то есть не приводил к бесконечным взаимным вызовам подпрограмм.
Образно косвенную рекурсию можно описать так. Перед зеркалом 1 стоит зеркало 2, в котором отражается само зеркало
1. В последнем видно зеркало 2 и т.д.
Приведем пример программы, иллюстрирующей косвенные рекурсивные вызовы процедур. В этой программе
процедуры Rec1 и Rec2 рекурсивно вызывают друг друга, поочередно уменьшая свои фактические параметры. Легко видеть,
что обе процедуры работают с одной глобальной переменной А, которая передается в них по ссылке. Критерием завершения
работы является обращение этой переменной в ноль.
Обратите внимание, что в программе необходимо предварительное определение второй процедуры Rec2, так как ее
вызов встречается в процедуре Rec1, т.е. перед ее полным описанием.
Program KosvRecurs;
Var
A : integer;
Procedure Rec2 (Var Y:integer); Forward;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Rec1 (Var X:integer);
Begin
69
X := X-1;
if X>0
then
Rec2;
writeln (X)
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Rec2 (Var Y:integer);
Begin
Y := Y div 2;
if Y>2
then
Rec1;
writeln (Y)
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
A := 15;
Rec1(A);
End.
Творческое задание. Придумайте и решите задачу на демонстрацию косвенной рекурсии в графическом режиме.
Занятие 4. Решение задач
1. Определите члены последовательность Фибоначчи.
2. Найдите максимальный элемент в одномерном массиве.
3. Составьте алгоритм вычисления суммы
Указание. Обозначьте
a i  a i 1
si  s i 1
ai 
1
x1 x2
x3
xn


 ... 
1! 2! 3!
n! .
xi
i! и используйте соотношения
x
, a0 1
i
 a i, s 0  1
x1 x3
x5 x 7
xn



 ...  (1) n
7!
n!
4. Вычислите 1! 3! 5!
5. Определите n–й член последовательности, в которой каждый следующий член равен сумме обратных величин всех
предыдущих.
6. Определите n–й член последовательности, в которой каждый следующий член равен сумме квадратов всех
предыдущих.
7. При положительном а решением уравнения х=х/2+а/(2х) служит х=
x
a
xi  i 1 
, x 1
2 2xi 1 1  можно использовать для быстрого вычисления
8. Составьте алгоритм для вычисления
xi 
3
a . Рекуррентное соотношение
a . Определите корень квадратный числа а.
a , используя соотношение
2x i 1
a
 2 , x1  1
3
3x i 1
9. Составьте алгоритм, вычисляющий n–й член последовательности, заданной соотношениями:
70
a) a i  a i 1  a i 2  a i 3 , a 1  a2  a 3  1
· ) a i  i * ai  1  a i 2 ,
a 1  a2  1
10. Составить рекурсивную программу ввода с клавиатуры последовательности чисел (окончание ввода - 0) и вывода ее
на экран в обратном порядке.
Для сдачи зачета приготовьте файлы и листинги с решенными задачами, а также будьте готовы ответить на
теоретические вопросы, рассмотренные в этой теме.
Для любознательных. Ханойские башни. Задача о разрезании прямоугольника
Ханойские башни – это древняя игра. Заключается она в следующем. Имеются три стержня, на одном из них (например,
на правом) насажены диски разных размеров, причем диски располагаются так, чтобы стержень с дисками напоминал
башню, т.е. внизу располагаются самые большие диски, а вверху – маленькие. Цель игры – перенести башню с правого
стержня на левый, причем за один раз можно переносить только один диск и при этом можно насаживать только диск с
меньшим диаметром на диск с большим диаметром. Средний стержень является вспомогательным для временного хранения
дисков.
В программе применяются вложенность подпрограмм и рекурсивный вызов подпрограмм.
Пронумеруем стержни слева направо и договоримся переносить диски с правого (3) стержня на левый(1).
Program Tower;
Type
Position = (Left, Centre, Right);
Var
N : integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure MoveDisk (From, Tol : Position);
Procedure writePos (P : Position);
Begin
case P of
Left : write ('1');
Centre : write ('2');
Right : write ('3');
end;
End;
Begin
writePos (From);
write('->');
writePos (Tol);
writeln
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure MoveTower(Hight : integer; From, Tol, Work : Position);
Begin
if Hight>0
then
begin
MoveTower(Hight-1, From, Work, Tol);
MoveDisk (From, Tol);
MoveTower(Hight-1, Work, Tol, From);
end;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
writeln('Введите количество колец ');
readln(N);
MoveTower(N, Right, Left, Centre);
End.
Задание. Изучите текст программы. Введите текст программы, запишите файл на диск и откомпилируйте его. после
того, как компиляция выполнится успешно, задайте для просмотра в окне отладчика переменные Hight, From, Tol, Work.
Установите видимыми одновременно окно редактора с текстом программы и окно просмотра. Исполните программу в
пошаговом режиме с заходом в процедуры и пронаблюдайте за рекурсивным вызовом процедуры MoveTower. Дополните
программу операторами графического режима, чтобы наглядно можно было представить перенос дисков со стержня на
стержень. Дополните текст программы комментариями.
Рассмотрим задачу о разрезании прямоугольника.
71
Задача. Дан прямоугольник со сторонами А и В, где А, В – натуральные числа. Начинаем отсекать от него квадраты.
Сколько таких квадратов можно отсечь, если каждый раз отсекается самый большой квадрат?
3
1
2
4
5
Для решения этой задачи нам нужны будут функции Max и Min для переопределения длины и ширины
прямоугольника. А также введем вспомогательные переменные Х и У (У>=Х), соответствующие уменьшающимся сторонам
прямоугольника, и вспомогательную переменную D, которая определяет уменьшение размеров прямоугольника после
очередного отсечения наибольшего квадрата, сторона которого находится как Х:=Min(D, X) и продолжаем цикл.
В программе нам нужно организовать цикл, в котором сторона У уменьшается каждый раз на Min(D, X) до тех пор,
пока не останется последний квадрат или У не станет меньше Х. В последнем случае переименовываем стороны оставшегося
прямоугольника как Y := Max(D, X) и X := Min(D, Х) и продолжаем цикл.
Program OtsehKvadr;
Var
A, B, D, K, X, Y : integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Min(I,J : integer) : integer;
Begin
If I<J
Then
Min := I
Else
Min := J;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Max(I,J : integer) : integer;
Begin
if I>J
then
Max := I
else
Max := J;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
repeat
writeln ('Введите два натуральных числа ');
readln(A,B);
until (A>0) and (B>0);
K := 1;
X := Min(A, B);
Y := Max(A, B);
while X<>Y do
begin
K := K+1;
D := Y-X;
Y := Max(D, X);
X := Min(D, X);
end;
writeln('Искомое число квадратов : ',K);
End.
Задание. Наберите текст программы. Проверьте ее работоспособность. Дополните программу комментариями. Если у
Вас возникло желание, то усовершенствуйте эту программу своими дополнениями. Результат покажите учителю для оценки.
Анализ рекурсивных алгоритмов
При изучении темы "Рекурсия" полезно проанализировать рекурсивные алгоритмы с точки зрения последовательности
их выполнения. Под последовательностью выполненного рекурсивного алгоритма будем понимать последовательность
вызовов алгоритма с различными значениями аргументов и очередью определения результатов.
Рассмотрим сначала функцию расчетов факториала числа (см. выше)
72
Для алгоритма определения 5-го члена ряда Фибоначчи схема нахождения изображена на рисунке:
fib(5)
B1
B2
B3
fib(4)
fib(3)
fib(2)
B4
fib(1)
B5
fib(2)
B6
B7
fib(3)
B8
fib(2)
fib(1)
Чтобы определить значение 5-го элемента Фибоначчи, для этого необходимо определить значения fib(2), fib (1), fib (3),
fib (2). Из схемы видно также , что в рассматриваемом случае значения fib (1), fib (3), fib (2) определяются дважды. При
нахождении члена последовательности с большим номером число повторных вычислений значительно увеличивается. В
результате при определения значения fib (17) компьютер выполнит свыше 1000, значения fib (31) свыше 1000000, значения
fib (45) свыше 1000000000 операций сложения. В тоже время при использовании не рекурсивного алгоритма для вычисления
45-го члена потребуется всего 43 операции сложения.
Это позволяет сделать вывод о неэффективности использования рекурсии для решения рассматриваемой задачи.
Аналогичный вывод можно сделать для решения других задач.
Особенности отладки и компиляции программ, содержащих процедуры и функции
При пошаговой отладке программ, содержащих процедуры и функции, при нажатии клавиши F7 в строке, которая
содержит вызов подпрограммы, мы переходим в начало (на слово begin) данной подпрограммы. При завершении работы
подпрограммы – если подсвечена конечная строка end или exit. При следующем нажатии F7 мы возвращаемся в ту строку
основной программы, с которой попали в подпрограмму. Постоянный заход в подпрограммы часто бывает не нужен. Для
пошагового исполнения основной программы без захода в подпрограммы используйте клавишу F8.
В меню Debug предусмотрено специальное окно для просмотра последовательности вызываемых функций и процедур.
Это окно открывается клавишами Ctrl+F4 или через пункт меню Debug/Call stack. В этом окне прослеживается текущее, то
есть изменяющееся при пошаговой отладке, состояние стека вызова подпрограмм. В верхней строке – исполняемая в данный
момент подпрограмма, в нижней – основная программа, в промежутке между ними – последовательность вызовов
подпрограмм от основной программы до текущей программы.
При выходе из подпрограммы стек программы освобождается от ее вызова, и верхняя строка в окне стека убирается. Это
окно следует применять при сложной иерархии взаимных вызовов подпрограмм, когда не очевидно, каким путем
выполнение алгоритма привело к данной подпрограмме.
При разработке программных проектов, содержащих несколько модулей, удобно использовать многооконный
интерфейс среды, позволяющий одновременно работать со всеми файлами данного проекта.
Пункты этого меню позволяют выбрать расположение окон на экране, переключаться между окнами, закрывать окна.
Пункт Tile разделяет экран на отдельные кусочки, в каждом из которых находится свое окно. Такой способ разбиения имеет
смысл применить, если открыто 2-4 окна. Пункт Cascade накладывает окна одно на другое таким образом, что край нижних
окон виден из-под верхних. При таком раскладе окон каждое из них имеет достаточно большой размер и легко может быть
активизировано.
Cascade
Tile
73
Переключение между окнами производится нажатием клавиш, указанными в меню. Для изменения размера и
положения окна нужно нажатием клавиш Ctrl+F5 вызвать пункт Size/Move. Размеры окна изменяются клавишами
перемещения курсора. Когда требуемый размер установлен, нужно нажать Enter для фиксации положения окна. Если Вы
забудете нажать Enter, все действия будут блокированы. Для перемещения окна при нажатии клавиш управления курсором
надо держать нажатой клавишу Shift.
При компиляции проектов, использующих модули, можно использовать различные режимы компиляции.
По нажатию клавиш Alt+F9 компилируется программа или модуль, находившиеся в активном окне. Используемые этой
программой модули должны быть предварительно откомпилированы.
Компиляцию проектов, состоящих из нескольких модулей, удобно производить, установив основной файл – это, как
правило, файл с основной программой. Для этого выбирается пункт Primary file и вводится имя файла. Уничтожение этой
записи производится путем выбора пункта Clear primary file. Если начальный файл установлен, компиляция или компиляция
с исполнением происходит всегда так, как будто активным окном являлось окно основной программы. Это позволяет
вносить изменения в отдельных модулях и сразу запускать компиляцию и исполнение всего проекта, не переключаясь
специально к основной программе.
Для подключения к основной программе модулей компилятор ищет их прежде всего в рабочем каталоге, а затем в
каталогах, указанных в строке Units окна настройки, которое появляется при выборе пункта меню Options/Directories.
При нажатии клавиши F9 (Make) прежде всего происходит компиляция начального файла, заданного в строке Primary
file. Если эта строка пуста, компиляция начинается с активного окна. когда в процессе компиляции программы или модуля
встречаются ссылки на другие модули, проверяется необходимость перекомпиляции подключаемых модулей. Проверка
заключается в сверке изменений файла с текстом модуля на Паскале и откомпилированного модуля (по времени внесения
последних изменений в файл). Если в текст были внесены изменения, данный модуль компилируется вновь. Если файл
модуля с текстом не найден , берется откомпилированный файл без проверки. Эта опция компилятора оптимальна по
затратам времени на компиляцию, так как компилируется только то, что нужно. Компиляция и запуск на исполнение,
вызываемые клавишами Ctrl+F9, производит компиляцию по данной логике.
В ряде случаев нам необходима обязательная перекомпиляция всех файлов (Build). В частности, это необходимо, если
мы изменили опции компиляции в меню Options/Compiler. Изменение опций компиляции через окно не прослеживается
далее автоматически, то есть среда не определяет, откомпилирован файл с новыми или старыми опциями, и не производит
автоматически перекомпиляцию. Для полной компиляции всех файлов вызывается пункт Build.
Пункт Target устанавливает, для какой платформы – реального режима, защищенного режима или Windows – должны
компилироваться файлы.
74
ОДНОМЕРНЫЕ МАССИВЫ
Занятие 1. Понятие массива. Одномерные массивы. Способы задания одномерных массивов
На прошлом занятии мы завершили изучение простых типов Turbo Pascal и сегодня приступаем к изучению
структурированных. Их в Turbo Pascal три:
1. Массивы
2. Записи
3. Множества
Мы начнем знакомство с ними с массивов.
В математике, экономике, информатике часто используются различные наборы данных: последовательности чисел,
списки фамилий, таблицы. Для обработки наборов однотипных данных мы введем понятие массива. Под массивом мы будем
понимать структуру, отличительной особенностью которой является то, что все ее компоненты есть данные одного типа, и
после упорядочения к любому из них можно получить доступ, указав его номер. Массивы нужны и тогда, когда для решения
задачи необходимо хранение последовательности значений.
Определение. Массив – это совокупность объектов, состоящая из фиксированного упорядоченного числа элементов,
имеющих один и тот же тип.
Массивы могут быть одномерными и многомерными (двух-, трехмерными и т. д.). Примером одномерных массивов
может быть список фамилий учеников класса, многомерных - таблица умножения, классный журнал, аттестат зрелости.
Элементы, образующие массив, упорядочены таким образом, что каждому элементу соответствует номер (индекс),
определяющий его местоположение в общей последовательности. Доступ к каждому элементу осуществляется путём
индексирования.
Для описания массива используется словосочетание array of (массив из) и имеет вид:
array [тип индекса] of <тип>
Тип индекса – любой порядковый номер, определяющий границы изменения значений индекса.
Описание массива задается следующим образом:
<имя типа> = array [тип индекса] of <тип данных>;
Например,
Program Name;
Const
m=50;
Type
mas=array [1..m] of integer;
{массив из m целых чисел}
digit = array [0 .. 9] of char;
{массив десяти символов, имеющих порядковые номера от 0 до 9}
matrix = array [byte] of string;
{массив 256 строк, пронумерованных с 0 до 255}
Var
massiv: mas;
m: matrix;
d: digit;
a: array [1..n] of real;
{явное описание переменной типа массив}
В качестве индексных типов можно использовать любые порядковые типы, кроме Longint и типов-диапазонов с базовым
типом Longint.
Если несколько массивов имеют одинаковый тип индексов и одинаковый базовый тип, то можно при описании
объединить массивы в один список. Например
Var
a, b, c: mas;
Такой записью мы объявили три массива вещественных чисел a, b, c, каждый из которых содержит по 50 элементов:
A[1], А[2], ... A[50],_
В[1], В[2], ... В[50],
С[1], С[2], ... С[50].
Представим себе массив в виде набора ячеек памяти, размер которых зависит от значений, содержащихся в массиве.
Общий размер памяти, отводимой компьютером для хранения переменной такого типа данных можно определить
следующим образом:
75
Общий объем = количество ячеек памяти * объем одной ячейки
Например, если возьмем переменную
Var
M : digit;
то объем памяти, выделенный под хранение переменной m будет равен 10 байтам и выглядеть это будет приблизительно
так:
Индекс
элемента
m
0
1
2
3
4
5
6
7
8
9
2
*
4
=
в
о
с
е
м
ь
m[4] – элемент массива m, находящийся в ячейке с индексом 4 и равный символу ‘в’
Примечание. Не путайте понятия "индекс" и "тип индекса". Тип индекса используется только в разделе описания
массива, а индекс указывается в разделе операторов для обозначения конкретных элементов массива. В качестве индекса
может быть выражение, частным случаем которого является константа или переменная.
Над элементами массива можно производить те же операции, которые допустимы для данных его базового типа.
Способы задания одномерных массивов
Для ввода и вывода числовых значений массива используются циклы.
Рассмотрим процедуры, которые бы формировали одномерный массив двумя способами
1) случайным образом,
2) вводом элементов с клавиатуры
Предположим, что мы будем работать с массивом целых чисел. Пусть нам достаточно иметь максимальное
количество элементов равное 50. Процедура принимает параметр по ссылке массив Massiv заданного типа и целую
переменную n, отвечающую за количество заполняемых ячеек массива. Также нам нужна будет локальная переменная i,
которая будет выполнять функции параметра цикла и использоваться для указания номера, определяющего местоположение
элемента в массиве.
1. Формирование одномерного массива случайным образом. Зададим значение каждого элемента результатом случайной
функции Random(10). Заполнение массива зададим циклическим оператором for, в теле которого выполняется вычисление
случайного числа функцией Random(10), после чего это значение присваивается очередному i-му элементу массива.
Procedure InsertMas1(Var massiv:mas; n:integer);
Var
i: integer;
Begin
Randomize;
for i:=1 to n do
massiv[i] := Random(10);
End;
2. Формирование одномерного массива вводом элементов с клавиатуры.
Procedure InsertMas2(Var massiv:mas; n:integer);
Var
i: integer;
Begin
for i:=1 to n do
begin
write('Введите ',i,'-ый элемент массива ');
readln(massiv[i]);
end;
End;
Вывод массива на экран осуществляется следующим образом:
Procedure PrintMas(massiv:mas; n:integer);
Var
i: integer;
Begin
for i:=1 to n
Write(Massiv[i]:5);
End;
76
Задание. Составьте программу-шаблон, в которой содержались бы два возможных варианта ввода элементов массива,
оформленных в виде процедур, и одна процедура вывода полученного массива на экран. Результат работы покажите учителю
для оценки.
Теперь проверьте себя, попробовав ответить на вопросы:
1. Что понимается под массивом?
2. Как обозначить в программе элементы массива?
3. Какие операции разрешены над элементами массива?
4. Как организовать в программе ввод и вывод элементов массива?
5. Приведите примеры, где можно использовать массивы.
6. Какие из приведенных описаний одномерных массивов являются правильными и почему?
a) Var a: Array[1..20] of Integer;
b) Type Myarrray: Array[1..20]
Var b: Myarrray;
c) Var sd:Array[1..n] of Integer;
d) Var dd:Array[1] of integer;
7. Сколько элементов в каждом из следующих массивов
a) Var mb: Array[2..20] of Integer;
b) Type myarray1[2..20] of Integer;
myarray2[-5..5] of Integer;
Var aa: myarray1;
bb: myarray2;
Дополнительное задание. (на усмотрение учителя)
1. Организуйте ввод в массив и выдайте на экран следующие последовательности:
а) 1, 3, 5, 7, ..., 131
б) список учеников вашего класса
2. Организуйте ввод чисел в массив с клавиатуры, а вывод элементов массива в столбик. Ввод и вывод организуйте в
процедурах.
3. Дан произвольный массив N элементов. Организуйте вывод элементов массива на экран начиная с последнего
элемента.
Занятие 2. Доступ к элементам массива
Рассмотрите предложенные ниже фрагменты программ для решения некоторых типичных задач.
Изменение значения некоторых элементов
Задача. Заменить отрицательные элементы на противоположные по знаку.
Для этого опишем процедуру. Ей будем передавать один параметр – массив, который будет результатом ее выполнения,
так как некоторые элементы могут быть заменены.
Procedure Zamena (Var m : MyArray; n:integer);
Var
i : integer;
Begin
for i := 1 to n do
if m[i] < 0
then
m[i] := -1*m[i];
End;
Нахождение номеров элементов с заданным свойством
Задача. Найти и вывести на экран номера четных элементов.
Для решения задачи необходимо просмотреть весь массив, и если просматриваемый элемент является четным, то
выводить его номер. Опишем процедуру, которой передается данный массив и выводятся нужные номера.
Procedure PoiskChet(m : MyArray; n:integer);
77
Var
i : integer;
Begin
for i := 1 to n do
if m[i] mod 2 =0
then
Write(i:5);
End;
Нахождение количества элементов с заданным свойством
Задача. Найти количество положительных и отрицательных элементов в данном массиве.
Опишем процедуру, которой будем отправлять три параметра – массив и два счетчика, один для элементов, больших
нуля, а второй – для отрицательных элементов.
Procedure OtrPol(m : MyArray; ; n:integer; Var k1,k2 : Integer);
Var
i : integer;
Begin
k1 :=0;
k2 :=0;
for i := 1 to n do
if m[i] > 0
then
Inc(k1)
else
if m[i] < 0
then
Inc(k2);
End;
Есть ли в данном массиве элементы с данным свойством?
Для решения таких задач удобнее использовать циклы с условиями и составлять функции, результат которых имеет
логический тип.
Задача. Есть ли отрицательный элемент в массиве?
Начинаем с первого элемента (i=1). пока не просмотрен последний элемент (i<=n) и не найден отрицательный
(m[i]>=0), будем переходить к следующему (Inc(i)). Таким образом, мы закончим просмотр массива в одном из двух случаев:
первый – просмотрели все элементы и не нашли отрицательный, тогда i>n, второй – нашли нужный, при этом i<=n. Опишем
функцию, значение которой истина (True), если такой элемент есть, и ложь (False), если его нет.
Function Control (m : MyArray; n:integer) : Boolean;
Var
i : integer;
Begin
i := 1;
while (i<=n) and (m[i]>0) do
Inc(i);
Control := (i<=n);
End;
Задание. Выберите с учителем задачи для самостоятельного решения.
1. Дан одномерный массив. Найдите разность наибольшего и наименьшего чисел в этом массиве.
2. Даны два одномерных массива А и В. Подсчитайте количество тех i, для которых:
а) А[i] < B[i]
б) A[i] = B[i];
в) A[i] > B[i]
3. Составьте программу определения количества элементов массива, больших среднего арифметического всех его
элементов.
4. Дан одномерный массив. Подсчитайте, сколько раз встречается в этой таблице максимальное по величине число.
78
5. Дан одномерный целочисленный массив. Составьте программу определения значения наибольшего элемента этого
массива.
6. Дан одномерный целочисленный массив. Составьте программу определения индекса(-ов) минимального элемента
массива.
7. Составьте программу, проверяющую упорядочены ли элементы одномерного массива по возрастанию.
8. Дан одномерный массив чисел. Определите сумму его элементов.
9. Дан одномерный массив чисел. Измените знаки всех его элементов на противоположные.
10. Дан одномерный массив чисел. Подсчитайте, сколько раз в нем встречается число 1.
11. Дан одномерный массив чисел. Подсчитать в нем количество элементов равных нулю, отрицательных элементов и
положительных элементов.
12. В массиве А (m,n) найдите количество всех чисел, по модулю меньших заданного Т.
Занятие 3. Удаление элементов из одномерного массива.
Задача. Удалить из массива максимальный элемент, если все элементы разные.
Для того, чтобы решить задачу нужно:

найти номер максимального элемента k;

сдвинуть все элементы, начиная с k-го, на один элемент влево;

последнему элементу присвоить значение 0;

уменьшить количество элементов массива на единицу.
Рассмотрим задачу на конкретном примере. Пусть дан одномерный массив из целых чисел, состоящий из 10 элементов:
6, 3, 4, 7, 11, 2, 13, 8, 1, 5.
Номер максимального элемента равен 7 (k=7), то есть, начиная с 7-го элемента, будем сдвигать элементы на один влево:
7-му присвоим значение 8-го, 8-му присвоим значение 9-го, 9-му присвоим значение 10-го, на этом сдвиг заканчивается.
Таким образом, сдвиг начинается с k-го элемента и идет по (n-1)-й (где n – количество элементов в массиве). После этого
последнему элементу присвоим значение, равное 0, и тогда массив будет следующим:
6, 3, 4, 7, 11, 2, 8, 1, 5, 0.
Примечание. При удалении элемента размерность массива не изменяется.
Составим программу, удаляющую максимальный элемент из одномерного массива. В программе опустим уже знакомые
Вам процедуры заполнения массива и вывода элементов массива на экран. Чтобы последний элемент не выводился,
модифицируйте соответствующую процедуру таким образом, чтобы ей передавать не только массив, но и количество
элементов, которые надо вывести, начиная с первого.
Program DeleteK;
Const
n=30; dd=51;
Type
MyArray = Array [1..n] of Integer;
Var
A : MyArray;
k : Integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas1(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas2(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure PrintMas(m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Function Maximum (m : MyArray; n:integer) : Integer;
Var
i, max, maxi : integer;
Begin
max:=-maxint;
{начальным значением переменной будет наименьшее значение данного типа}
for i := 1 to n do {просматриваем все элементы массива}
79
if m[i] > max
{если найден элемент больше, чем мы считаем максимальным}
then
begin
max:=A[i]; {то запомним найденное значение}
maxi:=i; {а также место, на котором он стоит в массиве}
end;
Maximum := maxi; {имени функции присвоим найденный результат}
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Delete(Var m : MyArray; Var n:integer; k1 : integer);
Var
i : integer;
Begin
for i := 1 to n-1 do
m[i] := m[i+1];
m[n]:=0;
Dec(n);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
. . .
k:=Maximum(A,m);
Delete(A,m,k);
. . .
End.
Задание. На основе имеющегося шаблона программы и рассмотренного алгоритма решения задачи, закончите
составление работающей программы. Результат покажите учителю для оценки.
Изменим условие задачи. Пусть максимальный элемент встречается несколько раз.
Для решения этой задачи необходимо удалять несколько элементов. Это лучше сделать с конца массива, так как, иначе,
нужно будет снова возвращаться к элементу с номером, который только что удаляли для предупреждения частного случая,
когда подряд идут два максимальных элемента (при удалении первого на его месте будет стоять второй снова максимальный
элемент. Это можно сделать при помощи цикла с параметром (downto). Кроме того, номер максимального элемента
запоминать не нужно. При прохождении массива с конца, если элемент имеет максимальное значение, то удалим его, при
этом значение счетчика k будем увеличивать на 1.
Задание. С учетом выше изложенного составьте программу, решающую поставленную задачу или дополните
предыдущую. Результат покажите учителю для оценки.
Внимание! Любая Ваша программа должна сопровождаться комментариями.
Задачи для самостоятельного решения
1. Удалить первый отрицательный элемент, если таковой имеется.
2. Удалить все отрицательные элементы.
3. Удалить все элементы, большие данного числа А (А вводить с клавиатуры).
4. Удалить все четные элементы, стоящие на нечетных местах.
5. Удалить все повторяющиеся элементы, оставив только их первые вхождения, то есть получить массив различных
элементов.
6. Удалить последний четный элемент.
7. Удалить все элементы, кратные 3 или 5.
8. Удалить все элементы, начиная с k1-го по k2-ой. Сделать проверку корректности ввода значений k1 и k2, если ввод
некорректный, то вывести сообщение об ошибке и закончить работу.
Занятие 4. Вставка элементов в одномерный массив.
Вставка одного элемента
Вставлять элемент можно до или после данного элемента, номер этого элемента можно вводить с клавиатуры или искать
при определенных условиях.
Пусть k – это номер элемента, после которого мы должны вставить элемент х. Тогда вставка осуществляется следующим
образом:

первые k элементов массива остаются без изменения,
80

все элементы, начиная с (k+1)-го, необходимо сдвинуть на один назад,

на место (k+1)-го элемента записываем значение х;

увеличить количество элементов в массиве на единицу.
Задача. Вставить число 100 после пятого элемента массива.
Рассмотрим на конкретном примере. Пусть задан следующий одномерный массив из N (N=10) элементов:
3, -12, 5, 14, 27, -6, 1, -34, 10, -15.
Надо вставить 100 после пятого элемента массива, т. е. должен получиться следующий массив:
3, -12, 5, 14, 27, 100, -6, 1, -34, 10, -15.
Таким образом, в массиве стало 11 элементов, то есть массив надо определять на N+1 элемент:
Type
MyArray = array[1..n+1] of integer
Кроме того, в программе необходимо выводить массив два раза, сначала первые N элементов массива, а затем все N+1
элементы.
Рассмотрите процедуру вставки Insert1(m, n, Mesto, Element), которой передаются:
m – массив, в котором делаем преобразования;
n – количество элементов в массиве.
Mesto – номер элемента, после которого надо вставить данный,
Element – число, которое вставляем,
Кроме того, сдвиг элементов будем начинать с последнего элемента.
Program Vstavka1;
Const
n=10; dd=51;
Type
MyArray = array [1..n+1] of integer;
Var
A : MyArray;
k, x : Integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas1(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas2(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure PrintMas(m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure Insert1(Var m : MyArray; Var n : integer; Mesto, Element : integer);
Var
i : integer;
Begin
for i := n downto Mesto+1 do
m[i+1] := m[i];
m[Mesto+1]:= Element;
Inc(n);
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
. . .
Writeln('Номер элемента, после которого вставлять > ');
Readln(k);
Writeln('Вставляемое число > ');
Readln(x);
Insert1(A, n, k, x);
. . .
End.
81
Задание. На основе разобранной задачи вставьте число перед некоторым заданным элементом самостоятельно.
Дополните программу необходимыми операторами и комментариями и добейтесь работоспособности программы.
Покажите результат работы учителю для оценки.
Вставка нескольких элементов
Задача. Вставить число после всех элементов массива, кратных трем.
Первое, на что необходимо обратить внимание – это описание массива: на сколько элементов может увеличиться
массив? Максимальное количество элементов, после которых будет вставлен новый элемент, совпадает с количеством
элементов массива, так как может случиться, что все элементы массива отвечают заданному свойству. Поэтому массив
может увеличиться в два раза, а значит, соответствующее ему описание будет следующим:
Type
MyArray[1..2*n] of Integer;
Второе. Если мы будем просматривать массив с начала и вставлять новый после элемента с заданным свойством, то
номер последнего элемента каждый раз может меняться, кроме того, будет просматриваться и новый (вставленный) элемент
и его необходимо будет пропускать, поэтому решение будет не очень эффективным. Лучше всего просматривать массив,
начиная с конца, тогда вставляемый элемент мешать не будет. Кроме того, номер последнего элемента можно будет знать
(если знать, сколько элементов вставлено на данный момент), при этом просмотр будет последовательным от N-го до 1-го.
Program VstavkaN;
Const
n=10; dd=51;
Type
MyArray = Array [1..2*n] of Integer;
Var
A : MyArray;
k, x, i : Integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas1(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertMas2(Var m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure PrintMas(m : MyArray; n : integer);
. . .
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure InsertN(Var m : MyArray; Var n : integer; Mesto, Element : Integer;);
Var
i : Integer;
Begin
for i := n downto Mesto+1 do
m[i+1] := m[i];
m[Mesto+1]:= Element;
Inc[n];
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
. . .
Writeln('Вставляемое число > ');
Readln(x);
k:=0;
for i:=n downto 1 do
if A[i] mod 3=0
then
InsertN(A, n, i, x);
. . .
End.
Задание. Дополните программу необходимыми операторами и комментариями и добейтесь работоспособности
программы. Покажите результат работы учителю для оценки.
Задачи для самостоятельного решения
1. Вставить элемент после первого отрицательного элемента.
2. Вставить элемент перед отрицательным последним элементом.
3. Вставить два элемента: первый – после максимального элемента, второй – перед максимальным элементом.
82
4. Вставить по одному элементу перед всеми элементами, кратными заданному числу.
5. Вставить по одному элементу перед всеми отрицательными элементами.
6. Вставить два элемента: первый – после всех элементов, больших данного числа Р, а второй – перед всеми элементами,
большими данного числа Р (Р вводить с клавиатуры).
7. Вставить число А перед всеми элементами, большими А, а число В – после всех элементов, меньших его.
Занятие 5. Перестановка элементов массива.
Перестановка двух элементов
Задача. Поменять местами два элемента массива с номерами k1 и k2.
Рассмотрите процедуру, с помощью которой эта задача легко решается.
Procedure Obmen2(Var m : MyArray; n, k1, k2 : integer;);
Var
x : integer;
Begin
x:=m[k1];
m[k1] := m[k2];
m[k2] := x;
End;
Перестановка части массива
Задача. Дан одномерный массив А, состоящий из 2n элементов. Поменять местами первую и вторую его половины
Задание. Оформите решение этой задачи, применив процедуру обмена значений Obmen2, рассмотренную выше.
Заметим лишь, что Вы должны поменять местами элементы с номерами 1 и n+1, 2 и n+2 и т.д., последняя пара – n и 2n, а
значит, обмен происходит по правилу: элемент с номером i меняется местами с элементом с номером n+i. Эту
закономерность следует применить в организации обращения к процедуре обмена. Например, так
for i := 1 to n do
Obmen2(A, 2*n, i, i+n,);
Задание. Выберите с учителем задачи для самостоятельного решения из предложенного списка:
1. Поменять местами:
а) первый элемент и максимальный;
б) второй и минимальный;
в) первый и последний из отрицательных чисел.
2. Дан одномерный массив А, состоящий из 2n элементов. Поменять его половины следующим образом: первый элемент
поменять с последним, второй с предпоследним и так далее.
3. Дан одномерный массив В, состоящий из 2n элементов. Переставить его элементы по следующему правилу:
а) b[n+1], b[n+2], ..., b[2n],b[1], b[2], ..., b[n];
b) b[n+1], b[n+2], ..., b[2n],b[n], b[n-1], ..., b[1];
c) b[1], b[n+1],b[2], b[n+2], ..., b[n], b[2n];
d) b[2n], b[2n-1], ..., b[n+1],b[1], b[2], ..., b[n];
4. Дан одномерный массив. Переставить в обратном порядке элементы массива, расположенные между минимальным и
максимальным элементами.
Работа с несколькими массивами.
В Turbo Pascal можно одним оператором присваивания передать все элементы какого-либо массива другому массиву
того же типа, например:
Var
a, b: array [1 .. 5] of integer;
Begin
..........
a:=b;
..........
End.
После такого присваивания все пять элементов массива a получат значения из массива b.
83
Рассмотрим одну из типичных задач.
Задача. Найти скалярное произведение двух массивов.
Скалярным произведением двух массивов одинаковой размерности называется сумма произведений соответствующих
элементов. Это можно записать так:
a[1]*b[1] + a[2]*b[2] + ... + a[n-1]*b[n-1] + a[n]*b[n],
где n – это количество элементов в массивах (размерность).
Тогда можно составить следующую функцию:
Function Sp (a, b : MyArray; n ; integer) : LongInt;
Var
i : Integer;
s : LongInt;
Begin
s:= 0;
for i := 1 to n do
s := s+a[i]*b[i];
Sp := s;
End;
Задание. Выберите с учителем задачи для самостоятельного решения:
1. Дан одномерный массив чисел а. Cформируйте такой массив b, который содержит копию положительных элементов
массива а.
2. Скопируйте отрицательные и положительные кратные заданному числу элементы массива А в массив В в обратном
порядке.
3. Из двух упорядоченных одномерных массивов (длины K и N) сформируйте одномерный массив размером K+N,
упорядоченный так же, как исходные массивы.
4. Из двух упорядоченных одномерных массивов (длины K и N) сформируйте одномерный массив размером K+N,
упорядоченный в обратную сторону.
5. Дан упорядоченный целочисленный массив. Сформировать второй массив всех таких различных значений, которые в
первом массиве встречаются по два и более раза.
6. Дан упорядоченный целочисленный массив. Сформировать второй массив всех таких различных чисел, которые ни
разу в первом массиве не встречаются и имеют величину больше минимального и меньше максимального из чисел первого
массива.
7. Сформировать массив:
Y[1]=A[1]+A[n]
Y[2]= A[2]+A[n-1]
Y[3]= A[3]+A[n-2]
и т.д. (n – четное)
8. Даны два одномерных массива А и В. Подсчитайте количество тех i, для которых:
а) А[i] < B[i]
б) A[i] = B[i];
в) A[i] > B[i]
9. Даны два целочисленных массива одинаковой размерности. Получить третий массив той же размерности, каждый
элемент которого равен большему из соответствующих элементов данного массива.
10. Определить величину максимальной разности между соответствующими элементами двух массивов и записать на то
же место в третий массив той же размерности.
11. Даны два одномерных массива одинаковой длины. Получить третий массив такой же размерности, каждый элемент
которого равен сумме соответствующих элементов данных массивов, умноженной на больший из них.
Занятие 6. Самостоятельное решение задач.
Выберите с учителем задачи для самостоятельного решения:
1. В целочисленном массиве A[1:n] найдите число, повторяющееся максимальное количество раз. Если таких чисел
несколько, то одно из них.
84
2. Измените знак всех нечетных (четных) элементов массива, состоящего из L чисел (предусмотреть случай наличия
нецелых элементов).
3. "Сожмите" массив, "выбросив" каждый второй его элемент (дополнительные массивы использовать не разрешается).
4. Задан одномерный массив A(N), состоящий только из нулей и единиц. Проверьте, строго ли они чередуются.
5.Отсортировать массив по возрастанию, используя процедуру Obmen2, которая меняет местами 2 элемента.
6. Дан целочисленный массив А. Найти длину самой длинной последовательности подряд идущих элементов массива,
равных нулю.
7. Дан одномерный массив. Составьте программу подсчета количества таких i, что Z[i] не меньше всех предыдущих
элементов таблицы (Z[1], Z[2], ..., Z[i-1]).
8. В массиве X(N) каждый элемент равен 0, 1 или 2. Переставить элементы массива так, чтобы сначала располагались
все единицы, затем все двойки и, наконец, все нули (дополнительного массива не заводить).
9. В заданной последовательности все элементы, не равные нулю, расположить сохраняя их порядок следования, в
начале последовательности, а нулевые элементы - в конце последовательности.
10. Дан одномерный целочисленный массив A(N). Известно, что среди его элементов два и только два равны между
собой. Напечатать их индексы.
11. Пусть дан упорядоченный по не убыванию массив целых или действительных чисел и пусть дано некоторое число b
(соответственно целое или действительное), для которого нужно найти такое место среди чисел, чтобы после вставки числа b
на это место упорядоченность не нарушилась.
12. Из текста выбрать числа и записать в массив N. Количество чисел не больше 10.
13. Из шестизначного числа выделить цифры и из них сформировать одномерный массив.
14. Фамилии участников олимпиады хранятся в одном массиве, а количество баллов - в другом. Составьте программу,
которая будет печатать фамилию победителя, если он набрал 100 баллов.
15. “Суперзамок”. Секретный замок для сейфа состоит из 10 расположенных в ряд ячеек, в которые надо вставить
игральные кубики. Но дверь открывается только в том случае, когда в любых трёх соседних ячейках сумма точек на
передних гранях кубика равна 10. (Игральный кубик имеет на каждой грани от 1 до 6 точек.) Напишите программу, которая
разгадывает код замка при условии, что два кубика уже вставлены в ячейки.
16. При поступлении в институт абитуриенты, получившие двойку на первом экзамене, ко второму не допускаются. В
массиве А записаны оценки экзаменующихся. Подсчитать, сколько человек не допущено ко второму экзамену.
17. Мажорирующим элементом в массиве А[1..n] будем называть элемент, встречающийся в массиве более n/2 раз.
Легко заметить, что в массиве может быть не более одного мажорирующего элемента. Например, массив 3, 3, 4, 2, 4, 4, 2, 4,
4, 3 имеет мажорирующий элемент 4. Необходлимо определить, есть ли в массиве мажорирующий элемент, и если есть, то
какой.
18. Дан целочисленный массив А длиной n, в котором значениями заполнены только первые m элементов (m<n). Дан
также целочисленный массив В длиной r. Требуется вместо каждого равного 0 элемента в А среди m первых элементов
вставить всю последовательность В. Нельзя использовать дополнительный массив.
19. Задан целочисленный массив. Подсчитать число различных значений в массиве.
20. Среди N точек на плоскости (х1,у1), (х2,у2)...(хn,yn). Определить точку наиболее удаленную от начала координат.
21. Дан неупорядоченный массив целых чисел. Удалить в нем все элементы, встречающиеся более 1 раза.
22. Дан одномерный массив чисел. Определите сумму его элементов.
23. Дан одномерный массив чисел. Определите сумму элементов, больших данного числа А (А вводить с клавиатуры).
24. Дан одномерный массив чисел. Определите сумму элементов, принадлежащих промежутку от А до В (А и В водить с
клавиатуры).
25. Задан массив размером N. Вычислить среднее значение элементов массива.
26. Задан массив-список фамилий возможных пользователей ЭВМ. Организовать проверку на допуск к работе с ЭВМ
пользователя, проверяя наличие в списке его фамилии.
27. Дан одномерный массив чисел, в котором есть положительные, отрицательные и нулевые элементы. Вычислить:
а) количество элементов равных нулю, отрицательных элементов и положительных элементов;
б) среднее арифметическое положительных элементов;
в) среднее арифметическое положительных элементов, значение которых больше К;
г) сумму элементов, стоящих на нечетных местах.
85
28. Задан массив размером N. Вывести на печать каждый второй элемент массива.
29. В массиве А (m,n) найдите количество всех чисел, по модулю меньших заданного Т.
30. При поступлении в институт абитуриенты, получившие двойку на первом экзамене, ко второму не допускаются. В
массиве А записаны оценки экзаменующихся. Подсчитать, сколько человек не допущено ко второму экзамену.
31. Составьте программу определения количества элементов массива, больших среднего арифметического всех его
элементов.
32. Найти количество чётных элементов массива и напечатать эти элементы.
33. Определите сумму элементов массива, индекс которых делится на 3.
34. Рост учеников в классе представлен в виде массива. Рост девочек кодируется знаком “+”, а рост мальчиков
кодируется знаком “-”. Определите средний рост мальчиков и девочек.
35. В массиве А[20] есть хотя бы одно отрицательное значение элемента:
а) вычислить произведение элементов массива до первого отрицательного элемента;
б) вычислить сумму значений элементов массива после первого отрицательного значения.
36. Массив состоит из символов. Посчитать сколько раз в нём встречаются скобки. Учесть все виды скобок.
37. В одномерном массиве А[1..10], поменяйте местами 1-й и 6–й элементы.
38. Дан одномерный целочисленный массив. Составьте программу определения значения наибольшего элемента этого
массива.
39. Дан одномерный массив. Подсчитайте, сколько раз встречается в этой таблице максимальное по величине число.
40. Дан одномерный массив. Найти номера всех элементов с максимальным значением.
41. Составить программу, по которой в данном массиве А, состоящем из 10 элементов, находится количество простых
чисел. В программе использовать подпрограмму, по которой определяется, простое или нет данное число.
42. Дан массив, состоящий из N элементов. Найти все положительные значения элементов массива, среди
положительных выбрать наименьшее.
43. Вычесть из положительных элементов элемент с номером k1, а к отрицательным прибавить элемент с номером k2,
нулевые элементы оставить без изменения.
44. Составьте программу, проверяющую упорядочены ли элементы одномерного массива по возрастанию.
45. Дан одномерный массив А. Проверьте, являются элементы массива, последовательность чисел Фибоначчи (a n=an+a
1 n-2, a1=1, a2=1).
46. Дан одномерный целочисленный массив A(N). Известно, что среди его элементов два и только два равны между
собой. Напечатать их индексы.
47. В целочисленном массиве A[1:n] найдите число, повторяющееся максимальное количество раз. Если таких чисел
несколько, то одно из них.
48. Из шестизначного числа выделить цифры и из них сформировать одномерный массив.
49. Дан целочисленный массив А. Найти длину самой длинной последовательности подряд идущих элементов массива,
равных нулю.
50. Дан одномерный литерный массив, элементы которого имеют только значения “да” или “нет”. Подсчитайте
наибольшее число подряд идущих элементов со значением “да”.
51. Найдите самое длинное звено ломанной, координаты вершин которой сведены в две таблицы Х[1..10] и У[1..10].
Дайте графическую иллюстрацию.
52. Пусть дан упорядоченный по неубыванию массив целых или действительных чисел и пусть дано некоторое число b
(соответственно целое или действительное), для которого нужно найти такое место среди чисел, чтобы после вставки числа b
на это место упорядоченность не нарушилась.
53. Осуществить циклическую перестановку элементов массива 1 во 2, 2 в 3, 3 в 4, ..., последний в 1.
54. Удалить се повторяющиеся элементы, оставив только их первые вхождения, то есть получить массив различных
значений.
55*. Последовательность строится следующим образом: вначале записываются две единицы, затем между ними
вписывается 2, затем между каждыми соседними ее членами записывается их сумма и т.д. Сколько раз в этой
последовательности встретится число n.
56*. Энциклопедия "Вычислительная техника" содержит семь томов. Они стоят на полке в такой последовательности: 1,
5, 6, 2, 4, 3, 7. Надо расставить их в правильном порядке, действуя по правилу: переставить три рядом стоящих тома в начало,
86
конец или между двумя другими книгами, не меняя пpи этом поpядка этих тpех томов. Hапишите программу, которая
находит не менее пяти вариантов решения этой задачи и выбирает наилучший (минимальное число перестановок)
87
ДВУМЕРНЫЕ МАССИВЫ
Занятие 1. Понятие двумерного массива. Описание типа массива. Формирование значений
элементов массива случайным образом.
Одним из основных направлений использования компьютеров является накопление и обработка данных – различных
таблиц, справочников, словарей и другой информации. Для представления такой информации в программе удобно
использовать массивы. Как правило, обработка таких данных осуществляется по одному и тому же закону, для чего удобно
использовать циклические алгоритмы.
Мы уже рассматривали, как формировать и обрабатывать одномерные массивы. Вспомним, что в массив мы объединяем
конечную последовательность компонентов одного типа и даем им общее имя. Каждый отдельный компонент массива
называется элементом. Количество элементов называется размером массива. Тип элементов определяет тип массива. Размер
и тип массива указываются при его описании, причем размер может быть указан либо конкретным значением, либо ранее
определенной константой. Номер элемента называется индексом. Индексы могут быть целыми положительными
константами или целыми переменными. Чтобы обратиться к некоторому элементу массива, нужно рядом с идентификатором
массива в скобках указать индекс элемента.
Но часто данные могут быть организованы в виде таблицы (матрицы), где расположение каждой переменной
определяется номером строки и номером столбца. Например, место в зрительном зале задается указанием номера ряда и
номером места в этом ряду. Такие данные удобно описать как двумерный массив. В отличие от одномерного массива
каждому элементу двумерного массива соответствует пара индексов. Первый индекс – это номер строки, а второй – номер
столбца, где расположен элемент массива.
Размер двумерного массива задается парой чисел: M*N, где M – число строк, а N – число столбцов в таблице.
Пусть задан двумерный массив Matr, имеющий размер 10*20. Этот массив на языке Паскаль может быть описан
следующим образом:
Var
Matr : array [1..10,1..20] of integer;
тогда
Matr[5,7] – элемент, расположенный в 5-ой строке и в 7-ом столбце.
Любая константа, переменная, значение функции или выражения в Турбо Паскале характеризуется своим типом. Тип
любого из этих объектов определяет множество допустимых значений, которые может иметь объект, а также множество
допустимых операций, которые применимы к объекту. Кроме того, тип определяет и формат внутреннего представления
значения объекта.
Имя, которое программист присваивает своему определяемому типу, – произвольный идентификатор. Объявление типа
должно быть сделано в разделе объявлений, и ему должно предшествовать кодовое слово Type.
Отличительной особенностью массивов является то обстоятельство, что все их компоненты суть данные одного типа
(возможно, структурированного); эти компоненты можно легко упорядочить и обеспечить доступ к любому из них простым
указанием его порядкового номера, например:
Type
Digit = array [0..9] of integer;
Matrix = array [1..100, 0..9] of real;
Var
m : Matrix;
d : Digit;
i : integer;
Описание типа массива задается следующим образом:
<имя типа> = array [<сп. инд. типов>] of <тип>;
где:
<имя типа> – правильный идентификатор,
<сп. инд. типов> – список из одного или нескольких индексных типов, разделенных запятыми,
<тип> – любой тип Турбо Паскаля.
Примечание. Обычно в качестве индексного типа используется тип-диапазон, в котором задаются границы изменения
индексов через две точки (..). Так как <тип>, идущий за кодовым словом of, – любой тип Турбо Паскаля, он может быть, в
частности, другим массивом.
Рассмотрим примеры.
Пример 1. Массив можно описать как одномерный, элементами которого в свою очередь являются одномерные
массивы.
Const
n=20; m=30;
Type
MyArray1 = array [1..m] of integer;
MyArray2 = array [1..n] of MyArray1;
Var
V : MyArray1;
A : MyArray2;
В данном случае переменная V объявлена как одномерный массив из трех элементов целого типа, а переменная А
описана как двумерный массив из двух строк, в каждую из которых включено по три элемента.
88
Пример 2. Описание массива можно сократить, исключив определение массива MyArray1 в определении типа
MyArray2.
Const
n=20; m=30;
Type
MyArray2 = array [1..n] of array [1..m] of integer;
Var
A : MyArray2;
Пример 3. Еще более краткое описание массива А можно получить, указывая имя массива и диапазоны изменения
индексов для каждой размерности массива (чем мы уже пользовались).
Const
n=20; m=30;
Type
MyArray2 = array [1..n, 1..m] of integer;
Var
A : MyArray2;
Пример 4. Если же указанный тип используется для определения одного массива в программе, то удобно объявление
массива в разделе описания переменных.
Const
n=20; m=30;
Var
A : array [1..n, 1..m] of integer;
Формирование значений элементов массива случайным образом и с клавиатуры и вывод их на экран
Операции работы с двумерными массивами аналогичны операциям работы с одномерными массивами, нужно только не
забывать о различиях между массивами. Обычно при работе с двумерными массивами используются вложенные циклы.
Очень часто значения элементов массива вводятся с клавиатуры. Этот способ задания информации слишком трудоемок
при работе с массивами больших размеров. Для отладки широкого класса алгоритмов такой ввод информации должен быть
заменен на формирование элементов массива случайным образом. Для этого используют встроенные средства Турбо
Паскаля, процедуру Randomize и функцию Random. Вы уже сталкивались с этими средствами. Сегодня же наша задача
создать процедуры различного ввода элементов в массив и процедуру вывода элементов на экран.
Приведем пример формирования массива случайным образом. Эта процедура должна принять входными параметрами
массив, количество строк и столбцов, заданные пользователем с клавиатуры в основном разделе операторов. Так как наша
процедура будет воздействовать на пустой исходный массив, то его мы должны передать по ссылке. Количество строк и
столбцов достаточно передать копиями по значению.
Procedure InsertMas1(Var X : MyArray; n, m: integer);
Var
i, j : integer;
Begin
Randomize;
for i := 1 to n do
{пробегая последовательно строки массива}
for j := 1 to m do
{просмотрим каждую ее ячейку текущего столбца}
X[i, j]:= Random(50); {и запишем туда случайное число, которое сформирует компьютер в диапазоне [0..49]}
End;
Теперь, чтобы воспользоваться этой процедурой, достаточно вызвать ее в основном разделе программы, передав ей
параметры.
Рассмотрим процедуру вывода элементов массива на экран. Для того, чтобы наш массив при выводе выглядел удобно в
виде таблицы, поставим при переходе к новой строке пустой оператор writeln и применим формат вывода элементов на экран
(:5).
Procedure PrintMas(X : MyArray; n, m: integer);
Var
i, j : integer;
Begin
for i := 1 to n do {пробегая последовательно строки и столбцы массива}
begin
for j := 1 to m do
write(X[i, j]:5);
{выведем элемент массива на экран, выделив ему 5 знакомест}
writeln;
{переход на новую строку}
end;
End;
Задание. Наберите программу-шаблон для работы с двумерными массивами. Как вы уже знаете из предыдущей темы,
она должна содержать две процедуры ввода и процедуру вывода элементов заданного массива. Основной раздел операторов
должен содержать диалог с пользователем и защиту программы от ввода недопустимых значений для количества строк и
89
столбцов. Сохраните файл в соответствующем каталоге на своей дискете, а листинг решенной задачи покажите учителю для
оценки.
Рассмотрите процедуру, решающую следующую задачу.
Задача. Дана таблица действительных чисел. Сосчитайте сумму всех чисел в таблице.
Procedure Summa(A : MyArray; n, m: integer; Var S: real);
Var
i, j : integer;
Var
i, j , Summa : integer;
Begin
S:= 0;
for i := 1 to n do
for j := 1 to m do
S := S+A[i,j];
End.
Обратите внимание, что внутри цикла со счетчиком i организован цикл со счетчиком j. В результате суммируются в
начале числа 1-й строки (i=1, при j=1, 2, ..., m), затем суммируются числа 2-й строки (i=2, при j=1, 2, ..., m) и т.д.
В данной программе в теле одного цикла содержится другой цикл. Такие циклы, как Вы уже знаете, называются
вложенными. Причем цикл со счетчиком i является внешним, а цикл со счетчиком j – внутренним. Не забывайте основное
правило при написании вложенных циклов: последний оператор внутреннего цикла должен либо предшествовать, либо
совпадать с последним оператором внешнего цикла. Вложенные циклы напоминают матрешек, вложенных одна в другую.
Задание. Откройте файл программы-шаблона, сохраните его под другим (соответствующем задаче) именем и дополните
текст программы функцией нахождения суммы элементов, правильно преобразовав в нее рассмотренную выше процедуру.
Внесите в программу необходимые операторы и комментарии. Покажите учителю файл программы и листинг для оценки.
Задание. Ниже приведен фрагмент решения некоторой задачи. Внимательно рассмотрев решение, сформулируйте
решаемую задачу и оформите по всем правилам, применив знания текущего занятия. Файл и листинг решенной задачи
покажите учителю для оценки.
...
for i := 1 to N do
Begin
M := a[i,1];
S := a[i, 1];
for j := 2 to N do
begin
if M>a[i, j]
Then
M := a[i, j];
S := S+a[i, j];
end;
writeln (i:7, M:6, S:6:3);
End;
...
Занятие 2. Работа с элементами массива.
Для обработки двумерных массивов могут применяться методы решения задач, рассмотренные в теме "Одномерные
массивы". Поскольку положение элемента в двумерном массиве описывается двумя индексами (первый – номер строки,
второй – номер столбца), программы большинства задач строятся на основе вложенных циклов. Рассмотрите предложенные
ниже методы решения некоторых типов задач. Постарайтесь ответить на поставленные вопросы. С возникшими
затруднениями обращайтесь к учителю.
Нахождение количества элементов с данным свойством
Задачи на нахождение номеров элементов с заданными свойствами и на нахождение количества таких элементов во
всем массиве останутся практически такими же. В них только добавится второй цикл или вывод двух индексов вместо
одного.
Задача 1. Найти максимальный элемент массива и его индексы.
Так как элементы могут повторяться, то договоримся, что будем запоминать только индексы первого максимального
элемента. Опишем процедуру, которой передается массив, и ее результатом является значение максимального элемента и
индексы первой встречи такого значения.
Procedure Maximum(X : MyArray; n, m : integer; Var Max, Maxi, Maxj : integer);
Var
i, j : integer;
Begin
Max := X[1, 1];
{Предположим, что максимумом является первый элемент}
90
Maxi := 1;
{в этом случае запомним первую строку}
Maxj := 1;
{и первый столбец}
for i := 1 to n do
for j := 1 to m do
if X[i, j] > Max
{если среди элементов массива нашелся больший элемент, то}
then
begin
Max := X[i, j];{внесем новое найденное значение в переменную Мах}
Maxi := i;
{и не забудем запомнить индексы строки}
Maxj := j;
{и столбца этого элемента}
end;
End;
Задача 2. Найти количество отрицательных элементов в каждой строке.
Рассмотрим несколько способов решения этой задачи.
Способ 1 – количество элементов каждой строки хранить в одномерном массиве (Y) соответствующей размерности.
Тогда можно описать такую процедуру:
Procedure KolOtr1(X : MyArray2; n, m : integer; Var Y : MyArray1);
Var
i, j : integer;
Begin
for i := 1 to n do
begin
Y[i] := 0;
{записываем начальное значение количества элементов в соответствующую столбцу
ячейку}
for j := 1 to m do
if X[i, j] < 0 {если отрицательный элемент найден}
then
Inc(Y[i]);
{то увеличиваем текущее значение на единицу}
end;
End;
Способ 2 – использовать счетчик, находить количество элементов строки и выводить значение на экран.
Procedure KolOtr2(X : MyArray2; n, m : integer);
Var
i, j, k : integer;
Begin
for i := 1 to n do
begin
k := 0;
for j := 1 to m do
if X[i, j] < 0
then
Inc(k);
writeln(i,' – ', k);
end;
End;
Вопрос. Сравните предложенные способы решения задачи. Какой способ Вам понравился больше и почему?
Определить, отвечает ли заданный массив некоторым требованиям
Задача. Определить, есть ли в заданном массиве элемент, равный 0.
Опишем логическую функцию, значение которой равно истине, если такой элемент есть, и ложь в противном случае.
Самый простой способ – это просматривать элементы и, если найден искомый элемент, то присвоить функции значение True,
иначе – False.
Function Check1(X : MyArray; n, m : integer) : Boolean;
Var
i, j : integer;
Flag : Boolean;
Begin
Flag := False;
{Предполагаем, что искомого элемента в массиве нет}
i := 1;
while not(Flag) and (i<=n) do
{элемент не найден и строки не закончились}
begin
j := 1;
while (j<=m) and (X[i, j]<>0) do
{перебираем все элементы текущей строки, пропуская ненулевые
элементы}
Inc(j);
Flag := not(j=m+1);{если искомый элемент найден, то переменной Flag присваиваем значение True}
91
Inc(i);
end;
Check1 := Flag;
End;
Задача. Определить, является ли данный квадратный массив симметричным относительно своей главной диагонали.
В задачах подобного типа необходимо увидеть зависимость между индексами элементов массива. Для этого удобно
представить массив в виде таблицы, обозначив элементы, например, буквой а и написав рядом их индексы.
а
а
а
а
а
а
а
11
12
а
21
22
а
31
а
а
а
а
а
а
а
а
а
а
72
а
73
а
а
а
57
а
66
а
75
а
47
56
65
а
74
а
а
а
а
37
46
55
64
а
а
а
а
27
36
45
54
63
а
а
17
а
26
35
44
53
62
а
а
16
а
25
34
43
52
61
а
а
15
а
24
33
42
51
14
а
23
32
41
71
13
а
а
67
а
76
а
77
Заметим, что если массив является симметричным, то для него выполняется равенство A[i, j]=A[j, i] для всех i=1, ..., n и
j=1, ..., n. Поэтому можно составить следующую функцию:
Function Check2(X : MyArray; n, m : integer) : Boolean;
Var
i, j : integer;
Flag : Boolean;
Begin
Flag := True;
{Предполагаем, что матрица симметрична}
i := 2;
while Flag and (i<n) do
begin
j := 1;
while (j<i) and (X[i, j]=X[j, i]) do
Inc(j);
Flag := (j=i);
Inc(i);
end;
Check2 := Flag;
End;
Вопрос. Почему в функции употребляется условие i>j? Можно ли без него обойтись и что при этом изменится?
Изменение значений некоторых элементов, удовлетворяющих заданному свойству
Задача. В массиве размерностью NxM к элементам четных столбцов прибавить элемент первого столбца
соответствующей строки.
Procedure Izmenenie1(Var X : MyArray2; n, m : integer);
Var
i, j : integer;
Begin
for i := 1 to n do
for j := 1 to m div 2 do
Inc(X[i, 2*j], X[i, 1]);
End;
Вопрос. Какой смысл вложен в оператор цикла for j := 1 to m div 2 do?
Задача. Заменить все отрицательные элементы на противоположные.
Procedure Izmenenie2(Var X : MyArray2; n, m : integer);
Var
i, j : integer;
Begin
for i := 1 to n do
for j := 1 to m do
X[i, j] := Abs(X[i, j]);
End;
92
Заполнение массива по правилу
Задача. Заполнить массив А размером NxM "змейкой" следующим образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Для того, чтобы заполнить, надо вывести правило заполнения, а оно в данном случае будет таким:
если ряд нечетный, то A[i, j]=(i-1)*m+j;
если ряд четный, то A[i, j]=i*m-j+1.
По этому правилу и составляем процедуру заполнения:
Procedure FillArray(Var X : MyArray2; n, m : integer);
Var
i, j : integer;
Begin
for i := 1 to n do
for j := 1 to m do
if i mod 2 =1
then
A[i, j]=(i-1)*m+j
else
X[i, j]=i*m-j+1;
End;
Задание. Вставьте в программу-шаблон рассмотренные подпрограммы и организуйте выбор одной из них через меню.
Дополните подпрограммы, не содержащие пояснений, соответствующими комментариями. Сохраните файл на дискете.
Листинг сдайте учителю для проверки.
Задачи для самостоятельного решения
Выберите задачи из предложенного списка в соответствии с Вашим порядковым номером в журнале. При решении задач
используйте программу-шаблон. Не забудьте пояснять решение задачи комментариями. Приготовьтесь объяснить решение
задач учителю.
1. Найти сумму и количество элементов с заданным условием (хранить эти значения в массивах):
1)
элементы каждого столбца, кратные k1 или k2;
2)
элементы каждого столбца, попадающие в промежуток [А..В];
3)
элементы каждого столбца, которые являются простыми числами;
4)
элементы каждого столбца положительны и лежат выше главной диагонали;
5)
отрицательные элементы каждого столбца, меньшие заданного числа а;
6)
элементы каждого столбца, меньшие среднего арифметического элементов каждого столбца;
7)
элементы каждой строки, больших среднего арифметического элементов данной строки;
8)
максимальные элементы каждой строки;
9)
отрицательные элементы каждой строки;
10)
элементы каждой строки, равные сумме соседних с ним элементов;
11)
элементы каждой строки, равные элементу в том же столбце, но в предыдущей строке.
2. Найти и вывести на экран индексы заданных элементов массива (если их нет выдать соответствующее
сообщение):
1)
четных элементов каждой строки и нечетных элементов каждого столбца;
2)
симметричных чисел;
3)
первых k отрицательных элементов каждого столбца;
4)
последних k отрицательных элементов каждой строки;
5)
последних k отрицательных элементов каждого столбца;
6)
равных между собой элементов каждого столбца;
7)
элементов, являющимися действительными числами;
8)
элементов, являющихся трехзначными числами;
9)
элементов, не имеющих целой части;
10)
элементов, являющихся числами, сумма цифр которых равна заданному числу;
11)
элементов, являющихся числами, первая цифра которых равна заданной.
3. Используя функцию булева типа, определить:
1)
есть ли в данном массиве отрицательный элемент;
2)
есть ли два одинаковых элемента;
3)
есть ли данное число А среди элементов массива;
4)
есть ли в заштрихованной области массива (рис. а) элемент, равный введенному с клавиатуры числу (массив
имеет размерность nxn);
5)
есть ли в заштрихованной области массива (рис. b) элемент, равный введенному с клавиатуры числу (массив
имеет размерность nxn):
93
6)
есть ли в заштрихованной области массива (рис. c) элемент, равный введенному с клавиатуры числу (массив
имеет размерность nxn):
l1
l2
k1
a)
b)
k2
c)
7)
является ли массив логическим квадратом, то есть суммы по всем горизонталям, вертикалям и двум диагоналям
должны быть равны;
8)
добавить к предыдущему условию, что сумма должна быть равна данному числу А;
9)
состоящая только из положительных элементов;
10)
состоящая только из положительных или нулевых элементов;
11)
состоящая только из элементов, принадлежащих промежутку от А до В.
4. Измените исходный массив в соответствии с заданием:
1)
в каждой строке сменить знак максимального по модулю элемента на противоположный;
2)
отрицательный последний элемент каждого столбца заменить нулем;
3)
положительные элементы умножить на первый элемент соответствующей строки, а отрицательные – на
последний;
4)
заменить все элементы строки с номером k и столбца с номером р на противоположные по знаку (элемент,
стоящий на пересечении, не изменять);
5)
к элементам столбца k1 прибавить элементы столбца k2;
6)
переверните в массиве каждую третью строку;
7)
поменяйте местами заданные элементы каждого столбца;
8)
добавьте к массиву столбец, содержащий максимальный элемент соответствующей строки, и строку
содержащую минимальный элемент соответствующего столбца;
9)
найти максимальный элемент каждой строки и заменить им все минимальные элементы строки;
10)
найти минимальный и максимальный элементы столбца и заменить их суммой последний элемент;
11)
переверните в массиве каждую половину каждого столбца.
5. Решите задачу на заполнение массива по определенному правилу.
1) Составить программу вывода на экран арифметического квадрата, в нем первый столбец и первая строка заполнены
единицами, а каждый из остальных элементов равен сумме своих соседей сверху и слева. Квадрат должен быть занесен в
массив.
2) Заполнить массив А размером NxM следующим образом:
21
20
19
18
17
16
15
8
9
10
11
12
13
14
7
6
5
4
3
2
1
3) Заполнить массив А размером NxM следующим образом:
1
0
2
0
3
0
4
0
5
0
6
0
7
0
8
0
9
0
10
0
11
4) Заполнить квадратный массив В размером NxN следующим образом:
1
4
7
10
13
17
20
2
5
8
11
14
18
21
3
6
9
12
15
19
22
5) Заполнить квадратный массив В размером NxN следующим образом:
1
3
4
10
11
21
2
5
9
12
20
22
6
8
13
19
23
30
7
14
18
24
29
31
15
17
25
28
32
35
16
26
27
33
34
36
6) Заполнить квадратный массив В размером NxN (N<10)следующим образом:
1
2
3
4
5
6
7
11
12
13
14
15
16
17
21
22
23
24
25
26
27
7) Заполнить квадратный массив В размером NxN следующим образом:
0
1
1
1
1
0
2
0
1
1
0
4
2
2
0
0
4
4
2
2
0
0
4
4
2
0
3
3
0
4
94
0
3
3
3
3
0
8) Заполнить квадратный массив В размером NxN следующим образом:
6
1
1
1
1
5
2
6
1
1
5
4
2
2
6
5
4
4
2
2
5
6
4
4
2
5
3
3
6
4
5
3
3
3
3
6
9) Заполнить квадратный массив В следующим образом: первая строка – числа Фибоначчи, а каждый столбец
продолжает ряд Фибоначчи от элемента, находящегося в первой строке.
10) Заполнить массив рядом натуральных чисел, расположив их закручивающейся спиралью по часовой стрелке.
11) Заполнить массив рядом натуральных чисел, расположив их раскручивающейся спиралью против часовой стрелки.
Занятие 3. Вставка и удаление строк и столбцов.
Мы уже рассматривали такие действия для одномерных массивов. Обобщим для двумерных.
Вставка строк и столбцов
Для решения задачи вставки строки необходимо:
1. Первые k строк оставить без изменения.
2. Все строки после k-ой сдвинуть на одну назад, это лучше сделать, начиная с последней строки и идти до (k+1)-ой.
3. Элементам строки k+1 присвоить заданное значение.
4. Увеличить количество строк.
Кроме того, необходимо изменить размерность массива. Так как мы вставляем строку, то число строк будет на одну
больше.
Задача. Вставить строку из нулей после строки с номером k.
Procedure Insert1(Var X : MyArray2; n, m : integer; k1 : integer);
Var
i, j : integer;
Begin
for i := n downto k1 +1 do
for j := 1 to m do
X[i+1, j] := X[i, j];{элементу столбца j присваиваем элемент этого же столбца, но из предыдущей строки}
for j := 1 to m do
X[k1+1, j] := 0;
Inc(n);
End;
Для вставки столбца пользуйтесь практически тем же правилом, только размерность увеличивается для столбцов и
сдвигаем назад столбцы.
Задание. Напишите программу, содержащую процедуры вставки строки и столбца из заданного одномерного массива.
И еще несколько советов.
1. Если необходимо вставить после строки, удовлетворяющей какому-либо условию, то надо найти лишь ее номер и
задача сводится к рассмотренной выше.
2. Если надо вставлять после всех строк с заданным условием, то надо увеличить размерность по строкам, и если строка
удовлетворяет условию, то к ней применять вставку. При этом надо заметить, что лучше просматривать строки с последней и
ввести счетчик вставленных строк.
3. Вставка перед строкой с данным номером отличается лишь тем, что сдвигать назад надо не с (k+1)-ой строки, а с k-ой.
Удаление строк и столбцов
Для решения задачи удаления строки необходимо:
1. Сдвинуть все строки, начиная с данной на одну вверх.
2. Последнюю строку обнулить.
3. Уменьшить количество строк.
Процедура удаления строки приведена ниже.
Procedure Delete1(Var X : MyArray2; Var n, m : integer; k1 : integer);
Var
i, j : integer;
Begin
for i := k1 to n-1 do
for j := 1 to m do
X[i, j] := X[i+1, j];
for j := 1 to m do
X[n, j] := 0;
Dec(n);
End;
Удаление столбца аналогично удалению строки.
95
И еще несколько советов.
1. При выводе на экран полученного массива не выводите нулевые строки и столбцы.
2. Задачу об удалении строки с заданным условием можно решить тем же способом, достаточно только найти ее номер,
а в случае отсутствия такой строки можно просто сообщить об этом и закончить программу.
Задание. Выберите с учителем задачи из предложенного списка. Решите их, применяя подпрограммы, приготовьте для
проверки 3-4 теста.
Задачи для самостоятельного решения
Задачи на вставку элементов.
1. Вставить первую строку после строки, в которой находится первый встреченный максимальный элемент и первый
столбец перед всеми столбцами, в которых встретится заданное число. Если такого столбца или строки нет, то вывести
сообщение об этом.
2. Вставить второй столбец после первого столбца, в котором все элементы положительны и заданную строку перед
всеми строками, в которых все элементы отрицательны. Если такого столбца или строки нет, то вывести сообщение об этом.
3. Вставить нулевую строку и нулевой столбец перед строками и столбцами, где находятся минимальные элементы.
4. Вставить после всех строк, в которых есть заданное число А, последнюю строку, а перед столбцами, которые задал
пользователь, нулевой столбец. Если такого столбца или строки нет, то вывести сообщение об этом.
5. Вставить перед всеми столбцами, в которых нет отрицательных элементов, второй столбец, а после строк, в которых
есть отрицательный элемент, вставить строку, полученную случайным образом. Если такого столбца или строки нет, то
вывести сообщение об этом.
6. Вставить перед всеми строками, в которых есть 0, первую строку, а после всех столбцов, в которых есть
отрицательные элементы – первый столбец.
7. Вставить нулевую строку и столбец перед строкой и после столбца, в которых встретился элемент, равный сумме
своих индексов. Если такого столбца или строки нет, то вывести сообщение об этом.
8. Вставить нулевую строку и столбец перед строкой и столбцом, в которых встретился минимальный элемент.
9. В квадратном массиве вставить перед четными столбцами нулевой столбец, а после нечетных строк строку,
состоящую из единиц.
10. Если в строке есть элемент, равный среднему арифметическому элементов этой строки, то вставьте после него
строку, состоящую из этих элементов. Перед столбцом, в котором находится элемент, равный индексу строки, вставьте
строку, состоящую из единиц. Если такого столбца или строки нет, то вывести сообщение об этом.
11. Если в строке имеется элемент, равный сумме своих соседей, то вставить перед этой строкой нулевую и после
столбца, в котором находится этот элемент, нулевой столбец. Если такого столбца или строки нет, то вывести сообщение об
этом.
Задачи на удаление элементов
1. Если в массиве есть равные строки, то удалите их. Если в получившемся после удаления строк массиве обнаружен
столбец, каждый элемент которого больше на единицу соответствующего элемента в предыдущем столбце, то удалите его.
Если такого столбца или строки нет, то вывести сообщение об этом.
2. Удалите строки, содержащие ноль, а затем столбцы, в которых только отрицательные элементы. Если такого столбца
или строки нет, то вывести сообщение об этом.
3. Удалите строки, содержащие более одного максимального элемента, а затем столбцы, сумма элементов которых равна
заданному числу. Если такого столбца или строки нет, то вывести сообщение об этом.
4. Удалите строку и столбец, на пересечении которых находится второй, пятый и седьмой встреченные отрицательные
элементы. Если такого столбца или строки нет, то вывести сообщение об этом.
5. Удалить все строки и столбцы, на пересечении которых стоят отрицательные элементы. Если такого столбца или
строки нет, то вывести сообщение об этом.
6. Если в столбцах, встретился элемент, равный сумме первых двух элементов текущего столбца, то удалите строки, в
которых они находятся. Удалите столбцы, в которых первый элемент нулевой. Если такого столбца или строки нет, то
вывести сообщение об этом.
7. Удалите все столбцы, в котором находится минимальный элемент, а затем строки, в которых больше одного
максимального элемента. Если такого столбца или строки нет, то вывести сообщение об этом.
8. Удалить строки с номерами, кратными k, и столбцы, в которых нет отрицательного элемента. Если такого столбца или
строки нет, то вывести сообщение об этом.
9. Удалить все столбцы, с номерами, оканчивающимися нулем, а затем строки, в которых на четных местах находятся
нули, а на нечетных – единицы. Если такого столбца или строки нет, то вывести сообщение об этом.
10. Удалите строки, находящиеся между первым минимальным и последним максимальным элементами текущего
столбца. В оставшихся строках удалить столбцы, в которых встретился максимальный отрицательный элемент текущей
строки. Если такого столбца или строки нет, то вывести сообщение об этом.
11. Удалите столбцы, в которых есть заданный элемент, а затем строки, сумма элементов первой половины которых
больше суммы элементов второй половины. Если такого столбца или строки нет, то вывести сообщение об этом.
Файл сохраните на дискете, листинг сдайте учителю для оценки.
Занятие 4. Перестановка элементов массива.
Рассмотрим задачу о перестановки двух столбцов (аналогично и для строк), так как многие задачи используют именно
это действие.
96
Задача. Поменять местами столбцы с номерами m1 и m2.
Эту задачу можно реализовать несколькими способами. Мы составим две процедуры, причем процедура обмена
столбцами содержит в себе процедуру обмена значениями двух переданных ей ячеек массива. Рассмотрите их.
Procedure Swap2(Var X : MyArray2; n, m, m1, m2 : integer;);
Var
i, j : integer;
Procedure Swap1(Var elem1, elem2 : integer);
Var
z : integer;
Begin
z:=elem1;
elem1:=elem2;
elem2:=z;
End;
Begin
if((m1<1) or (m1>m)) or ((m2<1) or (m2>m))
then
writeln('?')
else
for i := 1 to m do
Swap1(X[i, m1], X[i, m2]);
End;
Вопрос. Какое сообщение должно быть выведено оператором writeln вместо знака вопроса и почему?
Задание. Выберите с учителем задачи из предложенного списка. Решите их, применяя подпрограммы, приготовьте для
проверки 3-4 различных теста.
Задачи для самостоятельного решения
1. В квадратном массиве поменять местами строку и столбец, на пересечении которых находится ноль. Если такого
элемента нет, то вывести сообщение об этом.
2. Поменять местами каждые две строки массива.
3. В каждой строке переставить первый отрицательный и последний положительный элементы. Поменять местами
столбцы, в которых находятся первый встреченный максимальный и последний минимальный элементы. Если такого
столбца или строки нет, то вывести сообщение об этом.
4. Если количество столбцов нечетно, то поменять первый и средний столбец, если четно, то средние два столбца
поменять с первым и последним соответственно.
5. Поменять местами первую строку и строку, в которой находится первый нулевой элемент.
6. В двумерном массиве переставить строки следующим образом: первую с последней, вторую с предпоследней и так
далее. Если строк нечетное количество, то средняя останется неизменной, иначе средние строки тоже меняем местами.
7. Дан двумерный массив. Расставить его столбцы следующим образом: последний, предпоследний, ..., второй, первый.
8. Дан двумерный массив. Начиная с первой строки, сдвинуть все строки на две вниз, а последние две перенести на
место первых двух строк.
9. Первые k столбцов сдвинуть назад, а последние k поставить на место первых.
10. Дан двумерный массив. Расставить его строки следующим образом: первая, последняя, вторая, предпоследняя,
третья, ... .
11. Начиная с k-го столбца, сдвинуть их вперед, а первые k поставить на место последних.
Файл сохраните на дискете, листинг сдайте учителю для оценки.
Занятие 5. Самостоятельное решение задач.
Выберите с учителем задачи из предложенного ниже списка.
I. Заполнение и анализ элементов массива
1. Заполнить квадратный двумерный массив таким образом, чтобы на главной диагонали были расположены числа от N
до 1, под главной диагональю нули, а над главной диагональю по строкам числа в порядке возрастания от заданного.
Используйте подпрограммы для решения каждой частной задачи.
2. Заполнить квадратный двумерный массив по следующему правилу: элементы главной диагонали равны 1, ниже
главной диагонали – 0, а выше – сумме индексов. Используйте подпрограммы для решения каждой частной задачи.
3. Заполните квадратный массив единицами в шахматном порядке, начиная с верхнего левого угла. Используйте
подпрограммы для решения каждой частной задачи.
97
4. Заполните двумерный массив с клавиатуры только числами кратными трем, предусмотрите защиту элементов этого
массива от неправильного ввода и найдите сумму тех элементов массива, которые без остатка делятся на 9. Используйте
подпрограммы для решения каждой частной задачи.
5. Заполните двумерный массив с клавиатуры только неотрицательными числами, предусмотрите защиту элементов
этого массива от неправильного ввода. Найдите число нулевых элементов, расположенных в нечетных строках. Используйте
подпрограммы для решения каждой частной задачи.
6. Заполните двумерный массив с клавиатуры только простыми числами, предусмотрите защиту элементов этого
массива от неправильного ввода. Найдите сумму элементов, имеющих нечетную сумму индексов. Используйте
подпрограммы для решения каждой частной задачи.
7. Заполняя двумерный массив с клавиатуры, предусмотрите замену вводимых отрицательных элементов на (-1),
положительных на 1, нулевые оставить без изменения. Найдите число элементов, равных (-1), расположенных в четных
строках. Используйте подпрограммы для решения каждой частной задачи.
8. Для данного двумерного массива найти среднее арифметическое наибольшего и наименьшего значений ее элементов
и замените им все элементы заданной строки. Используйте подпрограммы для решения каждой частной задачи.
9. Определите, имеются ли в двумерном массиве строки, равные первой строке. Если есть, выведите их индексы на
экран. Используйте подпрограммы для решения каждой частной задачи.
10. Для данного двумерного массива укажите индексы тех элементов, сумма которых равна заданному числу (если такие
есть). Если таких элементов нет, вывести об этом сообщение. Используйте подпрограммы для решения каждой частной
задачи.
11. Дан двумерный массив. Найдите сумму элементов столбца и строки массива, на пересечении которых находится
нулевой элемент. Используйте подпрограммы для решения каждой частной задачи.
II. Работа с одномерным и двумерным массивами
1. Составить программу, записывающую все положительные элементы двумерного массива А в одномерный массив В, а
отрицательные – в одномерный массив С. Вывести полученные массивы на экран. Используйте подпрограммы для решения
каждой частной задачи.
2. Дан двумерный массив. Сформировать одномерный массив путем деления положительных элементов заданной
таблицы на число К. Вывести полученный массив на экран. Используйте подпрограммы для решения каждой частной задачи.
3. Вычислите сумму элементов, находящихся на пересечении текущей строки и двух диагоналей двумерного
квадратного массива, и запишите их в одномерный массив. Найдите наибольший из этих элементов. (Элементами i-й строки,
лежащими на диагоналях, являются ai,j и ai,n-j+1). Используйте подпрограммы для решения каждой частной задачи.
4. Дан двумерный массив. Заполнить одномерный массив суммами элементов строк, вывести полученную информацию
на экран и номера строк, в которых сумма наименьшая. Используйте подпрограммы для решения каждой частной задачи.
5. Дан двумерный массив. Заполнить одномерный массив наименьшими значениями элементов строк, вывести
полученную информацию на экран и номера строк, в которых значения наименьшие. Используйте подпрограммы для
решения каждой частной задачи.
6. Дан двумерный массив. Заполнить одномерный массив разностями наибольших и наименьших значений элементов
строк, вывести полученную информацию на экран и номера строк, в которых разности одинаковые. Используйте
подпрограммы для решения каждой частной задачи.
7. Для данного двумерного массива вычислите и запомните в другом двумерном массиве сумму и число положительных
элементов каждого столбца заданного двумерного массива. Используйте подпрограммы для решения каждой частной задачи.
8. Для данного двумерного массива вычислите и запомните в другом двумерном массиве сумму и число положительных
элементов каждой строки и расположенных не ниже главной диагонали заданного двумерного массива. Используйте
подпрограммы для решения каждой частной задачи.
9. Из предложенного одномерного массива размерностью S сформируйте двумерный массив так, чтобы первая строка
новой таблицы содержала бы четные по номеру элементы исходного массива, а вторая – нечетные. Предусмотрите случай
нечетности S. Используйте подпрограммы для решения каждой частной задачи.
10. Дан произвольный двумерный массив. Занести в другой двумерный массив в каждую строку следующую
информацию о повторяющихся элементах: на первое место сам элемент, далее двузначные числа, первая цифра которых
является индексом строки, вторая – индексом столбца всех совпадающих элементов. Используйте подпрограммы для
решения каждой частной задачи.
11. Для целочисленного двумерного массива найти для каждой строки число элементов, кратных 5, запишите
информацию в одномерный массив и найдите наибольший из полученных результатов. Используйте подпрограммы для
решения каждой частной задачи.
Дополнительные задачи (на усмотрение учителя)
1. Заполните одномерный массив произведениями элементов строк заданного двумерного массива и выведите его на
экран. Найдите сумму этих произведений. Используйте подпрограммы для решения каждой частной задачи.
2. Заполните одномерный массив положительными элементами, расположенные на главной диагонали заданного
квадратного массива. Выведите полученный массив на экран и найдите произведение элементов. Используйте подпрограммы
для решения каждой частной задачи.
3. Дан двумерный квадратный массив. Вычислить сумму тех его элементов, расположенных на главной диагонали и
выше нее, которые превосходят по величине все элементы, расположенные ниже главной диагонали. Если на главной
диагонали и выше нее нет элементов с указанным свойством, то выдайте соответствующее сообщение. Используйте
подпрограммы для решения каждой частной задачи.
4. Дан двумерный квадратный массив. Найти номера строк, все элементы которых равны нулю. Используйте
подпрограммы для решения каждой частной задачи.
98
5. Дан двумерный квадратный массив. Найти номера строк, элементы в каждой из которых одинаковы между собой.
Используйте подпрограммы для решения каждой частной задачи.
6. Дан двумерный квадратный массив. Найти номера строк, все элементы которых четны. Используйте подпрограммы
для решения каждой частной задачи.
7. Сколько в произвольном двумерном массиве содержится различных элементов? Занесите их в одномерный массив и
выведите на экран. Используйте подпрограммы для решения каждой частной задачи.
8. Дан двумерный массив. Найти наибольший и наименьший элементы массива и ,чередуя, заполнить ими одномерный
массив заданной размерности. Используйте подпрограммы для решения каждой частной задачи.
9. Дан двумерный квадратный массив. В каждой строке двумерного массива наибольший элемент и элемент главной
диагонали поменять местами, а их среднее арифметическое занести в одномерный массив. Вывести на экран полученный
массив и среднее арифметическое его элементов. Используйте подпрограммы для решения каждой частной задачи.
10. Дан двумерный квадратный массив. В каждой строке двумерного массива наибольший элемент поместить на место
первого элемента массива, а наименьший элементы – на место последнего. Создать одномерный массив, элементы которого
являются суммой этих элементов. Вывести на экран полученный массив и сумму его элементов. Используйте подпрограммы
для решения каждой частной задачи.
11. Определить минимальный элемент двумерного массива. Напечатать номер строки, содержащей максимальное число
минимальных элементов, если такие имеются. Используйте подпрограммы для решения каждой частной задачи.
12. В двумерном массиве Х все числа различны. В каждой строке выбирается минимальный элемент, затем среди этих
чисел выбирается максимальное. Напечатать номер строки массива Х, в которой расположено выбранное число.
13. Дан двумерный массив. Найти наибольшее из значений элементов первой и последней строки. Используйте
подпрограммы для решения каждой частной задачи.
14. Дан двумерный массив. Найдите сумму наибольших значений элементов его строк. Используйте подпрограммы для
решения каждой частной задачи.
15. Дан двумерный массив. Найдите строку с наибольшей суммой элементов и наименьшей. Вывести на экран
найденные строки и суммы их элементов. Используйте подпрограммы для решения каждой частной задачи.
16. Составьте программу нахождения седловой точки таблицы. Седловой точкой называется элемент, являющийся
одновременно максимальным в столбце и минимальным в строчке. Используйте подпрограммы для решения каждой частной
задачи.
17. Дан двумерный квадратный массив. В строках с отрицательным элементом на главной диагонали найти сумму всех
элементов и наибольший из всех элементов. Используйте подпрограммы для решения каждой частной задачи.
18. Дан двумерный массив. Найдите сумму элементов столбца и строки массива, на пересечении которых находится
максимальный элемент. Используйте подпрограммы для решения каждой частной задачи.
19. Дан двумерный массив. Найдите сумму минимальных элементов диагоналей массива. Используйте подпрограммы
для решения каждой частной задачи.
20. Дан двумерный массив. Преобразовать его по следующему правилу: строку с номером N сделать столбцом с
номером N, а столбец – строкой.
21. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (a).
22. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (b).
23. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (c).
24. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (d).
25. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (e).
26. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (f).
27. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (g).
28. Дан двумерный массив. Найти наибольшее из значений элементов, расположенных в заштрихованной части (k).
29*. "Магическим" квадратом называется квадратная таблица целых чисел от 1 до N, расположенных так, что суммы
элементов каждой строки, каждого столбца и обеих диагоналей одинаковы и равны (1/2)*N*(1+N) 2.
99
Построить "магический" квадрат для N=3, N=4, N=5.
30*. Построить и вывести на экран "латинский" квадрат - таблицу, состоящую из n различных чисел, всех по n раз
расположенных так, что в каждой строке и столбце каждое число встречается только один раз.
Занятие 6. Контрольная работа
1. Данный фрагмент программы преобразуйте в подпрограмму, используя правила форматирования:
Program Primer; Var a: array[1..8] of integer; M, k: integer;
Begin for k:=1 to 8 do readln(a[k]);M:=a[1]; for k:=2 to 8 Do if M<a[k] Then M:=A[k]; Write(m)
End.
Сколько раз будет исполнен подчеркнутый оператор при заданном массиве: 3, 8, 7, 9, 4, 10, 2, 12:
a)
7;
b)
8;
c)
4;
d)
1.
Чему будет равно значение М?
2. Чему будет равно значение переменной К после исполнения фрагмента программы
K:=1; while (a[K]<>X) and (K<=10) do K:=K+1;
(Здесь Х=7, а в качестве элементов массива введены числа: 2, 3, 5, 9, 12, 0, 7, 6, 7.)
3. При наборе программы вычисления суммы отрицательных элементов массива
for k:=1 to 8 do readln(a[k]); s:=0; for k:=1 to 8 do if a[k]<0 then s:=s+1; write(s)
была допущена ошибка. Каким оказался ответ, если были введены числа: -1, 3, -2, 4, -5, 6, -7, 8.
Каким должен был быть оператор и чему равен правильный ответ?
4. Дано тело подпрограммы:
begin
for k:=1 to 4 do for g:=1 to 4 do a[k,g]:=g-k;q:=0; for k:=1 to 4 do for g:=1 to 4 do if a[k,g]<0 then begin q:=q+1;
b[q]:=a[k,g] end; m:=b[1]; for k:=1 to q do if m<b[k] then m:=b[k]; writeln(m);
end;
Опишите заголовок подпрограммы и необходимые локальные переменные.
Какое число будет выведено после ее выполнения?
5. Основное различие между процедурами и функциями заключается в том, что:
a)
в результате работы процедуры можно получить любое количество переменных, а функции – одно;
b)
в процедуре допускается описание локальных переменных, а в функции – нет;
c)
в программе обращение к процедуре может осуществляться многократно, тогда как к функции только один
d)
в процедуре допускается использование глобальных переменных, а в функции – нет.
раз;
6. Формальные параметры процедуры:
a)
описываются в ее заголовке;
b)
перечисляются при вызове процедуры;
c)
указываются при описании данных в программе;
d)
указываются при описании промежуточных переменных процедуры.
7. Фактические параметры процедуры:
a) описываются в ее заголовке;
b) перечисляются при вызове процедуры;
100
c) указываются при описании данных в программе;
d) указываются при описании промежуточных переменных процедуры.
8. Задача о выборах
Пусть шесть населенных пунктов, обозначенные номерами от 1 до 6 (величина k), а пять кандидатов – номерами от 1
до 5 (величина n). Количество голосов, набранных кандидатами в каждом пункте, определяется формулой
ak=random(10i+50), где i – номер Вашего варианта. В результате получается таблица результатов голосования, где значения
в строках – данные из населенных пунктов, а в столбцах – данные по конкретным кандидатам. Создайте в подпрограмме
одномерный массив с искомыми данными в соответствии со своим вариантом.
1.
Какое количество голосов было подано за первого и второго кандидатов во всех населенных пунктах?
У кого из второго, четвертого и пятого кандидатов наивысший рейтинг?
2.
В каких населенных пунктах второй и четвертый кандидаты набрали максимальное количество
голосов? Кто набрал максимальное, а кто минимальное количество голосов в первом населенном пункте?
3.
Сколько избирателей приняли участие в голосовании в каждом из населенных пунктов? В каких
населенных пунктах первый и пятый кандидаты набрали больше 100 голосов?
4.
Кто из кандидатов имеет максимальный рейтинг? В каких населенных пунктах количество участников
выборов не превысило 450?
5.
Кто из кандидатов набрал максимальное количество голосов во втором населенном пункте? У кого из
кандидатов рейтинг больше некоторого заданного числа р?
6.
В каких населенных пунктах количество опрошенных больше некоторого заданного числа р? Какие
кандидаты набрали минимальное количество голосов в каждом из населенных пунктов?
7.
За кого из кандидатов подано количество голосов меньше некоторого заданного числа р? Какие
кандидаты набрали максимальное и минимальное количество голосов во втором и пятом населенных пунктах?
8.
В каких населенных пунктах первый кандидат набрал максимальное количество голосов? У кого из
кандидатов наименьший рейтинг?
9.
В каком населенном пункте проголосовало наибольшее количество людей? У кого из кандидатов
рейтинг превысил некоторое заданное число р?
10.
Кто из кандидатов набрал наибольшее количество голосов во втором и третьем населенных пунктах?
В каких населенных пунктах третий кандидат набрал максимальное количество голосов?
11.
В каком населенном пункте первый кандидат набрал минимальное количество голосов, а в каком
максимальное? Определить номера населенных пунктов, где количество поданных голосов превысило 150.
Для любопытных. Графические программы с применением массивов.
Рассмотрите приведенный ниже пример.
Задача. Нарисовать олимпийский флаг. Обеспечьте в программе ввод радиуса колец (R) и расположение флага на
экране, задавая координаты его верхнего правого угла (Х, Y). Для хранения цветов колец использовать массив.
Program Flag;
Uses
Graph;
Var
...
U, V, X, Y, R, A, B, L, i : integer;
Palitra : array [1..5] of integer;
Begin
write('R=');
readln (R);
write('X=');
readln (X);
write('Y=');
readln (Y);
...{Инициализация графического режима}
Palitra [1] := LightBlue;
Palitra [2] := Black;
Palitra [3] := Red;
{Задание цветов колец}
Palitra [4] := Yellow;
Palitra [5] := Green;
A := 7*R;
101
B := 5*R;
{Вычисление размера флага}
L := 2*R-round(R/4);
{Вычисление расстояния между кольцами}
SetFillStyle(1, 15);
Bar (X, Y, X+A, Y+B);
{Рисование белого флага}
SetLineStyle(0, 1, 3);
U := X+Round (1.75*R); {Координаты первого верхнего кольца}
V := Y+L;
for i := 1 to 5 do
{Рисование пяти колец}
begin
if i=4
Then
Begin
U := X+Round(2.65*R); {Координаты первого нижнего кольца}
V := Y+3*R;
End;
SetColor(Pal[i]);
{Задание цвета i-го кольца}
Circle(U, V, R);
{Рисование кольца}
U := U+L;
{Расположение следующего кольца}
end;
readln;
CloseGraph;
End.
Выберите самостоятельно задачу из ниже предложенного перечня:
1. Нарисовать радугу в нижней части экрана.
2. Вывести разноцветные концентрические кольца с центром в середине экрана. Обеспечить диалоговый ввод
последовательности меняющихся цветов колец и контроль выхода за границы экрана.
3. Модифицировать задачу 2 для рисования разноцветных неконцентрических колец, цвета которых вводятся в диалоге.
4. Нарисовать шахматную доску. Расставить шашечную позицию, которая запрашивается с экрана. Расположение
шашки задается парой чисел: номером клетки по вертикали и по горизонтали.
5. Нарисовать схему расположения городов, которые отмечаются на экране кружочками. Координаты городов
предварительно вводятся с клавиатуры.
6. Модифицировать предыдущую задачу, предполагая, что размер кружка зависит от численности населения города.
7. Изобразить на экране движение шара по биллиардному столу с лузами. Расположить лузы по краям биллиардного
стола, задав их координаты в диалоге. Движение шара прекращается при попадании его в лузу.
8. Получить мультфильм "Круги на воде", используя концентрические окружности. Центры окружностей должны быть
совмещены с центром экрана. Иллюзия движения создается последовательной сменой цветов всех окружностей, начиная с
внутренней и кончая внешней. Обеспечить ввод максимального и минимального радиусов в диалоге, а также количество
волн и последовательность сменяющихся цветов.
9. Промоделировать работу светофора без учета дорожной обстановки. Обеспечить ввод временных интервалов смены
цветов. Для обеспечения временной задержки используйте процедуру Delay.
10. Нарисовать поле размером 10х10 для игры в "Морской бой". На нем с помощью датчика случайных чисел расставить
10 однопалубных кораблей, чтобы они не соприкасались друг с другом. Изобразить позицию на экране компьютера.
МЕТОДЫ СОРТИРОВКИ МАССИВА
Занятие 1. Сортировка массива. Способы сортировки массива.
Для решения многих задач удобно сначала упорядочить данные по определенному признаку, так можно ускорить поиск
некоторого объекта. Например, в преферансе игроки раскладывают карты по мастям и по значению. Так легче определить,
каких карт не хватает. Или возьмем любой энциклопедический словарь – статьи в нем упорядочены в алфавитном порядке.
Перегруппирование заданного множества объектов в определенном порядке называют сортировкой.
Почему сортировке уделяется большое внимание? Вы это поймете, прочитав цитаты двух великих людей.
"Даже если бы сортировка была почти бесполезна, нашлась бы масса причин заняться ею! Изобретательные методы
сортировки говорят о том, что она и сама по себе интересна как объект исследования." /Д. Кнут/
"Создается впечатление, что можно построить целый курс программирования, выбирая примеры только из задач
сортировки." /Н. Вирт/
Отличительной особенностью сортировки является то обстоятельство, что эффективность алгоритмов, реализующих ее,
прямо пропорциональна сложности понимания этого алгоритма. Другими словами, чем легче для понимания метод
сортировки массива, тем ниже его эффективность.
Сегодня существует множество методов сортировки, но для понимания сути сортировки рассмотрим некоторые из них.
102
Но прежде чем перейти к рассмотрению конкретного алгоритма той или иной сортировки немного вспомним материал,
который пригодится нам в дальнейшем.
Задача. Даны две целочисленные переменные х и y. Составить фрагмент программы, после выполнения которого
значения этих переменных распределяются в порядке убывания.
Обмен значений переменных нужно производить лишь в том случае, если х<у. Для того чтобы не потерять начальное
значение переменной х, введем дополнительную переменную t.
if x<y
then
begin
t:=x;
x:=y;
y:=t;
end;
Задача. Составить фрагмент программы поиска максимального числа из трех введенных с клавиатуры чисел.
Пусть а, b, c – вводимые с клавиатуры числа, Max – максимальное из их значений. На первом шаге предположим , что а
– максимальное из чисел и поэтому Max:=a. Затем сравним значение предполагаемого максимума со значениями переменных
b и с. Если значение m окажется меньше, чем значение очередной переменной, то переопределим значение максимума.
. . .
m:=a;
if m<b
then
m:=b;
if m<c
then
m:=c;
. . .
Задача. Дан массив а, состоящий из 10 элементов. Составить программу поиска максимального элемента массива.
Используем идею предыдущей задачи. Перед началом поиска выберем условно в качестве максимального первый
элемент массива Max:=a[1]. Затем по очереди каждый элемент массива сравним со значением переменной m. Если он
окажется больше, то изменим значение Max. После анализа всех элементов массива переменная Max содержит значение
максимального элемента массива.
. . .
Max:=a[1];
for i := 2 to 10 do
if Max<a[i]
then
Max := a[i];
. . .
До написания программ Вам необходимо выполнить некоторую подготовительную работу – написать шаблон
программы следующего содержания:
Рrogram Sorting;
Сonst
n = ... ;
{количество элементов в массиве}
Type
TArray = array [1..n] of integer;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure FillArray (Var a: TArray);
103
Var
i: integer;
Begin
for i: = 1 to n do
a [i] := Random(100);
End;
{конец процедуры}
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Procedure PrintArray (a: TArray);
Var
i: integer;
Begin
for i: = 1 to n do
write (a [i]: 3, ' ');
writeln;
End;
{- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
Begin
{Главная программа}
writeln('Сортировка МЕТОДОМ . . .');
writeln('Заполняем исходный массив: ');
FillArray (a);
PrintArray (a);
AnySort (a, b);{имя процедуры, реализующей данный метод}
writeln('Отсортированный массив: ');
PrintArray (b);
End.
Для реализации различных методов сортировки Вам необходимо подготовить несколько вспомогательных процедур и
функций.
1. Функция, которая ищет минимальный элемент правее некоторого заданного и возвращает его номер в качестве
результата. Аргументами функции являются номер элемента массива и обрабатываемый массив:
2. Большинство методов сортировок основаны на обмене двух чисел. Для этой цели предназначена процедура, которая в
качестве параметров берет два числа и меняет их значения
3. Также Вам пригодится процедура, которая берет элемент с индексом i, перемещает его на место элемента с номером j.
А все элементы, которые имеют индексы от j до i-1 сдвигает на одну позицию вправо.
Задание. Подготовьте программу-шаблон, содержащую все рассмотренные выше процедуры и функции.
Занятие 2. Сортировка вставкой. Сортировка выбором.
При решении задачи сортировки обычно выдвигается требование минимального использования дополнительной памяти,
из которого вытекает недопустимость применения дополнительных массивов.
Для оценки быстродействия алгоритмов различных методов сортировки, как правило, используют два показателя:
- количество присваиваний;
- количество сравнений.
Все методы сортировки можно разделить на две большие группы:
- прямые методы сортировки;
- улучшенные методы сортировки.
Прямые методы сортировки по принципу, лежащему в основе метода, в свою очередь разделяются на три подгруппы:
1) сортировка вставкой (включением);
104
2) сортировка выбором (выделением);
3) сортировка обменом (так называемая "пузырьковая" сортировка).
Улучшенные методы сортировки основываются на тех же принципах, что и прямые, но используют некоторые
оригинальные идеи для ускорения процесса
Рассмотрим сортировку методом вставки.
Принцип метода заключается в следующем:
Массив разделяется на две части: отсортированную и не отсортированную. элементы из не отсортированной части
поочередно выбираются и вставляются в отсортированную часть так, чтобы не нарушить в ней упорядоченность элементов.
В начале работы алгоритма в качестве отсортированной части массива принимают только первый элемент, а в качестве не
отсортированной – все остальные элементы.
Таким образом, алгоритм будет состоять из (n-1)-го прохода (n – размерность массива), каждый из которых будет
включать четыре действия:
•
взятие очередного i-го не отсортированного элемента и сохранение его в дополнительной переменной;
• поиск позиции j в отсортированной части массива, в которой присутствие взятого элемента не нарушит
упорядоченности элементов;
•
сдвиг элементов массива от i-го до j-1-го вправо, чтобы освободить найденную позицию вставки;
•
вставка взятого элемента в найденную i-ю позицию.
Для реализации данного метода можно предложить несколько алгоритмов, которые будут отличаться способом поиска
позиции вставки.
Рассмотрите процедуру, реализующую выше рассмотренный алгоритм:
Procedure Vstavka(Var a : Array1);
Var
i, j,e,g:integer;
Begin
for i:=2 to c do
begin
e:=A[i];
j:=1;
while (e>a[j]) do
Inc(j);
for g:=i-1 downto j do
a[g+1]:=a[g];
a[j]:=e;
end;
End;
Задание. Составьте программу сортировки одномерного массива рассмотренным методом.
Сортировка выбором
Принцип метода:
Находим (выбираем) в массиве элемент с минимальным значением на интервале от 1-го элемента до n-го (последнего)
элемента и меняем его местами с первым элементом. На втором шаге находим элемент с минимальным значением на
интервале от 2-го до n-го элемента и меняем его местами со вторым элементом. И так далее для всех элементов до n-1-го.
Рассмотрите схему алгоритма прямого выбора.
105
5
11
3
11
7
1
4
2
9
12
1
11
3
7
5
4
Min
13
1
3
2
7
5
2
9
Min
4
11
9
14
1
2
3
7
5
4
11
9
11
9
Min
Min
15
1
2
3
4
5
7
11
9
16
1
Min
17
1
2
3
4
5
2
3
4
5
7
Min
7
11
9
Min
Рассмотрите процедуру, реализующую выше рассмотренный алгоритм:
Procedure Vibor(Var a: Array1);
Var
i, j, Min, MinI : integer;
Begin
for i:=1 to c do
begin
Min:=a[i];
MinI:=i;
for j:=i+1 to c do
if a[j]<Min
then
begin
Min:=a[j];
MinI:=j;
end;
a[MinI]:=a[i];
a[i]:=Min;
end;
End;
106
Задание. Составьте программу сортировки одномерного массива рассмотренным методом.
Занятие 3. Сортировка методом простого обмена. Рекурсивная сортировка
Принцип метода:
Слева направо поочередно сравниваются два соседних элемента, и если их взаимное расположение не соответствует
заданному условию упорядоченности, то они меняются местами. Далее берутся два следующих соседних элемента и так
далее до конца массива.
После одного такого прохода на последней n-ой позиции массива будет стоять максимальный (или минимальный)
элемент ("всплыл" первый "пузырек"). Поскольку максимальный (или минимальный) элемент уже стоит на своей последней
позиции, то второй проход обменов выполняется до (n-1)-го элемента. И так далее. Всего требуется (n-1) проход.
Задание. В тетради начертите схему работы рассмотренного алгоритма произвольно выбранного массива.
Рассмотрите процедуру, реализующую выше рассмотренный алгоритм:
Procedure Obmen(Var a : Array1);
Var
i,j,f,g:integer;
Begin
for i:=n downto 2 do
for j:=1 to i-1 do
if a[j]>a[j+1]
then
begin
f:=a[j];
a[j]:=a[j+1];
a[j+1]:=f;
end;
End;
Задание. Составьте программу сортировки одномерного массива рассмотренным методом.
Cортировка массива с помощью рекурсии.
Рассмотрим использование рекурсии для построения алгоритма сортировки значений массива.
Алгоритм реализуется следующим образом: в некотором отрезке массива выбирается центральное (серединное)
значение; все элементы из левой части отрезка, превосходящие центральное значение, перемещаются в правую часть, и
наоборот. На следующем шаге (для которого используются рекурсивные вызовы этой же процедуры) алгоритм повторяется
для обоих частей отрезка.
Рассмотрите процедуру, упорядочивающую по возрастанию значения из массива Massiv в диапазоне индексов
Left..Right.
Procedure QuickSort (Left, Right : integer; Massiv : Array1);
Var
i, j, x, y : integer;
Begin
i := Left;
j := Right;
x := Massiv[(Left+Right) div 2];{}
repeat
while Massiv[i]<x do
Inc(i);
while Massiv[j]>x do
Dec(j);
if i<=j
then
begin
107
y := Massiv[i];
Massiv[i] := Massiv[j];
Massiv[j] := y;
Inc(i);
Dec(j);
end;
until i>j;
if Left<j
then
QuickSort (Left, j);
if i<Right
then
QuickSort (i, Right);
End;
Задача. Составьте программу, реализующую рассмотренный метод. Дополните ее комментариями.
Занятие 4. Сортировка методом слияний.
Определение. Целочисленный массив с расположенными по неубыванию или по невозрастанию значениями элементов
называется упорядоченным.
Использование упорядоченности позволяет создавать эффективные алгоритмы для решения многих интересных задач.
Задача слияния двух входных упорядоченных массивов А и В состоит в формировании упорядоченного выходного
массива С, содержащего все элементы из входных массивов.
Рассмотрим алгоритм слияния для упорядоченных по неубыванию массивов. Вначале элемент А[1] сравнивается с
элементом В[1] и наименьший из них записывается в массив С. Если наименьшим был А[1], то на следующем шаге
сравниваются А[2] и B[1], а если наименьшим был B[1], то будут сравниваться A[1] и B[2] и т.д. Если на очередном шаге
окажется, что из одного входного массива все элементы переписаны в С, то переписывается элемент из другого массива.
Рассмотрим пример работы алгоритма слияния.
Пусть в массиве А содержатся 3 элемента: {5, 13, 14}, а в массиве В – 4 элемента: {7, 9, 10, 12}. Внимательно
рассмотрите таблицу, в которой по шагам показано изменение переменных i, i1, i2 и действия с массивами.
i
i1
i2
Сравниваются
C[i]
1
1
1
A[1]=5 и B[1]=7
5
2
2
1
A[2]=13 и B[1]=7
7
3
2
2
A[2]=13 и B[2]=9
9
4
2
3
A[2]=13 и B[3]=10
10
5
2
4
A[2]=13 и B[4]=12
12
6
2
5
В весь переписан
13
7
3
5
В весь переписан
14
Рассмотрите фрагмент решения задачи на слияние двух массивов А и В, которые содержат соответственно n1 и n2
элементов. Результирующий массив С будет содержать n1+n2 элементов.
. . .
i1 := 1;
i2 := 1;
for i := 1 to n1+n2 do
if i1>n1
then
begin
C[i] := B[i2];
i2 := i2+1;
end
else
if i2>n2
then
begin
C[i] := A[i1];
108
i1 := i1+1;
end
else
if A[i1]<=B[i2]
then
begin
C[i] := A[i1];
i1 := i1+1;
end
else
begin
C[i] := B[i2];
i2 := i2+1;
end;
. . .
Задача. Составьте программу, реализующую рассмотренный метод. Дополните ее комментариями.
Для любопытных. Рекурсивная сортировка слиянием
Задача. Напишите программу, содержащую алгоритм слияния в процедуре Sort(A, B, b1, e1, e2). Алгоритм должен
копировать со слиянием два упорядоченные куска из массива А с номерами от b1 до e1 и от e1+1 до e2 соответственно в
массив В с номерами элементов от b1 до e2.
Предположив, что Вы правильно выполнили предыдущую задачу, алгоритм сортировки можно определить очень
просто:
1) если длина сортируемого массива 1, то ничего не делается;
2) в противном случае массив делится на две одинаковые (или почти одинаковые) части, к каждой части применяется
алгоритм сортировки, после чего эти упорядоченные части сливаются в один упорядоченный кусок.
Рассмотрите процедуру сортировки слиянием. На вход процедуры сортировки поступает неупорядоченный кусок
массива А с номерами элементов от b до e, на выходе – тот же кусок, но упорядоченный. Массив С – вспомогательный.
Procedure Sort2(Var A, C : Array1; b, e : integer);
Var
i, d : integer;
Begin
if b<e
then
begin
d := (b+e) div 2;
Sort2(A, C, b, d);
Sort2(A, C, d+1, e);
Sort(A, C, b, d, e);
for i := b to e do
A[i] := C[i]
end;
End;
Занятие 5-6. Самостоятельное решение задач.
Задание. Выберите с учителем задачи для решения из предложенного ниже перечня.
1. В массиве X(N) каждый элемент равен 0, 1 или 2. Переставить элементы массива так, чтобы сначала
располагались все единицы, затем все двойки и, наконец, все нули (дополнительного массива не заводить).
2. В заданной последовательности все элементы, не равные нулю, расположить сохраняя их порядок следования, в
начале последовательности, а нулевые элементы - в конце последовательности. Дополнительного массива не заводить.
3. Отсортировать массив по возрастанию, используя процедуру Swap, которая меняет местами 2 элемента.
4. Составьте алгоритм, упорядочивающий элементы массива, стоящие на нечетных местах, в возрастающем порядке,
а на четных - в убывающем.
5. Из двух упорядоченных одномерных массивов (длины K и N) сформируйте одномерный массив размером K+N,
упорядоченный так же, как исходные массивы.
6. Из двух упорядоченных одномерных массивов (длины K и N) сформируйте одномерный массив размером K+N,
упорядоченный в обратную сторону.
109
7. Составьте алгоритм, упорядочивающий заданную последовательность чисел так, чтобы каждый элемент, стоящий
на четном месте, был больше каждого из соседних.
8. Дан упорядоченный целочисленный массив. Сформировать второй массив всех таких различных значений,
которые в первом массиве встречаются по два и более раза.
9. Дан упорядоченный целочисленный массив. Сформировать второй массив всех таких различных чисел, которые
ни разу в первом массиве не встречаются и имеют величину больше минимального и меньше максимального из чисел
первого массива.
10. Дана вещественная матрица размером 7x4. Переставляя ее строки и столбцы, добиться того, чтобы наибольший
элемент (один из них) оказался в левом верхнем углу.
11*. В заданном целочисленном массиве найти элементы, сумма которых равна данному числу, в предположении,
что такие числа существуют.
12. Дан массив А, состоящий из n элементов. Осуществить перестановку элементов массива на M элементов вправо.
13. В двумерном массиве поменяйте местами первую строчку, и строчку в которой находится первый нулевой
элемент.
14. В двумерном массиве переставьте строки следующим образом: первую с последней, вторую с предпоследней и
так далее. Если строк нечетное число, то средняя остается неизмененной.
15. Дан двумерный массив А. Расставить его столбцы в следующем порядке:
а) последний, предпоследний, ..., второй, первый;
б) первый, последний, второй, предпоследний, третий, ...
16. Дан двумерный массив. Начиная с первой строки, сдвинуть все строки на две вниз, а последние перенести на
место первых двух строк.
17. Дан двумерный массив вещественных чисел размерностью [1..N,1..N]. Произвести сортировку столбцов по
убыванию элементов последней строки. Вычислить сумму элементов расположенных на диагоналях полученной матрицы.
Сортировку произвести методом прямого выбора. Вывести на экран исходный и полученный массивы в виде матрицы.
18. Дан двумерный массив вещественных чисел размерностью [1..N,1..N]. Произвести сортировку столбцов по
возрастанию элементов первой строки. Вычислить среднее арифметическое элементов расположенных по периметру
полученной матрицы. Сортировку произвести методом прямого выбора. Вывести на экран исходный и полученный массивы
в виде матрицы.
19. Дан двумерный массив, содержащий 4 строки и 5 столбцов. Элементами массива являются целые числа.
Упорядочить массив по возрастанию элементов 3-го столбца.
20. Дан двумерный массив, содержащий 4 строки и 5 столбцов. Элементами массива являются целые числа.
Упорядочить массив по убыванию элементов 2-й строки.
Приготовьте рабочие программы и листинги с задачами этой темы.
СТРОКИ
Занятие 1. Тип данных char. Операции над символами
В большинстве применений компьютера алфавитно-цифровая информация используется наряду с числовой
информацией. Прежде чем мы сможем написать программу, которая манипулирует алфавитно-цифровыми знаками
(литерами), нам потребуется тип данных для их представления. для этих целей в языке Паскаль предусмотрен тип данных
char.
Так же, как переменная типа integer может хранить одно целое число, переменная типа char может хранить один символ.
Например,
Var
Alpha : char;
Begin
Alpha :='p'
Alpha :='+'
Alpha :='3'
Alpha :=' '
Alpha :=''''
Первый оператор присваивания записывает в переменную Alpha литеру р.
Второй делает Alpha равной литере плюса (+).
110
Третий делает Alpha равной символу 3. Заметим, что чисвол 3 отличается от целого числа 3 тем, что она не может быть
использована в арифметических операциях.
Четвертый оператор присваивания делает Alpha равной литере пробела. Хотя литера пробела при печати не
изображается, она является обыкновенным значением типа char.
Последний оператор присваивания делает Alpha равной литере апострофа, это специальный случай, так как знак
апострофа используется для ограничения значения типа char.
Мы будем пользоваться множеством литер, находящимся в таблице кодов, называемой ASCII – американский
стандартный код обмена информацией.
Все символы упорядочены, т.к. имеют свой личный номер. Важно, что соблюдаются следующие отношения:
'A' < 'B' < 'C' < ... < 'X' < 'Y' < 'Z'
'0' < '1' < '2' < ... < '7' < '8' < '9'
Для проверки равенства или неравенства переменных типа char могут использоваться операторы булевого
сравнения.
Задача. Написать программу, которая считывает две литеры и печатает больше, равна или меньше первая литера
второй.
Program Sravnenie;
Var
First, Second : char;
Begin
write ('Введите две литеры через пробел ');
readln (First, Second);
write ('Первая литера ');
if First > Second
then
write ('больше второй. ');
else
if First = Second
then
write ('равна второй. ');
else
write ('меньше второй. ');
Еnd.
Так как char – порядковый тип, то к его значениям применимы следующие функции.
Succ – возвращает следующий символ литерного множества;
Pred – возвращает предыдущий символ литерного множества;
Ord – возвращает значение кода литеры;
Chr – возвращает значение литеры, является обратной по отношению к функции Ord.
Например,
Succ('0')='1' – символ, следующий за символом 0, равен символу 1.
Pred('3')='2' – символ, предшествующий символу 3, равен 2;
Chr(65)='A' – символ, соответствующий коду 65, равен А;
Ord('A')=65 – код символа А равен 65
Задачи для самостоятельного решения
1. Вывести в одну строку АаБбВвГг.
2. Запросите у пользователя символ и выведите на экран 5 символов, следующих за ним в таблице американских
стандартных кодов обмена информацией. Проверьте, есть ли среди них знаки препинания.
3. Запросите у пользователя символ и выведите на экран 5 символов, предшествующих данному в таблице американских
стандартных кодов обмена информацией. Проверьте, есть ли среди них знаки простейших математических действий.
4. Определите выведите на экран коды русских заглавных букв и латинских прописных.
5. Определите и выведите на экран коды русских прописных букв и латинских заглавных.
6. Вывести в одну строку ZYY...AA...A.
7. Составьте программу, проверяющую, является ли введенный символ буквой латинского алфавита или скобкой (учесть
круглые, фигурные и квадратные скобки)
8. Запросите у пользователя несколько символов и выведите на экран их коды. Проверьте, являются ли они буквами.
9. Вывести в одну строку ABBCCCDDDD...ZZ...Z.
10. Вывести треугольник
Аяяяяяяяя…я
Бюююю…ю
Вээээээ…э
...
Эввв
Юбб
Яа.
11. Вывести треугольник
111
A B C ...Y Z
B C …Y Z
C ...Y Z
Занятие 2. Строка. Тип данных string. Строковые переменные, их описание. Длина строки.
Операции над строками
Строка (string) – это последовательность литер. Литерные строки уже использовались нами в качестве аргументов
операторa write при изучении темы "Ввод-вывод". Теперь познакомимся с ними подробнее.
Тип данных (string) определяет строки с максимальной длиной 255 символов. Переменная этого типа может принимать
значения переменной длины.
Например,
MaxLine : string;
City : string[30]
Строковая переменная может иметь атрибут длины, определяющий ее максимальную длину.
Текущая длина строковой переменной может быть определена с помощью встроенной функции Length. для заданного
значения типа string эта функция возвращает целое значение, показывающее количество литер в строке.
Выражения, в которых операндами служат строки, называются строковыми выражениями.
Над строками определены две операции:
1. Операция сцепления (+) применяется для сцепления нескольких строк в одну.
Например,
SumStr := 'Турбо'+'Паскаль'+'7.0'
2. Операции отношения (=, <>, >, <, >=, <=) проводят сравнение двух строк слева направо до первого несовпадающего
символа, и та строка считается больше, в которой первый несовпадающий символ имеет больший номер в стандартной
таблице обмена информацией. Результат выполнения операций отношения над строками всегда имеет булевой тип.
Например, выражение 'MS-DOS'<'MS-Dos' имеет значение True
Если строки имеют различную длину, но в общей части символы совпадают, считается, что более короткая строка
меньше, чем более длинная.
Строки считаются равными, если они совпадают по длине и содержат одни и те же символы на соответствующих местах
в строке.
Для присваивания строковой переменной результата строкового выражения используется оператор присваивания. Если
значение переменной после выполнения оператора присваивания превышает по длине максимально допустимую при
описании величину, то все лишние символы справа отбрасываются.
Допускается смешение в одном выражении операндов строкового и символьного типа.
К отдельным символам строки можно обратиться по номеру (индексу) данного символа в строке.
Например, чтобы обратиться к третьему символу строки SumStr надо записать SumStr[3]. Запись SumStr[0] дает
значение текущей длины строки.
Для эффективного программирования алгоритмов обработки текстов необходимо хорошо понимать внутреннюю
структуру представления строк в памяти. Строки реализованы достаточно просто. Для хранения строковых переменных
выделяется память, на единицу большая максимальной длины строки. Начальный байт этой памяти отводится для хранения
текущей длины строки, следующие байты - для символов самой строки. Так как элементы строк стандартно нумеруются
целыми числами, начиная с единицы, байт с длиной строки можно считать нулевым ее элементом. Такая структура памяти
допускает прямой доступ к ее элементам.
Длина
строки0
Stroka
14
1
М
2
А
3
М
4
А
5
__
6
М
7
Ы
8
Л
9
А
10
__
11
Р
12
А
13
М
14
У
15
Индексы
символов
16 17 18
19 20
строки
П У С Т Ы Е ЯЧЕЙКИ
Stroka[4]
Важно отметить, что имеется возможность динамически управлять текущей длиной строки. Следующая программа
показывает автоматическое изменение длины строки после тех или иных операций с нею. Обратите внимание, что общий
(определяемый с помощью стандартной функции SizeOf) размер памяти, отведенной для хранения строки все время остается
неизменным.
Program StringLength;
Var
S : string;
{макс. длина строки = 255}
Begin
S:='';
{пустая строка}
writeln (S,' ',SizeOf(S),' ',Length(S));
{размер=256, длина=0}
S:='Пример длинной строки';
{присваиваем строке некоторое значение}
writeln (S,' ',SizeOf(S),' ',Length(S));
{размер=256, длина=21}
Delete(S,7,8);
{удаляем из строки 8 символов, начиная с 7}
112
writeln (S,' ',SizeOf(S),' ',Length(S));
S:=S+' символов';
writeln (S,' ',SizeOf(S),' ',Length(S));
End.
{размер=256, длина=13}
{добавляем к строке строку}
{размер=256, длина=22}
Внимание! При решении задач со строковыми переменными Вы можете столкнуться с распространенной
трудноуловимой ошибкой, когда после присваивания некоторым элементам строки символов ни содержимое, ни длина
строки не изменяются. Разберемся, с чем это связано.
Очень важно понимать, что при доступе к некоторому элементу строки значение ее текущей длины не проверяется.
Это иллюстрирует следующая программа:
Program StringElements;
Var
S : string;
{макс. длина строки = 255}
Begin
S:='ABCD';
{инициализация строки}
writeln (S,' ',Length(S));
{вывод строки и ее длины}
S[5] := 'E';
{присваивание элементу строки}
writeln (S,' ',Length(S));
{ни сама строка, ни ее длина не изменились}
End.
Присваивание пятому элементу строки некоторого значения не изменяет длину строки, что подтверждает вывод на
экран ее содержимого и длины (конечно само присваивание реально произошло, но на значение текущей длины строки в
нулевом байте это никакого влияния не оказало). Работа с элементами строки без учета ее текущей длины и является
ошибкой программиста. Посмотрите следующую программу:
Program StringElements2;
Var
Str : string[26];
{длина строки = 26}
i : integer;
Begin
Str:='A';
for i := 1 to 26 do
Str[i] := Chr (Ord('A')+i-1);
writeln(Str);
End.
Предполагается, что данная программа должна сформировать строку из 26 символов, содержимым которой является
последовательность заглавных букв латинского алфавита. Однако вызов процедуры writeln показывает, что содержимым
переменной Str будет строка из одного символа 'А'. Природа совершенной ошибки заключается в том, что присваивание
значений элементам строки не влияет не текущую длину, которая была установлена равной 1 при первом присваивании.
Поэтому правильной будет следующая программа:
Program stringElements3;
Var
Str : string[26];
{длина строки = 26}
i : integer;
Begin
S:='';
for i := 'A' to 'Z' do
Str := Str + i;
writeln(Str);
End.
Операция конкатенации, как и все стандартные операции, работающие со строками, в отличие от поэлементного
присваивания, изменяет длину строки, что дает корректный результат. Кроме того, вторая программа работает
непосредственно с символами букв. Наконец, не следует забывать инициализировать строку перед ее заполнением (первый
оператор программы). В противном случае, так как начальная длина строки является неопределенной, можно получить
произвольный результат; не стоит рассчитывать на то, что в нулевом байте стоит ноль.
Для обработки строковых данных можно использовать встроенные процедуры и функции:
1. Delete (Str,Poz,N) – удаление N символов строки Str, начиная с позиции Poz.
2. Insert (What,Where,Poz) – вставка строки What в строку Where, начиная с позиции Poz.
3. Copy (Str,Poz,Nstr) – выделяет строку длиной Nstr, начиная с позиции Poz, из строки Str.
4. Concat (Str1,Str2,...,StrN) – выполняет сцепление строк в том порядке, в каком указаны в списке параметров.
5. Poz (What,Where) – обнаруживает первое появление подстроки What в строке Where.
6. UpCase (Ch) – преобразует строчную букву в прописную.
7. Str (Number,Stroka) – преобразует число в строку.
8. Val (Stroka,Number,Code) – преобразует строку в число и выдает код правильности преобразования.
Задачи для самостоятельного решения
1. Запросите у пользователя числа, преобразуйте их в строки, произведите их сцепление в разных сочетаниях и вывод на
экран. Не забудьте поставить между строками пробел, в конце точку и начать с заглавной буквы.
113
2. Запросите у пользователя несколько строк и выведите на экран их длину, результат конкатенации в некотором
порядке и произведите проверку, можно ли преобразовать эти строки в числа.
3. Запросите у пользователя строку, состоящую из 5 символов, и проверьте является ли она примером, складывающим
два однозначных числа, каждое из которых меньше пяти; если является, то вычислите его.
4. Запросите у пользователя строку, состоящую из нескольких слов, разделенных пробелом, и выведите ее на экран так,
чтобы каждое слово начиналось с новой строки.
5. Запросите у пользователя две строки и сравните их длину, первый и последний символ каждой строки, а также
выведите на экран эти строки с заглавной буквы.
6. Напишите алгоритм, проверяющий, является ли частью данного слова слово "сок". Если ответ отрицательный, то
добавьте к введенному слову слово "нет" в начало и конец. Если ответ "да", то проверьте, не является ли оно словом «сокол».
7. Задайте пользователю вопрос, требующий однозначного ответа. Проверьте его правильность. Дайте пользователю
несколько подсказок и попыток. Если он угадал, то спросите его имя, и выведите на экран поздравление, являющееся
конкатенацией нескольких строк, дважды употребив его имя.
8. Запросите у пользователя строку и символ и выведите на экран сообщение, имеется ли среди символов строки
заданный пользователем символ. Если – нет, то добавьте в его строку этот символ по выбору: в начало или в конец строки.
9. Загадайте пользователю детскую загадку. Дайте ему возможность трижды попробовать отгадать Вашу загадку.
Сопровождайте работу программы диалогом с пользователем. Примените конкатенацию введенных строк.
10. Заставьте компьютер случайным образом загадать букву латинского (русского) алфавита. Предложите пользователю
отгадать загаданную букву, помогая ему следующим образом. Если в очередной попытке пользователем введена буква,
стоящая ближе к загаданной, чем предыдущая, то выводите пользователю сообщение "Горячее!", а если дальше –
"Холоднее!".
11. Заставьте компьютер случайным образом загадать букву латинского (русского) алфавита. Предложите пользователю
отгадать загаданную букву, помогая ему следующим образом. Если пользователем введена буква, стоящая слева от
загаданной, то выводите пользователю сообщение "Правее!", а если справа – "Левее!".
Задачи для дополнительного решения (на усмотрение учителя)
1. Выясните, какая из букв (первая или последняя) встречается в заданном слове чаще.
2. Сколько букв "у" в слове стоит на четных местах?
3. В тексте, состоящем из латинских букв и заканчивающемся точкой, подсчитайте количество гласных букв.
5. Вычеркните i-ую букву слова.
6. Вычеркните из слова Х те буквы, которые встречаются в слове Z.
7. Напишите программу, которая вводит строку и выводит ее, сокращая каждый раз на 1 символ до тех пор, пока в
строке не останется 1 символ.
Занятие 3. Стандартные функции для работы со строками (concat,copy,length, pos,upcase).
Функция Length
Встроенная функция Length (длина) позволяет определить фактическую длину текстовой строки, хранящейся в
указанной переменной (а не величину предельного размера строки, установленную при декларации):
Program DemoFunctionLength;
Var
Word : string;
Begin
write ('Введите слово :');
readln(Word);
writeln('Это слово состоит из ',Length (Word),' букв');
End.
Примечание. При подсчете фактической длины строки учитываются все входящие в нее символы, в том числе и
пробелы.
Функция Upcase
Функция Upcase позволяет преобразовывать символ любой литеры из строчного в прописной. Эта функция
рассчитана на обработку отдельного символа. Поэтому для обработки строки символов с помощью этой функции приходится
организовывать цикл.
Program DemoFunctionUpcase;
Var
Word : string;
i : Byte;
Begin
Word := 'фирма Microsoft';
for i := 1 to Length (Word) do
Word[i] := UpCase (Word[i]);
writeln(Word); {выводится текст 'фирма MICROSOFT'}
End.
В результате работы программы на терминал выдается строка, содержащая большие английские буквы и маленькие
русские.
114
Примечание. Русские литеры не могут обрабатываться этой функцией.
Для того, чтобы преобразовать в заглавные строчные буквы русского алфавита, применяют оператор выбора Case:
. . .
case Word[i] of
'a' : Word[i] := 'A';
'б' : Word[i] := 'Б';
'в' : Word[i] := 'В';
. . .
end;
. . .
Функция Copy
Функция Copy позволяет копировать фрагмент некоторой строки из одной переменной в другую. Вызывая эту функцию
нужно указать следующие параметры:
• имя строки, из которой должен извлекаться копируемый фрагмент,
• позицию в строке, начиная с которой будет копироваться фрагмент,
• число копируемых символов.
Program DemoFunctionCopy;
Var
Word : string;
Word1 : string[20];
Begin
Word := 'фирма Microsoft';
writeln(Word); {выводится текст 'фирма MICROSOFT'}
Word1 := Copy (Word,1,5);
writeln(Word1); {выводится текст 'фирма'}
End.
Примечание. Если начальная или конечная позиции копируемого текста находятся вне пределов исходной строки
символов, то сообщение об ошибке не выдается. Результатом выполнения операции в первом случае будет строка нулевой
длины, во втором - фрагмент от начальной позиции копирования до конца исходной строки.
Функция Pos
C помощью функции Pos Вы можете осуществить поиск некоторого фрагмента в строке. Если заданный фрагмент в
строке присутствует, то функция возвращает номер позиции, с которой он начинается. Если фрагмент не найден, то функция
возвращает нуль.
Program DemoFunctionPos;
Var
Word : string;
SearchWord : string[20];
Position : Byte;
Begin
Word := 'фирма Microsoft';
writeln(Word); {выводится текст 'фирма MICROSOFT'}
writeln ('Введите искомый текст ');
readln (SearchWord);
Position := Pos(SearchWord, Word);
if Position <> 0
then
begin
write ('Фрагмент <',SearchWord,'> содержится в строке <',Word);
writeln ('>, начиная с позиции ',Position );
end
else
writeln('Фрагмент <',SearchWord,'> не содержится в строке <',Word); End.
Примечание. Функция Pos требует полного совпадения искомого фрагмента и фрагмента строки, в которой
производится поиск. Причем большие и маленькие буквы считаются различными символами.
Функция Concat
Функция Concat (Str1,Str2,...,StrN) выполняет конкатенацию (или сцепление) строк Str1,Str2,...,StrN в том порядке, в
каком они указаны в списке параметров. Сумма символов всех сцепленных строк не должна превышать 255.
Program DemoFunctionConcat;
Var
Word : string;
Word1, Word2 : string[20];
Begin
Word1 := 'фирмы ';
115
Word2 := 'Microsoft';
Word := Concat('Компьютеры ',Word1,Word2);
writeln(Word); {выводится текст 'Компьютеры фирмы Microsoft'}
End.
Задачи для самостоятельного решения
1. Задано существительное 1-го склонения, оканчивающееся на “а”. Проверьте правильность ввода. Напечатайте это
слово во всех падежах. Применяйте подпрограммы.
2. Проверьте правописание “ча” и “ща” в тексте. Выведите на экран количество сделанных ошибок и исправленную
строку. Применяйте подпрограммы.
3. Напишите алгоритм, подсчитывающий, сколько раз в данном слове х встречается данное слово у. Если слово у
длиннее, чем х, то результат должен быть равен нулю. Применяйте подпрограммы.
4. Выясните, сколько раз встречается каждая буква алфавита в предложенном тексте. Применяйте подпрограммы.
5. Запишите строку а в обратном порядке в строку б. Посчитайте, сколько одинаковых букв находятся на одинаковых
местах в этих строках. Применяйте подпрограммы.
6. Заданы фамилия, имя и отчество учащегося, разделенные пробелом. Напечатайте его фамилию и инициалы.
Применяйте подпрограммы.
7. Проверьте правописание “жи” и “ши” в тексте. Выведите на экран количество сделанных ошибок и исправленную
строку. Применяйте подпрограммы.
8. Запросите произвольное предложение и имя. Найдите ошибки употребления имени и исправьте их. Выведите на экран
количество сделанных ошибок и исправленную строку. Применяйте подпрограммы.
9. Посчитайте количество цифр в веденной строке символов. Применяйте подпрограммы.
10. Посчитайте количество букв в введенной строке символов. Применяйте подпрограммы.
11. Запросите несколько символов и строку для выяснения, сколько заданных символов встречается в строке.
Применяйте подпрограммы.
Занятие 4. Стандартные процедуры для работы со строками (delete, insert,str,val).
Процедура Insert
Процедура Insert вставляет в исходную строку, начиная с указанной позиции, какую-либо другую строку. Оператор
Insert (Word1,Word2,5) указывает, строку Word1 необходимо вставить в строку Word2, начиная с 5-ой позиции.
Процедура Delete
Процедура Delete удаляет в исходной строке фрагмент определенной длины, начиная с указанной позиции. Так,
оператор Delete(Word1,2,3) удаляет из указанной строки фрагмент, длиной в три символа, начиная со второго.
Процедура Str
Общий вид Str(Chislo,Stroka)
Процедура Str преобразовывает числовое значение переменной Chislo в строковую переменную Stroka. После первого
параметра может указываться формат, аналогичный формату вывода.
Program DemoProcedureStr;
Var
Word : string;
Chislo : integer;
Begin
Chislo := 1560;
Str(Chislo:8, Word);
writeln(Word); {выводится строка '
1500'}
End.
Процедура Val
Общий вид Val(Stroka,Chislo,Code)
Процедура Val преобразует значение строки Stroka в величину целочисленного или вещественного типа и помещает
результат в Chislo. Значение строковой переменной Stroka не должно содержать пробелов в начале и в конце. Code
целочисленная переменная. Если во время операции преобразования ошибки не обнаружено, значение Code равно нулю,
если же ошибка обнаружена, Code будет содержать номер позиции первого ошибочного символа, а значение Chislo будет не
определено.
Program DemoProcedureVal;
Var
Word : string;
Chislo, Code : integer;
Begin
writeln('Введите строку цифр ');
readln(Word);
116
Val(Word, Chislo, Code); {преобразование строки в число}
if Code <> 0
then
writeln('Ошибка! В позиции ',Code,' не цифра!',);
End.
Задачи для самостоятельного решения
1. Составьте алгоритм приписывания к каждому слову в начало заданной буквы в данной строке. Выведите полученную
строку на экран. Используйте подпрограммы для решения каждой частной задачи.
2. Составьте алгоритм замены в какой-нибудь литерной величине всех букв "а" на буквы "б" и наоборот (при такой
замене, например, из слова "баба" должно получиться слово "абаб"). Выведите полученную строку на экран. Используйте
подпрограммы для решения каждой частной задачи.
3. Составьте алгоритм, утраивающий каждую букву в заданном тексте (при этом, например, из слова "кот" должно
получиться слово "кккоооттт"). Выведите полученную строку на экран. Используйте подпрограммы для решения каждой
частной задачи.
4. Составьте алгоритм, выясняющий, является ли данное слово "перевертышем" (так называются слова, читающиеся
одинаково слева направо и справа налево, например: ПОТОП, КАЗАК). Используйте подпрограммы для решения каждой
частной задачи.
5. Составьте алгоритм, вычеркивающий из данного текста любую букву. Выведите полученную строку на экран. Если
такого символа нет, то выведите соответствующее сообщение. Используйте подпрограммы для решения каждой частной
задачи.
6. Составьте алгоритм, который каждую встреченную в слове букву "б" заменял бы сочетанием букв "ку". Если такого
символа нет, то выведите соответствующее сообщение. Выведите полученную строку на экран. Используйте подпрограммы
для решения каждой частной задачи.
7. Как только в строке встретится символ "*", удалить все символы в строке после "*". Выведите полученную строку на
экран. Если такого символа нет, то выведите соответствующее сообщение. Используйте подпрограммы для решения каждой
частной задачи.
8. Вставить в строку слово по условию:
а) в конец строки
б) в начало строки
в) после первого слова.
Выведите полученную строку на экран. Используйте подпрограммы для решения каждой частной задачи.
9. В строке удалить все буквы "б","с","д",".". Если такого символа нет, то выведите соответствующее сообщение.
Выведите полученную строку на экран. Используйте подпрограммы для решения каждой частной задачи.
10. Все слова, в которых буква “а” встречается более 2х раз, удалить из текста. Выведите полученную строку на экран.
Если такого символа нет, то выведите соответствующее сообщение. Используйте подпрограммы для решения каждой
частной задачи.
11. Из строки удалить среднюю букву, если длина строки нечетная, иначе - удалить две средние буквы. Выведите
полученную строку на экран. Используйте подпрограммы для решения каждой частной задачи.
Задачи для дополнительного решения (на усмотрение учителя)
1. Составьте программу вычисления суммы мест, на которых в слове Х стоят буквы "в" и "п".
2. Дана строка символов. Дано слово. Удалить из строки это слово.
3. Дана строка символов. Выделить подстроку между первой и второй точкой.
4. Дана строка символов до точки. Группы символов в ней между группами пробелов считаются словами. Определить,
сколько слов начинается и кончается одной и той же буквой.
5. Дана строка символов до точки. Группы символов в ней между группами пробелов считаются словами. Определить,
сколько слов содержат хотя бы одну букву "е".
Занятие 5. Контрольная работа
Вариант 1
1. Результатом вычисления функции Copy('программирование',4,5) будет слово
a) миров
b) грамм
c) программ
d) программа
e) грамми
2. Результатом работы программы:
Var x : string[6];
Begin
x := ‘мим’+’озадаченный’; writeln(x);
End.
будет слово:
117
a) мим озадаченный
b) мимозадаченный
c) мимоза
d) озадаченный мим
e) озадаченныймим
3. Составьте подпрограмму для решения задачи:
Выясните, какая из букв (первая или последняя) встречается в заданном слове чаще.
Вариант 1I
1. Результатом работы программы:
Program DemoUpcase;
Var
Word : string;
i : Byte;
Begin
Word := 'фирма Microsoft';
for i := 1 to Length (Word) do
Word[i] := UpCase (Word[i]);
writeln(Word); {выводится текст 'фирма MICROSOFT'}
End.
будет предложение:
a) 'Фирма MICROSOFT'
b) 'ФИРМА MICROSOFT'
c) 'фирма Microsoft
d) 'фирма MICROSOFT'
e) 'фирма microsoft
2. Вызывая функцию Copy не нужно указывать:
a) •имя строки, из которой должен извлекаться копируемый фрагмент,
b) •позицию в строке, начиная с которой будет копироваться фрагмент,
c) •число копируемых символов;
d) имя строки, в которую копируется данный фрагмент
e) имя функции.
3. Составьте подпрограмму для решения задачи:
Сколько букв "у" в слове стоит на четных местах?
Вариант III
1. Результатом работы программы:
Program DemoFunctionLength;
Var
Word : string[9];
Begin
Word := 'Я люблю программировать';
writeln(Length (Word));
End.
будет:
a)
9
b)
23
c)
'Я люблю программировать'
d)
'Я люблю '
e)
256
2. Результатом работы программы:
Program DemoFunctionPos;
Var
Word : string;
SearchWord : string[20];
Position : Byte;
Begin
Word := 'Карл у Клары украл кораллы. Клара у Карла украла кларнет.';
SearchWord := 'Карл';
Position := Pos(SearchWord, Word);
writeln (Position );
End.
будет:
a)
1 и 37
b)
37
c)
28
118
d)
1
e)
0
3. Составьте подпрограмму для решения задачи:
Вычеркните i-ые буквы текста и посчитайте в нем количество введенных повествовательных предложений.
Вариант 1V
1. Встроенная функция Length позволяет определить: (а не, установленную при декларации):
a) фактическую длину текстовой строки, хранящейся в указанной переменной,
b) величину предельного размера строки,
c) предполагаемую величину строки,
d) начальную длину строки,
e) длину строки, заранее заданную пользователем.
2. Результатом работы программы:
Program DemoFunctionConcat;
Var
Word : string;
Word1, Word2 : string[20];
Begin
Word1 := ' Microsoft ';
Word2 := ' фирмы';
Word := Concat('Компьютеры ',Word1,Word2);
writeln(Word);
End.
будет текст:
a) ' фирмы Компьютеры Microsoft',
b) ' Microsoft Компьютеры фирмы ',
c) 'Компьютеры фирмы Microsoft',
d) 'Компьютеры Microsoft фирмы ',
e) 'Компьютеры Microsoft фирмы '.
3. Составьте подпрограмму для решения задачи:
Вычеркните из слова Х те буквы, которые встречаются в слове Z.
Вариант V
1. При подсчете фактической длины строки
a) учитываются все входящие в нее символы,
b) учитываются все входящие в нее символы, кроме пробелов,
c) учитываются не все входящие в нее символы,
d) учитываются все входящие в нее символы, исключая служебные символы,
e) учитываются все входящие в нее символы, имеющиеся на клавиатуре.
2. Результатом работы программы:
Program DemoProcedureStr;
Var
Word : string;
Chislo : integer;
Begin
Chislo := 1560;
Str(Chislo:8, Word);
writeln(Word);
End.
будет текст:
a) '1500',
b) '
1560',
c) '
1560',
d) 100000000',
e) '00001560'.
3. Составьте подпрограмму для решения задачи:
Напишите программу, которая вводит строку и выводит ее, сокращая каждый раз на 1 символ до тех пор, пока в строке
не останется 1 символ.
Вариант V1
1. C помощью функции Pos Вы можете осуществить поиск некоторого фрагмента в строке. Если заданный фрагмент в
строке присутствует, то:
a) функция возвращает количество фрагментов в строке,
b) функция возвращает нуль,
c) функция вырезает найденный фрагмент из строки,
d) функция заменяет найденный фрагмент на введенный ранее,
e) функция возвращает номер позиции, с которой начинается фрагмент.
119
2. Результатом работы программы:
Program DemoProcedureVal;
Var
Word : string;
Chislo, Code : integer;
Begin
writeln('Введите строку цифр ');
readln(Word);
Val(Word, Chislo, Code); {преобразование строки в число}
if Code <> 0
then
writeln(‘??????????????’);
End.
должно быть следующее сообщение:
a) 'Ошибка! В позиции ',Code,' не ноль!',
b) 'Ошибка! Цифра Code,' не закодирована!',
c) 'Прекрасно! Число в переменной ',Code,' !',
d) 'Ошибка! В позиции ',Code,' не цифра!',
e) 'Прекрасно! Число в переменной ', Chislo,' !'.
3. Составьте подпрограмму для решения задачи:
Составьте программу вычисления суммы мест, на которых в слове Х стоят буквы "в" и "п".
Сформулируйте тексты решенных ниже задач
Примечание. При анализе алгоритмов Вам потребуются знания о некоторых операторах. В будущем применяйте их при
решении задач.
GoTo – оператор, устанавливающий курсор в заданное параметрами знакоместо в текстовом режиме. Первый параметр –
номер столбца, второй – номер строки. Общее количество строк 25, а столбцов – 80.
Delay – оператор задержки вывода на экран информации. Параметр равный 1000 соответствует 1 секунде.
Sound – оператор, включающий динамик компьютера с заданной частотой в виде параметра.
NoSound – оператор, выключающий динамик.
DelLine – оператор, выводящий строку из пробелов в строку, в которой находится курсор.
Window – оператор, организующий окно в текстовом режиме с координатами верхнего левого и правого нижнего углов,
переданными как параметры.
Задача 1.
Program MiskovVadim;
Var
i, k,x : integer;
a, b, c : string;
Begin
write('введите строку>');
readln(a);
k := length(a);
repeat
for i := 1 to 2 do
c:=c+b;
x:=x+1;
b:=Copy(a,x,1);
until x=k+1;
writeln ('Ваше слово - ',s);
End.
Задача 2.
Program AlexeyDashkin;
Type
Stroka = string [100];
Var
Vhod, St1, InStr : Stroka;
Begin
St1 := '
Поставьте мне пятерку в зачетку!!!!';
ClrScr;
InStr := ' ';
St1:= St1+InStr;
for i := 1 to length(St1) do
begin
Delete(St1,1,1);
120
GoTo(1,10);
write(St1);
Delay(500);
Sound(1000);
Delay(900);
NoSound;
DelLine;
end;
End.
Задача 3.
Program AkulovE;
Var
y,i : integer;
Name, Bukva : string;
Begin
write ('Введите что-нибудь ');
read (Name);
for i := Length(Name) downto 1 do
begin
Bukva := Name[i];
Delete(name,i,1);
for y := 1 to 25 do
begin
Window(19,1,80,25);
GotoXY(i,y);
write(Bukva);
Delay(500);
ClrScr;
write(Name);
end;
end;
End.
Выберите с учителем задачи для самостоятельного решения:
1. Дана строка текста. В данной строке поменять местами каждые два слова из четырех первых. Если количество слов
меньше заданного, то вывести об этом сообщение.
2. В заданном тексте найти и распечатать слово максимальной длины.
3. Написать (в порядке появления в тексте) все слова, длина которых попадает в интервал [X, Y]. Здесь X и Y целые
числа, задающиеся пользователем.
4. В данном предложении найти количество слов, содержащих удвоенную согласную (буквы латинские). Слова в
предложении разделяются пробелами, в конце предложения - точка.
5. Предложите пользователю ввести дату в предложенном формате ДД-ММ-ГГ. День и месяц могут быть указаны
одиночными числами, т.е. 1-5-94, а не 01-05-94. Выделите числа представляющие день, месяц и год, и выведите каждое
число с соответствующей поясняющей надписью на экран.
6. Предложите пользователю ввести число в интервале от 1 до 5 включительно. Ваша программа должна позволять
пользователю вводить любую последовательность символов. Организуйте проверку ввода, и если ввод не длиннее одного
символа, либо нецифровой, либо не попадает в допустимый интервал, тогда выведите сообщение об ошибке. Если ввод
неправилен, тогда предложите пользователю повторить попытку.
7. Даны два текста А и Б. Проверьте, можно ли из букв, входящих в А, составить Б. (Буквы можно переставлять, но
каждую букву можно использовать не более одного раза).
8. В строке, любое количество подряд следующих пробелов замените единственным пробелом.
9. Вычислите длину самого короткого слова в предложении из трех слов, разделенных пробелами.
10. Написать (в порядке появления в тексте) все слова, длина которых попадает в интервал [X, Y]. Здесь X и Y целые
числа, указывающие, соответственно, наибольшую и наименьшую длину
11. Составьте программу, вычеркивающую каждую третью букву слова Х в заданном предложении.
Занятие 6. Решение задач.
Выберите задачи для самостоятельного решения в соответствии со соим порядковым номером в журнале.
1. В тексте содержащем, несколько (много) предложений, найти все вхождения заданного слова и распечатать все
включающие его предложения. Принять, что каждое предложение заканчивается точкой.
2. Дана строка символов до точки. Группы символов в ней между группами пробелов считаются словами. Определить,
сколько слов содержат ровно 3 буквы "е".
121
3. Дан текст, состоящий из нескольких предложений. В каждом предложении найти самое короткое и самое длинное
слова.
4. Дан текст. Посчитать количество слов в тексте.
5 Дан текст. Посчитать количество слов, заканчивающихся на заданную букву и перенести их в другую строку, написав
через запятую. Вывести полученную строку на экран.
6. Даны 2 текста. Найти одно из общих слов, встречающихся в текстах.
7. Напишите программу, изменяющую порядок слов в строке по Вашему алгоритму.
8. Для каждого слова заданного предложения указать долю согласных. Определить слово в котором доля согласных
максимальна.
9. Составьте программу шифрования текстового сообщения. Можно использовать такой способ шифровки.
Шифровальщик задает ключ шифровки - целое число, которое определяет величину смещения букв русского алфавита,
например ключ =3, тогда в тексте буква “а” заменяется на “г” и т.д. Используются все буквы русского алфавита.
10. В заданном предложении удалите каждое второе слово, а оставшиеся слова переверните. (Например, из текста “А
роза упала на лапу азора” должен получиться текст “азор ан ароза”).
11. Составьте программу дешифрования текстового сообщения, зашифрованного программой задачи № 9.
В заданном предложении указать слово, в котором доля гласных (A, E, I, O) максимальна. Слова удобно хранить в
строковом массиве.
Задание. Приготовьте для проверки учителем все Ваши листинги и файлы с решенными и оцененными задачами по
данной теме.
Для увлеченных программированием. Бегущая строка. Пример программы осыпающихся букв. Строки в графическом
режиме.
Задание. Перед Вами две программы. Рассмотрите операторы, какова их роль?
Program AlexeyDashkin;
Uses
Crt;
Type
Stroka = string [100];
Var
Vhod, St1, InStr : Stroka;
Begin
St1 := '
Поставьте мне пятерку в зачетку!!!!';
ClrScr;
InStr := ' ';
St1:= St1+InStr;
for i := 1 to length(St1) do
begin
Delete(St1,1,1);
GoTo(1,10);
write(St1);
Delay(5);
Sound(1000);
Delay(90);
NoSound;
DelLine;
end;
End.
Program AkulovE;
Uses
Crt;
Var
y,i : integer;
Name, Bukva : string;
Begin
ClrScr;
write ('Введите что-нибудь ');
read (Name);
for i := Length(Name) downto 1 do
begin
Bukva := Name[i];
Delete(name,i,1);
for y := 1 to 25 do
begin
122
Window(19,1,80,25);
GotoXY(i,y);
write(Bukva);
Delay(50);
ClrScr;
write(Name);
end;
end;
End.
Задание.
1) Наберите программы на компьютере. Проверьте их работу.
2) Усовершенствуйте одну из программ, дополните ее комментариями. Покажите результат работы учителю для оценки.
3) Решите одну из задач в графическом режиме. Покажите результат работы учителю для оценки.
123
МНОЖЕСТВА
Занятие 1. Множественный тип данных. Множество. Элемент множества. Способы задания
множества. Объединение множеств. Разность множеств. Пересечение множеств.
Множественный тип данных напоминает перечислимый тип данных. Вместе с тем, множество – набор элементов, не
организованных в порядке следования. В математике множество – любая совокупность элементов произвольной природы.
Понятие множества в программировании значительно уже математического понятия.
Определение. Под множеством в Паскале понимается конечная совокупность элементов, принадлежащих некоторому
базовому типу.
В качестве базовых типов могут использоваться: перечислимые типы данных, символьный и байтовый типы или
диапазонные типы на их основе.
Такие ограничения связаны с формой представления множества в языке и могут быть сведены к тому, что функция Ord
для используемого базового типа должна быть в пределах от 0 до 255.
Множество имеет зарезервированное слово set of и вводится следующим описанием
Type
< имя типа > = set of < имя базового типа >;
Var
< идентификатор,... >:< имя типа >;
Рассмотрите примеры описания множеств:
Type
SetByte = set of byte; {множество 1, определённое над типом byte}
SetChisla = set of 10 ... 20; {множество 2, определённое в диапазоне от 10 до 20
Symbol = set of char; {множество, определённое на множестве символов}
Month = (January, February, March, April, May, June, July, August, September, October, November, December);
Season : set of Month; {тип множества, определённый на базе перечислимого типа Month}
Var
Letter, Digits, Sign : Symbol {множествa, определённые над символьным типом}
Winter, Spring, Summer, Autumn, Vacation, WarmSeason : Season;
Index : SetChisla=[12, 15, 17];
Operation : set of (Plus, Minus, Mult, Divid);
Param : set of 0..9=[0, 2, 4, 6, 8];
Для переменных типа множества в памяти отводится по 1 биту под каждое возможное значение базового типа. Так, под
переменные Letter, Digits, Sign будет отведено по 256/8=32 байта. Для переменной Winter, базовый тип которой (Month)
имеет 12 элементов, необходимо 2 байта, причем второй используется только наполовину. Если множество содержит какойто элемент, то связанный с ним бит имеет значение 1, если нет – 0.
Для того, чтобы дать переменной множества какое-то значение, используют либо конструктор множества –
перечисление элементов множества через запятую в квадратных скобках
Sign:=['+', '–'];
Spring:=[March, April, May];
b:=[ 'k', 'l', 'd' ]
либо определение через диапазон. Тогда в множество включены все элементы диапазона
Digits:=['0'..'9'];
WarmSeason := [May .. September];
Обратите внимание, что в определении множества Digits использованы символы в таблице ASCII-кодов, а не целые
числа.
Обе формы конструирования могут сочетаться:
Vacation:=[January, February, June .. August];
В программах множества часто используются как константы, в этом случае их можно определить следующим образом:
{постоянное множество допустимых символов
Const
YesOrNo = ['Y', 'y', 'N', 'n'];
{множества – типизированные константы}
Const
Digits : set of char=['0'..'9'];
DigitsAndLetter : set of char=['0'..'9', 'a'..'z', 'A'..'Z'];
124
{применение операции "+" для объявления множества-константы}
Const
Yes = ['Y', 'y'];
No = ['N', 'n'];
YesOrNo = Yes+No;
Объединение множеств (+)
Определение. Объединением 2-х множеств называется третье множество, которое содержит элементы, которые
принадлежат хотя бы одному из множеств операндов, при этом каждый элемент входит в множество только один раз.
3
1
7
3
2
1
5
9
4
5
M1
7
9
10
M2
2
3
5
4
10
M 1+ M 2
Объедине
ние множеств записывается как операция сложения.
Type
Symbol = set of char;
Var
SmallLatinLetter, CapitalLatinLetter, LatinLetter : Symbol;
Begin
......
SmallLatinLetter :=['a'..'z'];
CapitalLatinLetter := ['A'..'Z'];
LatinLetter := SmallLatinLetter+CapitalLatinLetter;
......
End.
В операции объединения множеств могут участвовать и отдельные элементы множества.
Например, допустима следующая запись, где два элемента и множество объединяются в новое множество:
WarmSeason := May+Summer+September;
или другая запись
B: = B+['c'],
которую можно применить для организации множества в цикле, если заменить множество ['c'] переменной Sim того же
типа, что и множество B, и считывать с клавиатуры данные в переменную Sim, а затем объединяя с множеством В.
B: = B+Sim,
Разность множеств (-)
Определение. Разностью 2-х множеств является третье множество, которое содержит элементы 1-го множества, не
входящие во 2-е множество.
a: = a–[ 'd' ]
3
1
7
2
3
1
5
9
4
5
M1
7
9
10
M2
4
M 1– M 2
вычитаемом множестве есть элементы, отсутствующие в уменьшаемом, они не влияют на результат.
Summer := WarmSeason–Spring–Autumn;
Summer := WarmSeason–May–September;
Модуль System содержит процедуры для включения элемента в множество
Include(Var S : set of T; Element : T);
и исключения из множества
125
2
3
5
10
Если
в
Exclude(Var S : set of T; Element : T);
где S – множество элементов типа Т, а Element – включаемый элемент.
Эти функции отличаются от операций объединения и вычитания множеств только скоростью исполнения.
Пересечение множеств
Определение. Пересечением множеств называется множество, содержащее элементы одновременно входящие в оба
множества операндов. Операция обозначается знаком умножения.
Summer := WarmSeason*Vacation;
3
1
7
2
3
1
5
9
4
5
M1
7
9
10
M2
2
3
5
4
10
M1 * M2
Задание.
В своей тетради опишите множества М1 и М2 произвольным образом. Получите результирующие множества (запишите
какие элементы будут содержать эти множества).
а) М3=М1+М2;
б) М3=М1*М2;
в) М3=М1-М2.
Занятие 2. Логические операции над множествами: проверка принадлежности элемента
множеству, проверка включения элемента в множество, сравнение множеств.
Сравнение множеств
Определение. Множества считаются равными, если все элементы, содержащиеся в одном множестве присутствуют в
другом, и наоборот.
В соответствии с этим правилом определяется результат логических операций "=" и "<>".
Например,
If WarmSeason*Vacation=Summer
Then
Writeln ('Правильно');
Задание. Сравните множества М1 и М2, пользуясь рисунками. Результаты сравнения запишите в тетрадь.
M1
M2
а)
‡)
M2
M1
б)·)
M2
M1
в) ‚)
Проверка включения
Определение. Одно множество считается входящим в другое, если все элементы содержатся во втором, при этом
обратное в общем случае может быть несправедливо.
Логические операции проверки вхождения одного множества в другое записываются через операции больше или
равно:
if S1<=S2
then
writeln ('S1 входит в S2');
if S1>=S2
then
writeln ('S2 входит в S1');
126
Задание. Что напечатает оператор Write в каждом из случаев:
1. if Vacation>=Summer
then
writeln ('Правильно')
else
writeln ('Неправильно')
2. if Vacation<=Summer
then
writeln ('Правильно')
else
writeln ('Неправильно')
Проверка принадлежности
Логическая операция проверки принадлежности элемента множеству записывается через оператор in.
Например, выражение
May in WarmSeason
имеет значение True.
Использование множеств и операции in позволяет, в частности, сделать эффективнее проверку правильности вводимых
символов.
Например, для проверки допустимости введенного символа можно использовать следующее условие:
(Reply='y') or (Reply='Y') or (Reply='n') or (Reply='N')
Но если ввести множество
Const
AllowSymbol : set of char = ['Y', 'y', 'N', 'n'];
проверяемое условие можно записать в более компактной форме:
Reply in AllowSymbol
Примечание. Множественный тип данных не может быть использован для определения функции.
Рассмотрите пример.
Задача. Описать множество М(1..50). Сделать его пустым. Вводя целые числа с клавиатуры, заполнить множество 10
элементами.
В разделе описания переменных опишем множество целых чисел от 1 до 50, переменную Х целого типа будем
использовать для считывания числа-кандидата в множество, целую переменную i используем для подсчета количества
введенных чисел.
В начале программы применим операцию инициализации множества М:=[ ], так как оно не имеет элементов и является
пустым.
Заполнение множества элементами произведем с использованием оператора цикла Repeat, параметр которого i будет
указывать порядковый номер вводимого элемента. Операцию заполнения множества запишем оператором присваивания
М:=M+[X]. Контроль заполнения множества запишем с использованием операции проверки принадлежности in. Если
условие X in M выполняется, выведем сообщение о том, что число Х помещено в множество.
Текст программы описания и заполнения множества будет таким:
Program InputMno;
Var
M : set of 1..50;
X, i : integer;
Begin
M := [ ];
i :=1;
repeat
write('Введите ',i,'-й элемент множества');
readln(X);
if (X in M)
then
begin
write(Х, ' уже содержится в множестве');
i := i-1;
127
end
else
begin
write(Х, ' помещен в множество');
M := M+[X];
end;
i := i+1;
until i>10;
End.
Задание. Наберите рассмотренную программу, откомпилируйте ее. Проверьте работу программы, исполняя ее по шагам
и наблюдая текущие значения переменных i, X, M в окне просмотра. Попробуйте задать значения числа большие 50,
повторно задавать одинаковые значения Х и анализируйте значения множества М. Дополните программу выводом на экран
содержимого полученного множества, сопровождая соответствующим сообщением. Откомпилируйте программу. Покажите
учителю рабочую программу и ее листинг для оценки.
Задание. В своей тетради выполните упражнения, выбрав их с учителем из предложенных ниже:
1. Опишите множества М1(1, 2) и М2(2, 1). Сравните эти множества на равенство.
2. Опишите множества М1('a', 'b') и М2('b', 'a', 'c'). Сравните эти множества на неравенство.
3. Опишите множества М1('a', 'b', 'c') и М2('a', 'c'). Сравните эти множества по операции >=.
4. Опишите множества М1(1, 2, 3) и М2(1, 2, 3, 4). Сравните эти множества по операции <=.
5. Опишите множества М1(1, 2) и М2(5, 6). Получите результирующее множество М3=М1+М2. Определите, имеется ли
в М3 элемент 7.
6. Опишите множества М1(1, 2, 3, 4) и М2(3, 4, 1). Получите результирующее множество М3=М1–М2. Определите,
имеется ли в М3 элемент 2.
5. Опишите множества М1(1, 2, 3) и М2(1, 4, 2, 5). Получите результирующее множество М3=М1*М2. Определите,
имеется ли в М3 элементы 1 и 2.
Занятие 3. Примеры решений задач на применение множества.
Пример 1 Описать множества гласных и согласных букв русского языка, определить количество гласных и согласных
букв в предложении, введенном с клавиатуры.
Зададим тип Letters – множество букв русского языка, затем опишем переменные этого типа: Glasn – множество гласных
букв, Sogl – множество согласных букв. Вводимое с клавиатуры предложение опишем переменной Text типа String. Для
указания символа в строке Text применим переменную i типа byte. Для подсчета количества гласных и согласных букв
опишем переменные G и S. Проверку принадлежности символов, составляющих предложение множествам гласных или
согласных букв русского языка запишем с использованием оператора повтора For, параметр i которого, изменяясь от 1 до
значения длины предложения, будет указывать порядковый номер символа в предложении. Принадлежностьб очередного
символа предложения множеству гласных или согласных букв запишем операцией in. Если выполняется условие Text[i] in
Sogl, тогда увеличивается на 1 счетчик S. Если выполняется условие Text[i] in Glasn, тогда увеличивается на 1 счетчик G.
Если не выполняется ни первое, ни второе условие, значит, очередной символ в предложении не является гласной или
согласной буквой русского языка.
Теперь рассмотрите текст программы:
Program GlasnSogl;
Type
Letters = set of 'A'..'я';
Var
Glasn, Sogl : Letters;
Text : String;
i, G, S : byte;
Begin
Glasn := ['A', 'я', 'Е', 'е', 'И', 'и', 'О', 'о', 'У', 'у', 'Э', 'э', 'Ю', 'ю', 'Я', 'я'];
Sogl := ['Б'..'Д', 'б'..'д', 'Ж', 'ж', 'З', 'з', 'К'..'Н', 'к'..'н', 'П'..'Т', 'п'..'т', 'Ф'..'Щ', 'ф'..'щ', 'ь'];
Write('Введите предложение ');
Readln(Text);
G := 0;
S := 0;
For i := 1 to Length(Text) do
Begin
If Text[i] in Glasn
Then
128
G := G+1;
If Text[i] in Sogl
Then
S := S+1;
End;
Write('В предложении " ', Text, ' " ', G, ' гласных и ', S, ' согласных букв');
End.
Задание. Усовершенствуйте текст решения задачи, дополните комментарием. Если у Вас возникла идея решения этой
задачи с помощью другого алгоритма, – дерзайте. Протестированную программу и листинг покажите учителю для оценки.
Пример 2. Поиск простых чисел с помощью решета Эратосфена в числовом промежутке [1..N].
В теме "Целочисленная арифметика" Вы решали задачи на поиск простых чисел в заданном диапазоне различными
способами. Здесь мы рассмотрим ту же задачу, но применим для ее решения знания, полученные при изучении темы
"Множества".
Примечание. Вспомним, что простым числом называется число, не имеющее делителей, кроме единицы и самого себя.
Идея метода "решета Эратосфена" заключается в следующем: сформируем множество М, в которое поместим все числа
заданного промежутка. Затем последовательно будем удалять из него элементы, кратные 2, 3, 4, и так далее до целой части
числа [N/2], кроме самих этих чисел. После такого "просеивания" в множестве М останутся только простые числа.
Рассмотрите вариант решения этой задачи.
Program Resheto;
Var
M : set of byte;
i, k, N : Integer;
Begin
Writeln('Введите размер промежутка (до 255) ');
Readln(N);
M := [2..N];
For k := 2 to N div 2 do
For i := 2 to N do
If (i mod k=0) and (i<>k)
Then
M := M-[i]
For i := 1 to N do
If i in M
Then
Write(i:3);
Readln;
End.
Ответьте на вопросы:
1. Как сформировано множество М?
2. Как организован просмотр элементов этого множества?
3. Как организован просмотр делителей?
4. Как удаляется элемент множества?
5. Как организован вывод "просеянного" множества?
Если Вы внимательно рассмотрели решение этой задачи и правильно ответили на вопросы, Вы должны были
заметить, что алгоритм решения задачи можно улучшить.
Задание. Улучшите алгоритм решения предложенной задачи. Протестируйте программу, дополните комментариями и
покажите файл и листинг учителю для оценки.
Примечание. Если Вы затрудняетесь при выполнении задания, то вот Вам подсказки:
1. Например, вы знаете, что если из множества М удалить все элементы, делящиеся на 2, то нет смысла проверять,
делятся ли оставшиеся числа на 4, 6, 8, 10, и т.д.
2. Когда программа проверяет делимость, например, на 50, то она проверяет и числа до 50, что не имеет смысла.
Пример 3. Разгадывание ребусов.
+ МУХА
МУХА
СЛОН
129
Каждая буква – это цифра, разным буквам соответствуют разные цифры. Необходимо заменить буквы цифрами так,
чтобы получилось верное равенство. Найти все решения. Для решения этой задачи используется метод перебора с возвратом.
Используем множество S1 для хранения цифр слова МУХА, причем будем вносить в него цифры последовательно, учитывая
уже внесенные цифры. Начальное значение S1 – пустое множество. после выбора всех цифр первого слова создаем его
числовой эквивалент и числовой образ слова СЛОН. Выделяем цифры СЛОНа (множество S2)и если слова состоят из разных
цифр (то есть пересечение S1 и S2 пустое) и все цифры СЛОНа разные (то есть пересечение множеств цифр тоже пустое), то
выводим решение на экран. Если же нет, то идет возврат – удаляем из множества S1 последнюю внесенную цифру и
пытаемся выбрать еще одно значение. Таким образом, мы перебираем все возможные варианты и выводим на экран только
те, которые удовлетворяют равенству.
Заметим, что значение буквы М в слове МУХА может иметь значения от 1 до 4, а буква А в этом же слове не может
быть равна 0.
Рассмотрите решение задачи.
Program Rebus;
Type
MN = set of 0..9;
Var
m, u, h, a : 0..9;
n1, n2 : Integer;
s, l, o, n : 0..9;
S1, S2 : MN;
Procedure Print(x, y : Integer);
Begin
writeln(x:5);
writeln('+');
writeln(x:5);
writeln('
');
writeln(y:5);
End;
Begin
S1 := [ ];
S2 := [ ];
for m := 1 to 4 do
begin
S1 := S1+[m];
for u := 0 to 9 do
if Not(u in S1)
then
begin
S1 := S1+[u];
for h := 0 to 9 do
if Not (h in S1)
then
begin
S1 := S1+[h];
for a := 1 to 9 do
if Not (a in S1)
then
begin
S1 := S1+[a];
n1 := 1000*m+100*u+10*h+a;
n2 := 2*n1;
s := n2 div 1000;
l :=n2 div 100 mod 10;
o := n2 div 10 mod 10;
n := n2 mod 10;
S2 := [s, l, o, n];
if (S1*S2=[ ]) and ([s]*[l]*[o]*[n]=[ ])
then
Print (n1, n2);
S1 := S1–[a];
end;
S1 := S1–[h];
end;
S1 := S1–[u];
end;
130
S1 := S1–[m];
end;
Readln;
End.
Задание. Решите один из ребусов:
1)
ПЧЁЛКА
x
7
ЖЖЖЖЖЖ
2) ТОРГ x Г = ГРОТ
3) ЛАДЬЯ+ЛАДЬЯ = ФЕРЗЬ
4) М3 = КУБ
5) СМ3 = КУБИК
6) МАТЕ * М = АТИКА
7) ПРОП * О = РЦИЯ
8) ПРОП : О = РЦИЯ
9) (М + О + С +К + В + А)4 = МОСКВА
10) ВЕТКА + ВЕТКА = ДЕРЕВО
11) САР = АТОВ
12) ПЛОМБА * 5 = АПЛОМБ
13) НИКЕЛЬ * 6 = ЕЛЬНИК
14) КВАНТ * 30 = ЖУРНАЛ
15) КАПЛЯ + КАПЛЯ + КАПЛЯ + = ОЗЕРКО
16) СОРОК * 5 = ДВЕСТИ
17) SIX * TWO = TWELVE
18) ДВЕСТИ * 5 = ТЫСЯЧА
19) НАТАША + ТОНЯ = СЁСТРЫ
20) БРА2 = БОМДОР
Пример 4. Рассмотрите специальную процедуру ввода положительных целых чисел, которая запрещает набор иных
символов, кроме цифр и ограничивает число используемых символов.
Procedure ReadWord(Var Result : Word; x, y, MaxLength : byte);
Const
ValidSymbol : set of char=['0'..'9',#8,#13];
Var
Str : string;
Code : integer;
Key : char;
Begin
GoToXY(x, y);{курсор – в заданную позицию}
Str := ''; {строка пустая}
repeat {начало бесконечного цикла}
{проверка вводимых символов на допустимость}
repeat
Key := ReadKey
until Key in ValidSymbol;
case Key of {анализ вводимых символов}
'0'..'9' : {нажата цифра}
if Length(Str)>=MaxLength {если длина больше заданной}
then
begin
Sound(100); {звуковой сигнал}
Delay(200);
131
NoSound;
end;
else {если длина меньше заданной}
begin
write(Key);
Str:=Str+Key; {добавление символа в строку}
end;
#8 : {нажата клавиша BackSpace}
if Length(Str)>0 {если строка не пустая}
then
begin
Delete(Str, Length(Str),1); {удаление из строки}
GoToXY(WhereX-1, WhereY); {возврат курсора}
write(''); {запись пробела вместо символа}
GoToXY(WhereX-1, WhereY); {возврат курсора}
end
else {если строка пустая}
begin
Sound(100); {звуковой сигнал}
Delay(200);
NoSound;
end;
#13 : {нажата клавиша Enter}
begin
Val(Str, Result, Code); {преобразование строки в целое число}
Exit {выход из подпрограммы}
end;
end; {конец оператора Case}
until False; {бесконечный цикл}
End;
В заголовке процедуры Result – возвращаемое число; MaxLength – максимальное число цифр в записи числа; х, у –
координаты начальной позиции вывода. Процедура формирует текстовую строку Str, состоящую из цифр. При нажатии
клавиши Enter строка преобразуется в целочисленную переменную.
В начале программы курсор направляется в заданную точку, и текстовой строке присваивается пустое значение. Далее
начинается бесконечный цикл, заданный оператором Repeat ... Until False. Выход из цикла происходит вместе с выходом из
процедуры по команде Exit. "Бесконечность" цикла обеспечивает произвольное число повторов и исправлений при вводе
числа.
Процедура реагирует только на нажатие цифровых клавиш, клавиш Enter и BackSpace. Назначение клавиш –
традиционное: Enter используется для завершения процедуры, BackSpace – для стирания последнего введенного символа.
Цикл
repeat
Key := ReadKey
until Key in ValidSymbol;
проверяет вводимые символы на допустимость. Множество допустимых символов ValidSymbol определено в процедуре
как константа, онон включает цифровые символы и символы, соответствующие клавишам Enter и BackSpace. Первая имеет
символьный код #13, вторая – #8.
Далее оператор Case производит выбор одного из трех направлений – обработка нажатой цифры, обработка клавиши
BackSpace или обработка клавиши Enter. При нажатой цифре сначала проверяют, не достигло ли число цифр максимального
значения. Число цифр определяется функцией Length, аргумент которой – редактируемая строка. Если длина уже достигла
максимального значения, выдается звуковой сигнал. Если длина вводимой строки меньше максимальной, то в строку
дописывается символ, и он же выводится на экран процедурой Write.
При нажатии клавиши BackSpace должен быть стерт последний введенный символ. Вначале производится проверка,
есть ли в строке символы. Если строка пуста, подается звуковой сигнал, если нет – начинается удаление символа. Для этого
строка уменьшается на один элемент процедурой Delete, курсор возвращается назад на одну позицию, на место стираемой
цифры записывается символ пробела, затем курсор снова возвращается на позицию назад. курсор возвращается назад на одну
позицию оператором GoToXY(WhereX-1, WhereY), который использует функции WhereX и WhereY для определения
текущего положения и уменьшает координату х на 1.
После нажатия Enter строка преобразуется в целочисленную переменную процедурой Val и происходит выход из
процедуры ReadWord по команде Exit.
132
В этой процедуре показано, что ввод данных и другие процедуры, связанные с работой оператора, должны, как правило,
иметь защиту от ошибочных действий. В данном примере это обеспечивается тем, что процедура блокирует неправильные
нажатия клавиш и ограничивает длину строки.
Поскольку все проверки усложняют программу, требование защиты от возможных ошибок программиста не является
обязательным. Вопрос в том – надеется ли программист на свою аккуратность при использовании собственных процедур.
Задание*. Составьте программу для проверки входных данных другого типа.
Примечание. Задание не является обязательным для всех учащихся.
Занятие 4. Самостоятельное решение задач.
Итак, коротко обо всем выше сказанном.
В языке Паскаль типом-множеством называется множество всевозможных сочетаний объектов исходного множества.
Число элементов исходного множества не может быть больше 256, а порядковые номера элементов (т.е. значение функции
Ord) должны находиться в пределах от 0 до 255. Для задания типа-множества следует использовать зарезервированные слова
set of , а затем указать элементы этого множества, как правило, в виде перечисления или диапазона.
Введя тип-множество, можно задать переменные или типизированные константы этого типа-множества. При задании
значений константе-множеству ее элементы перечисляются через запятую (допустимо указывать диапазоны) и помещаются в
квадратные скобки.
Множеству можно в программе присвоить то или иное значение. Обычно значение задается с помощью конструктора
множества. Конструктор задает множество элементов с помощью перечисления в квадратных скобках выражений, значения
которых дают элементы этого множества. Допустимо использовать диапазоны элементов.
Например, следующие конструкции являются конструкторами множеств:
[Plus,Minus]
[1..K mod 12, 15]
[Chr(0) .. Chr(31), 'A', 'B']
В каждое множество включается и так называемое пустое множество [ ], не содержащее никаких элементов.
Конструктор множества можно использовать и непосредственно в операциях над множествами.
Для множеств определены следующие операции:
+ –
объединение множеств;
–
–
разность множеств;
*
–
пересечение множеств;
= –
проверка эквивалентности двух множеств;
<> –
проверка неэквивалентности двух множеств;
<= –
проверка, является ли левое множество подмножеством правого множества;
>= –
проверка, является ли правое множество подмножеством левого множества;
in –
проверка, входит ли элемент, указанный слева, в множество, указанное справа.
Результатом операции объединения, разности или пересечения является соответствующее множество, остальные
операции дают результат логического типа.
Выберите с учителем задачи для самостоятельного решения из ниже предложенного списка.
1. Дана непустая последовательность символов. Требуется построить и напечатать множество, элементами которого
являются встречающиеся в последовательности цифры от 1 до 3 и от 17 до 100.
2. Дана непустая последовательность символов. Требуется построить и напечатать множество, элементами которого
являются встречающиеся в последовательности знаки препинания.
3. Дана непустая последовательность символов. Требуется построить и напечатать множество, элементами которого
являются встречающиеся в последовательности буквы от D до I.
4. TYPE natur=1..maxint;
Описать функцию digist(n), подсчитывающую количество различных (значащих) цифр в десятичной записи
натурального числа n.
5. TYPE natur=1..maxint;
133
Описать процедуру print(n), печатающую в возрастающем порядке все цифры не входящие в десятичную запись
натурального числа n.
6. Дана непустая последовательность слов из строчных русских букв; между соседними словами - запятая, за последним
словом - точка. Напечатать в алфавитном порядке все гласные буквы, которые входят в каждое слово.
(Примечание: гласные буквы - а, е, и, о, у, ы, э, ю, я;
согласные - все остальные буквы, кроме й, ъ, ь)
7. Дана непустая последовательность слов из строчных русских букв; между соседними словами - запятая, за последним
словом - точка. Напечатать в алфавитном порядке все согласные буквы которые не входят ни в одно слово.
(Примечание: гласные буквы - а, е, и, о, у, ы, э, ю, я; согласные - все остальные буквы, кроме й, ъ, ь)
8. Дана непустая последовательность слов из строчных русских букв; между соседними словами - запятая, за последним
словом - точка. Напечатать в алфавитном порядке все согласные буквы которые не входят ни в одно слово.
(Примечание: гласные буквы - а, е, и, о, у, ы, э, ю, я; согласные - все остальные буквы, кроме й, ъ, ь)
9. Описать множество гласных и согласных букв русского языка, определить количество гласных и согласных букв в
предложении, введенном с клавиатуры.
10. Опишите множество М(1..50). Сделайте его пустым. Вводя целые числа с клавиатуры, заполните множество 10
элементами.
11. Опишите множество Pr(1..20) и поместите в него все простые числа в диапазоне от а до b.
12. Составьте программу вычисления суммы мест, на которых в слове Х стоят гласные буквы.
13. Подсчитайте число разных букв в слове.
14. Опишите множества Rus и Lat, содержашие русские и латинские буквы. В цикле вводите русские и латинские буквы
и выводите соответствующее сообщение. Выход из цикла – какая-либо клавиша, не являющаяся алфавитно-цифровой.
15. Дан двумерный массив. Найти и напечатать число, которое встречается в каждой строке. Если такого числа нет напечатайте сообщение.
16. Задан целочисленный массив. Подсчитать число различных значений в массиве.
17. Даны две таблицы по 10 элементов в каждой. Найдите наименьшее среди тех чисел первой таблицы, которые не
входят во вторую таблицу (считая, что хотя бы одно такое число есть).
Задание. Приготовьте файлы и листинги решенных задач по этой теме.
Будьте готовы ответить на следующие вопросы:
1. Что такое множество? Каким элементам должны удовлетворять все элементы множества? Преимущества
использования типа множество?
2. Что такое базовый тип множества? Как он задается?
3. Какое множество называется пустым, как оно обозначается?
4. Как задается описание множественного типа?
5. Какие операции допустимы над множествами? Каков тип результатов выражений с применением операций над
множествами?
6. Какие множества считаются равными, неравными? Имеет ли значение для сравниваемых множеств порядок
следования элементов?
7. Для чего применяются операции ">=", "<="? В чем их отличие?
8. Для чего применяется операция in? Особенности ее применения.
9. Что называется объединением множеств?
10. Что называется разностью множеств?
134
ЗАПИСЬ
Занятие 1. Комбинированный тип данных. Запись. Описание записи. Доступ к полям записи.
Оператор With. Примеры решения задач
Довольно часто вполне оправданным является представление некоторых элементов в качестве составных частей другой,
более крупной логической единицы. представляется естественным сгруппировать информацию о номере дома, названии
улицы и городе в единое целое и назвать адресом, а объединенную информацию о дне, месяце и годе рождения – датой. В
языке Паскаль для представления совокупности разнородных данных служит комбинированный тип запись.
Запись и массив схожи в том, что обе эти структуры составлены из ряда отдельных компонент. В то же время, если
компоненты массива должны быть одного типа, записи могут содержать компоненты разных типов.
Приведем пример описания переменной, имеющей структуру записи:
Var
Address : Record
HouseNumber : Integer;
StreetName : String[20];
CityName : String[20];
PeopleName : String;
End;
Отметим, что поля StreetName и CityName имеют одинаковый тип: String[20]. Поскольку в описании эти поля могут
располагаться в любом порядке, то можно сократить описание записи с полями одинакового типа. Сокращенное описание
записи Address выглядит следующим образом:
Var
Address : Record
HouseNumber : Integer;
StreetName, CityName : String[20];
PeopleName : String;
End;
Каждая компонента записи называется полем. В переменной записи Address поле с именем HouseNumber само является
переменной типа Integer, поле StreetName – двадцатисимвольной строкой и т.д.
Для того чтобы обратиться к некоторому полю записи, следует написать имя переменной и имя поля. Эти два
идентификатора должны разделяться точкой.
Оператор, который присваивает полю HouseNumber значение 45, выглядит так:
Address.HouseNumber := 45;
Таким же образом присваиваются значения другим полям записи Address :
Address.StreetName := 'Профсоюзная';
Address.CityName := 'Сургут';
Address.PeopleName := 'Петрова Алла Ивановна';
Каждое поле записи Address можно рассматривать как обычную переменную, которую можно напечатать или
использовать в расчетах. Вместе с тем запись может использоваться как единое целое. В этом случае надо ввести тип записи.
Предположим, имеется следующее описание:
Type
Date = Record
Day : 1..31;
Month : (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Year : Integer;
End;
Var
HisBirth, MyBirth : Date;
После приведенного описания переменные HisBirth и MyBirth имеют тип записи Date. Помимо действий над
отдельными полями записей HisBirth и MyBirth можно выполнять операции над всей записью. Следующий оператор
присваивания устанавливает равенство значений записей HisBirth и MyBirth :
HisBirth := MyBirth;
Это присваивание эквивалентно следующей последовательности операторов:
HisBirth.Day := MyBirth.Day;
HisBirth.Month := MyBirth.Month;
135
HisBirth.Year := MyBirth.Year;
Для переменных одного типа можно проверить выполнение отношения равенства или неравенства ("=", "<>"). После
выполнения приведенных выше присваиваний следующее булево выражение будет иметь значение True:
HisBirth = MyBirth;
Рассмотрите пример описания процедуры, которая получает запись в качестве параметра–значения и печатает дату в
сокращенной стандартной форме, используя формат (MM-DD-YYYY).
Procedure WriteDate(OneDate : Date);
Begin
Write(Ord(OneDate.Month)+1);
Write('-');
Write(OneDate.Day:2);
Write('-');
Write(OneDate.Year:4);
End;
Так как на тип компонент массива не накладывается ограничений, то можно использовать массив, компонентами
которого являются записи. Посмотрите описание такого массива:
Var
Birthdays : Array [1..Persons] of Date;
Чтобы обратиться к некоторому полю определенной записи массива, следует определить имя массива, индекс
интересующей записи и имя необходимого поля.
Например, следующий оператор печатает содержимое поля Year записи Birthdays[3]:
Write(Birthdays[3].Year);
Примечание. Поля записи в свою очередь тоже могут быть массивами, множествами, записями.
Задание. Рассмотрите следующие описания:
Type
Date = Record
Day : 1..31;
Month :1..12;
Year : 1..9999
End;
Reminder = Record
Message : Array [1..5] of String;
Event : Date
End;
Var
Today : Date;
Memos : Array [1..100] of Reminder;
Calendar : Array [1..365] of Date;
Запишите в тетрадь, какой тип, если он определен, у следующих идентификаторов?
а) Today.Year
б) Memos [2]
в) Memos [4].Month
г) Calendar [200]
д) Memos [16].Message[2]
е) Memos [16].Message[1],[2]
ж) Calendar[1].Date
з) Memos [10].Event
Задание. Составьте программу, организующую ввод наиболее полной информации о людях и вывод интересующей
информации на экран.
Приведем описание массива, компоненты которого являются записями:
Var
Payroll : array [1..Workers] of
record
FirstName, LastName : string;
Residence : record
HouseNumber : real;
StreetName, CityName : string;
136
StateName : Array [1..2] char;
ZipCode : integer;
end;
Phone : record
AreaCode, Exchenge : 1..999;
Line : 1..9999;
rnd;
PayScale : 'A' ..'G';
end;
Отметим, что два поля Residence и Phone являются записями. Как выполнить обращение к полям этих записей? Как
распечатать условный шифр рабочего № 7? Поскольку это поле располагается во вложенной записи, то следует указать как
имя самой записи, так и имя записи, в которую данная запись входит.
write (Payroll[7].Residence.ZipCode);
Аналогично приведенное присваивание корректирует шифр рабочего № 23:
Payroll[23].Phone.AreaCode :=804;
Оператор if, представленный ниже, выполняет проверку инициала рабочего № 58:
if Payroll[58].LastName[1] in ['T'..'Z'] Then ...
Соблюдение всех правил перечисления индексов и имен полей при составлении ссылок является довольно
утомительным занятием, часто приводящим к ошибкам. В некоторых программах, содержащих большое количество
обращений к одному и тому же полю, такое положение приводит к однообразному повторению. Чтобы облегчить
выполнение многократных ссылок для описанных структур вводится оператор With (в переводе с английского – предлог "с").
Общая форма записи:
with <имя переменной> do <оператор>
В рамках оператора, определяемого внутри оператора With, к полям определяемой переменной можно обращаться
просто по имени. Например,
with Payroll[7].Residence do
ZipCode := 2345;
for i := 1 to Workers do
with Payroll[i] do
if PayScale < 'G'
then
PayScale := Succ(PayScale);
Оператор with позволяет более компактно представлять часто используемые переменные. Посмотрите это на примере
фрагмента программы, печатающего адрес рабочего № 14:
with Payroll[14].Residence do
begin
writeln(HouseNumber,' ',StreetName);
writeln(CityName,',',StateName,',',ZipCode);
end;
В рамках составного оператора, следующего за with, каждое обращение к имени поля автоматически связывается с
записью Payroll[14].Residence. Печать адресов всех рабочих выполняется при помощи следующего оператора цикла:
for i := 1 to Workers do
with Payroll[i].Residence do
begin
writeln(HouseNumber,' ',StreetName);
writeln(CityName,',',StateName,',',ZipCode);
end;
Операторы with могут быть вложенными. Приведенные ниже три оператора эквивалентны друг другу:
1. Payroll[i].Residence.HouseNumber := 50;
2. with Payroll[i].Residence do
HouseNumber := 50;
3. with Payroll[i] do
with Residence do
HouseNumber := 50;
Однако недопустимым является использование вложенных операторов With, в которых указываются поля одного типа,
поскольку возникает неоднозначность конструкции. По этой причине приведенное использование вложенных операторов
With является неверным:
137
with Payroll[5] do
with Payroll[17]do
PayScale :='A';
Следует очень внимательно подходить к использованию вложенных операторов With, применение которых не только
может привести к ошибкам, но также к потере наглядности структуры программы. Хотя оператор With является стандартным
средством сокращения, его полезность должна еще проявиться. Конечной целью всякого хорошего программиста является
написание не только короткой, но и понятной программы.
Рассмотрите решение задачи.
Задача. В массиве хранятся данные об учениках класса: школа, фамилия, класс. Вывести список учеников, которые
учатся в восьмом классе.
Program LipovsevM;
Uses
Crt;
Type
Uchenik=record
Shkola : integer;
Fam : string[15];
Klass : integer;
end;
Var
I,n,a,j : integer;
Massiv : array[1..100] of Uchenik;
Рrocedure Poisk;
Begin
for i:=1 to n do
if massiv[i].klass=8
then
with massiv[i] do
writeln(Shkola:4,' ',Fam:15,'
',klass);
End;
Begin
ClrScr;
writeln('Введите число учеников ');
write('->');
read(n);
for i:=1 to n do
begin
writeln('Введите через пробел номер школы и фамилию ученика ');
write('->');
with massiv[i] do
begin
readln(Shkola,Fam);
write('Введите класс ученика (только число) ->');
read(Klass);
end;
end;
writeln('Ученики 8-ых классов:');
writeln('Школа
Фамилия Класс');
writeln('---------------------------------');
Poisk;
ReadKey;
End.
Занятие 2. Самостоятельное решение задач
Выберите с учителем задачи для решения из предложенного списка. Для проверки учителем решения Вашей задачи
приготовьте не только листинг и файл с протестированной задачей, но и 3-4 теста для демонстрации различных вариантов
введения информации и вывода на экран.
1. Составить список учебной группы, включающей N человек. Для каждого учащегося указать дату рождения, год
поступления в техникум, курс, группу, оценки каждого года обучения. Информацию о каждом учащемся оформить в
программе в виде записи. Совокупность записей объединить в массив. Составить программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать анкетные данные студентов отличников.
138
2. Составить список учебной группы, включающей N человек. Для каждого учащегося указать дату рождения, год
поступления в техникум, курс, группу, оценки каждого года обучения. Информацию о каждом учащемся оформить в
программе в виде записи. Совокупность записей объединить в массив. Составить программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать анкетные данные студентов, получивших одну
оценку 3 за все время обучения.
3. Составить список учебной группы, включающей N человек. Для каждого учащегося указать дату рождения, год
поступления в техникум, курс, группу, оценки каждого года обучения. Информацию о каждом учащемся оформить в
программе в виде записи. Совокупность записей объединить в массив. Составить программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать список студентов, фамилии которых
начинаются на буквы Б и В, и их оценки за последнюю сессию.
4. Составьте список учебной группы, включающей N человек. Для каждого учащегося укажите фамилию, имя, отчество,
дату рождения, год поступления в ВУЗ, факультет, отделение, курс, группу. Информацию о каждом учащемся оформите в
программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать по выбору пользователя анкетные данные
студентов нужного курса.
5. Составьте список учебной группы, включающей N человек. Для каждого учащегося укажите фамилию, имя, отчество,
дату рождения, год поступления в ВУЗ, факультет, отделение, курс, группу. Информацию о каждом учащемся оформите в
программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатайте по выбору пользователя анкетные данные
студентов нужного факультета.
6. Составьте список учебной группы школы юного программиста, включающей N человек. Для каждого учащегося
укажите фамилию, имя, отчество, название общеобразовательной школы, класс, год поступления в школу, количество
сданных зачетов. Информацию о каждом учащемся оформите в программе в виде записи. Совокупность записей объединить
в массив. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте по выбору пользователя анкетные данные учащихся, сдавших нужное количество зачетов.
7. Составьте список учебной группы школы юного программиста, включающей N человек. Для каждого учащегося
укажите фамилию, имя, название общеобразовательной школы, класс, количество сданных зачетов, оценку за итоговый
экзамен. Информацию о каждом учащемся оформите в программе в виде записи. Совокупность записей объединить в массив.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте анкетные данные учащихся, успешно сдавших экзамен.
8. Составьте список группы спортсменов, занимающихся легкой атлетикой, включающей N человек. Для каждого
спортсмена укажите фамилию, имя, название общеобразовательной школы, класс, результаты по следующим дисциплинам:
- бег 100м,
- бег 3000м,
- прыжки в высоту,
- прыжки в длину,
- прыжки с шестом,
- метание ядра,
- метание копья,
- метание диска.
Информацию о каждом спортсмене оформить в программе в виде записи. Совокупность записей объединить в массив.
Составить программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатать анкетные данные спортсменов, занявших 1 место по каждой дисциплине.
9. Составьте список группы спортсменов, участвовавших в соревнованиях по плаванию, включающей N человек. Для
каждого пловца укажите фамилию, имя, название общеобразовательной школы, класс, результаты по следующим
дисциплинам:
- кроль на груди,
- кроль на спине,
- баттерфляй,
- комплексное плавание.
Информацию о каждом спортсмене оформите в программе в виде записи. Совокупность записей объедините в массив.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте анкетные данные спортсменов,
а) занявших 1 место по каждому стилю плавания;
б) показавших лучшее время по всем видам плавания,
в) не получивших ни одного призового места.
10. Составьте список группы спортсменов, участвовавших в соревнованиях по спортивной гимнастике, включающей N
человек. Для каждого гимнаста указажите фамилию, имя, название общеобразовательной школы, класс, результаты по
следующим видам:
139
- кольца,
- брусья,
- перекладина,
- вольные упражнения,
- прыжки на дорожке,
- прыжки через коня.
Информацию о каждом спортсмене оформить в программе в виде записи. Совокупность записей объединить в массив.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатать анкетные данные спортсменов,
а) показавших лучший результат по каждому виду;
б) показавших лучший результат по всем видам многоборья,
в) не получивших ни одного призового места.
11. Составьте список группы спортсменов, участвовавших в гонках на спортивных машинах, включающей N человек.
Для каждого гонщика укажите фамилию, имя, название страны, номер автомашины, наличие наград на предыдущих
состязаниях, результаты гонки. Информацию о каждом спортсмене оформите в программе в виде записи. Совокупность
записей объединить в массив. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в
виде таблицы, а также распечатайте анкетные данные спортсменов,
а) показавших лучший результат;
б) показавших три лучших результата,
в) не получивших ни одного призового места.
12. Составьте прайс-лист магазина "Техника", включающий в себя наименования товара, марку предприятияпроизводителя, страну-производитель, его цену, количество единиц товара на складе. Информацию о каждом виде товара
оформите в программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая
обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию о
товаре в зависимости от запроса покупателя.
13. Составьте прайс-лист кондитерского отдела магазина "Молодежный", включающий в себя наименования товара,
марку предприятия-производителя, страну-производитель, его цену, количество единиц товара на складе. Информацию о
каждом виде товара оформите в программе в виде записи. Совокупность записей объедините в массив. Составьте программу,
которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем
информацию о товаре в зависимости от запроса покупателя.
14. Составьте прайс-лист аптеки "Эксон", включающий в себя наименования товара, страну-производитель, его цену, его
состав, рекомендации врача. Информацию о каждом виде товара оформите в программе в виде записи. Совокупность записей
объедините в массив. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде
таблицы. Выведите на экран меню, а затем информацию о товаре в зависимости от запроса покупателя.
15. Составьте прайс-лист магазина "Спортивные товары", включающий в себя наименования товара, странупроизводитель, его цену, материал изготовления, размер, рекомендации для использования. Информацию о каждом виде
товара оформите в программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая
обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию о
товаре в зависимости от запроса покупателя.
16. Составьте прайс-лист магазина "Обувь", включающий в себя наименования товара, страну-производитель, его цену,
материал изготовления, размер, рекомендации для использования. Информацию о каждом виде товара оформите в
программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию о товаре в
зависимости от запроса покупателя.
17. Составьте банк данных своих друзей и (или) подруг, включающий в себя фамилию, имя, место знакомства, почтовой
и (или) электронный адрес, телефон, день и год рождения, хобби, любимое блюдо, любимый напиток (и другое).
Информацию о каждом товарище оформите в программе в виде записи. Совокупность записей объедините в массив.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран
меню, а затем информацию о друзьях в зависимости от Вашего запроса.
18. Составьте банк данных кинологов, включающий в себя фамилию и имя владельца собаки, кличку собаки, породу
собаки, день и год рождения собаки, наличие родословной, наличие медалей (и другое). Информацию о каждом владельце
оформите в программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая
обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию в
зависимости от Вашего запроса.
19. Составьте банк данных районного отдела милиции, включающий в себя фамилию, имя и отчество нарушителя, дату
рождения, наличие клички, мера наказания, срок заключения (и другое). Информацию о каждом нарушителе оформите в
программе в виде записи. Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию в зависимости от
Вашего запроса.
140
20. Составьте банк данных членов своей семьи и (или) ближайших родственников, включающий в себя имя, отчество,
степень родства, день и год рождения, хобби, любимое блюдо, любимый напиток, любимая поговорка (и другое).
Информацию о каждом родственнике оформите в программе в виде записи. Совокупность записей объедините в массив.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран
меню, а затем информацию о родне в зависимости от Вашего запроса.
Познакомившись с содержанием предыдущих задач придумайте свою интересную задачу и решите ее.
Занятие 3. Сортировка записей.
Рассмотрите решение задачи, наберите ее на компьютере, протестируйте, найдите в программе недостатки и устраните
их. Дополните задачу комментариями и покажите учителю для оценки.
Задача 1. Во время лыжных соревнований в центральный судейский компьютер поступают данные в следующем виде:
номер участника, его фамилия, страна и показанный результат. Составить программу, которая после ввода очередной
информации выдает таблицу результатов участников в порядке ухудшения.
Program Ski;
Uses
Crt;
Type
inf= record
num: byte;
name,strana: string[30];
rez: real;
end;
Var
m: array [1..100] of inf;
i,j,k,l: integer;
Procedure Input;
Begin
write('Введите количество участников соревнований: ');
readln(k);
for i:=1 to k do
with m[i] do
begin
write('Введите номер участника: ');
readln(num);
write('Введите фамилию: ');
readln(name);
write('Какую страну представляет: ');
readln(strana);
write('Показанный результат: ');
readln(rez);
writeln;
end;
End;
Procedure Vich;
Var
o: real;
n,s:string;
nm: byte;
Begin
ClrScr;
for i:=1 to k-1 do
for j:=i+1 to k do
begin
if m[j].rez<m[i].rez
then
begin
o:=m[j].rez;{Меняем результаты}
m[j].rez:=m[i].rez;
m[i].rez:=o;
nm:=m[j].num;{Меняем номера}
m[j].num:=m[i].num;
m[i].num:=nm;
141
n:=m[j].name;{Меняем фамилии}
m[j].name:=m[i].name;
m[i].name:=n;
s:=m[j].strana; {Меняем страны}
m[j].strana:=m[i].strana;
m[i].strana:=s;
end;
end;
End;
Procedure Output;
Begin
for i:=1 to k do
with m[i] do
begin
writeln('',i,'-ое место занял:');
writeln('участник под номером: ',num);
writeln('Его фамилия: ',name);
writeln('Представляет страну : ',strana);
writeln('Показанный результат: ',rez:3:1);
writeln;
end;
End;
Begin
ClrScr;
Input;
Vich;
Output;
ReadKey;
End.
Задание. Дополните решенную Вами предыдущую задачу сортировкой по выбранному Вами полю записи и выводом
отсортированного массива записей на экран. Сортировку осуществляйте с помощью одного из способов, выбранного
учителем из предложенных:
- сортировка вставкой;
- сортировка выбором;
- сортировка методом простого обмена;
- сортировка с помощью рекурсии.
Задание. Выберите с учителем задачи для решения из предложенного списка. Для проверки учителем решения Вашей
задачи приготовьте не только листинг и файл с протестированной задачей, но и 3-4 теста для демонстрации различных
вариантов введения информации и вывода на экран.
1. Среди N абитуриентов, сдававших экзамены по информатике, математике и английскому языку, выбрать всех
отличников и всех учащихся, набравших в сумме не меньше проходного балла. Данные о проходном балле вводятся с
клавиатуры.
2. Среди N абитуриентов, сдававших экзамены по информатике, математике и английскому языку в перечисленном
порядке, выбрать учащихся, не допущенных к сдаче следующего экзамена в связи с получением неудовлетворительной
оценки по предыдущему экзамену. Выдать на экран список абитуриентов, удачно сдавших все экзамены.
3. Составить программу, выдающую справку о номере квартиры, в которой проживает жилец. В доме имеется N квартир
и проживает M человек. Пользователь вводит фамилию жильца. Если в доме поживает несколько жильцов с такой фамилией,
то выдается сообщение о необходимости ввести инициалы. Если инициалы у нескольких жильцов совпадают, то необходимо
ввести год рождения. Если с такими данными найдется один жилец (несколько), то вывести номер (номера) квартир, где он
(они) проживают и все введенные о нем (них) сведения. Если жильца с такой фамилией нет, то вывести сообщение об этом.
4. Составить программу, которая анализировала бы введенную информацию о пользователях городской телефонной
сети и выдавала бы список абонентов, имеющих задолженность за месяц, а также считала пеню (вводится пользователем).
Запись должна иметь поля:
- месяц анализа данных;
- фамилию, имя, отчество;
- номер телефона;
- адрес;
- имеющиеся льготы по оплате;
- абонентская плата;
- стоимость междугородних разговоров;
- стоимость дополнительных платных услуг.
142
По введенной информации и запросу пользователя предусмотреть в программе вывод предупреждения абонентов,
имеющих задолженность.
5. Составить программу, собирающую данные об авиакомпаниях и выдающую справку туристу до запрашиваемого
места. Справка должна содержать:
- название авиакомпании;
- название рейса;
- номер рейса;
- тип самолета;
- даты вылета (содержатся в массиве);
- наличие мест в 1 и 2 классах;
- стоимость перелета.
В случае покупки билета, массив записей должен быть соответственно измениться.
6. Во время лыжных соревнований в центральный судейский компьютер поступают данные в следующем виде: номер
участника, его фамилия, страна и показанный результат. Составить алгоритм, который после ввода очередной информации
выдает таблицу результатов участников в порядке ухудшения.
7. В экзаменационной ведомости фиксируются фамилии учеников, номера билетов, оценки, записанной прописью.
Составьте подобную ведомость для группы из N человек на основе сформированного массива записей. Строка списка имеет
следующий вид:
Иванов Александр
билет № 12
(отлично)
Вывести информацию о результатах экзамена в следующем виде:
Количество экзаменуемых – 25
Сдали на "отлично" – 7
Сдали на "хорошо" – 10
Сдали на "удовлетворительно" – 7
Сдали на "неудовлетворительно" – 1
Не явились – нет
8. По окончании школы ученики сдавали экзамены по литературе, математике, физике и информатике. Определите
экзамен, на котором ученики получили наиболее высокий средний бал и выведите список учащихся в порядке убывания
результатов по этому экзамену.
9. Составить программу, организующую заполнение массива записями, содержащими информацию о здоровье детей в
лагере отдыха. Запись должна содержать поля:
- фамилия, имя ребенка;
- дата прибытия в лагерь;
- вес ребенка (на день прибытия, через 10 дней, через 20 дней);
- рост ребенка;
- возраст;
- номер отряда;
- наличие хронических заболеваний.
Вывести данные о детях, увеличивающих свой вес и о детях, которые худеют.
10. Познакомившись с содержанием предыдущих задач придумайте свою интересную задачу и решите ее.
Занятие 4. Записи с вариантами.
Записи, рассмотренные выше – это записи с фиксированными частями. Они имеют в различных ситуациях строго
определенную структуру. Соответственно записи с вариантами в различных ситуациях могут иметь различную структуру.
Предположим, что написана программа для введения списка библиографических ссылок. Если известно, что все входы в
этом списке – ссылки на книги, то можно использовать следующее описание:
Const
Kol = 1000;
Type
Entry = Record
Autor, Title, Publisher, City : String;
Year : 1..2000;
End;
Var
List : Array[1..Kol] of Entry;
143
Что произойдет, если некоторые из входов не являются ссылками на книги, а содержат ссылки на журнальные статьи.
Если ограничиваться только записями с фиксированными частями, то следует описать различные массивы для каждого вида
записей. Использование записей с вариантами позволяет образовать структуру, каждый вход которой соответствует
содержанию записи. Опишем новый тип, в котором перечислены различные входы:
Type
EntryType = (Book, Magazine);
Теперь можно привести скорректированное описание Entry
Type
Entry = Record
Autor, Title : String;
Year : 1..2000;
Case EntryType of
Book : (Publisher, City : String);
Magazine : (MagName : String,
Volume, Issue : Integer)
End;
Это описание делится на две части: фиксированную и вариантную. Поля Autor, Title, Year составляют фиксированную
часть. Оставшаяся часть описания Entry образует вариантную часть, структура которой, подобно хамелеону, может меняться
в пределах двух альтернативных определений.
Первая строка вариантной части представляет оператор Case, который отличается тем, что в качестве селектора
применяется идентификатор типа. Значения EntryType используются в качестве имен двух альтернатив определения записи.
Когда эта компонента имеет значение Book, можно обращаться к следующим полям:
Autor, Title, Year, Publisher, City
С другой стороны, когда она принимает значение Magazine, то можно обращаться к таким полям:
Autor, Title, Year, MagName, Volume, Issue
В такой ситуации возникает естественный вопрос: как программа может хранить информацию о текущем состоянии
каждой записи? Другими словами, каким образом можно узнать , что List[3] содержит ссылку на книгу, а List[4] – ссылку на
журнал?
Естественное решение этой проблемы заключается в добавлении в каждой записи нового поля, называемого полем тега.
Язык Паскаль позволяет за счет совмещения задать описание поля тега в сокращенной форме:
Type
Entry = Record
Autor, Title : String;
Year : 1..2000;
Case TAG : EntryType of
Book : (Publisher, City : String);
Magazine : (MagName : String,
Volume, Issue : Integer)
End;
Поле, названное TAG, является переменной типа EntryType. Когда запись содержит ссылку на книгу, TAG следует
присвоить значение Book. Когда запись содержит ссылку на журнал, TAG следует присвоить значение Magazine.
Рассмотрите последовательность операторов, где в RefList[12] помещается ссылка на книгу:
RefList[12].TAG := Book;
RefList[12].Autor := 'Thomas Hobbes';
RefList[12].Title := 'Leviathan';
RefList[12].Year := 1651;
RefList[12].Publisher := 'Andrew Crooke';
RefList[12].City := 'London';
Для определения состояния записи с вариантами достаточно проверить значение поля тега. Рассмотрите процедуру,
выводящую на экран переданную ей запись.
Procedure PrintRef(Citation : Entry);
Begin
Writeln(Citation.Autor);
Writeln(Citation.Title);
Writeln(Citation.Year);
If Citation.TAG = Book
Then
144
Writeln(Citation.Publisher,', ',Citation.City)
Else
Begin
Writeln(Citation.MagName);
Writeln(Citation.Volume'–',Citation.Issue)
End;
End;
Вариантная часть может содержать произвольное число альтернатив. Хотя перечисляемые типы предпочтительнее, так
как они более понятны, тем не менее для именования альтернатив записи с вариантами могут использоваться
идентификаторы произвольного порядкового типа.
Очевидно, что один и тот же идентификатор поля не может дважды использоваться при описании записи, даже если он
применяется в определении различных альтернатив записи с вариантами. Если же это условие не выполняется, то обращение
к такому идентификатору приведет к непредсказуемому результату.
Наверное Вы уже обратили внимание, что описание записи с вариантами может иметь единственный закрывающий
оператор End. Поскольку любая запись может иметь лишь одну вариантную часть, то End, который является индикатором
конца описания записи, служит для обозначения конца и ее вариантной части.
Задание. Опишите под именем Figure вариантную запись. Если переменная типа Figure представляет собой круг, то она
должна содержать радиус соответствующей окружности. Если эта переменная представляет прямоугольник, то она должна
содержать величину угла и длины двух сторон, образующих этот угол и т. д. Выполните одну из следующих задач:
а) Напишите процедуру, которая запрашивает и получает значение типа Figure от пользователя.
б) Напишите функцию, которая получает на входе значение типа Figure и вычисляет площадь фигуры.
в) Напишите функцию, которая получает на входе значение типа Figure и вычисляет периметр фигуры.
г) Напишите булеву функцию, которая получает на входе два значения типа Figure и определяет, помещается ли первая
фигура внутри второй.
Рассмотрите два примера решения задачи с вариантами.
Задача. В массиве хранятся данные об учениках класса: фамилия, имя, отчество, адрес (улица, дом , квартира) и
домашний телефон (если есть). Вывести список учеников, до которых нельзя дозвониться.
Program LipovsevM;
Uses
Crt;
Type
Uchenik=record
Name:string[10];
Fam:string[15];
Otch:string[15];
Ulica:string[20];
Dom:string[5];
Kvartira: integer;
case tel: boolean of
False:();
True:(Telefon:string[15]);
end;
Var
Massiv : array[1..100] of Uchenik;
I,n : integer;
Otvet : 0..1;
Begin
ClrScr;
TextColor(9);
write('Введите число учеников->');
readln(n);
for i:=1 to n do
begin
with massiv[i] do
begin
write('Введите имя ',i,'-го ученика ->');
readln(name);
write(''Введите фамилию ',i,'-го ученика ->');
readln(fam);
write(''Введите отчество ',i,'-го ученика ->');
readln(otch);
write(''Введите улицу ',i,'-го ученика ->');
145
readln(ulica);
write(''Введите дом ',i,'-го ученика ->');
readln(dom);
write(''Введите квартиру ',i,'-го ученика ->');
readln(kvartira);
write('Есть ли у ',i,'-го ученика телефон (0-нет, 1-да->');
readln(otvet);
if otvet=1
then
begin
tel:=True;
write(''Введите телефон ',i,'-го ученика ->');
readln(telefon);
end;
end;
End;
TextColor(red);
writeln('Список учеников, до которых нельзя дозвониться:');
for i:=1 to n do
begin
with massiv[i] do
if tel=False
then
begin
writeln('Имя:',name);
writeln('Фамилия:',fam);
writeln('Отчество:',otch);
writeln('Улица:',ulica);
writeln('Дом:',dom);
writeln('Квартира:',kvartira);
end;
end;
ReadKey;
End.
Задание. Будьте готовы объяснить решение предыдущей задачи и последующей учителю. Если затрудняетесь в чтении
алгоритма решения задачи, то обратитесь за помощью к учителю.
Задача. Осуществить ввод общей информации (автор, название) о содержимом библиотеки: имеющиеся книги,
журналы, газеты. Если книга, то осуществить дополнительно ввод года издания; если журнал – год издания и номер журнала;
если газета – год, месяц и день выхода газеты. Осуществить вывод информации, поиск литературы по типу издания.
Program SedihA;
Uses
Crt;
Type
TypePubl = (Book,Journal,Newspaper);
Litter = record
Title : string[50];
Author : string[50];
case V : TypePubl of
Вook
: (YearB : integer);
Journal
: (Num : 1..12;
YearJ : 1900..2000);
Newspaper : (Day : 1..31;
Month : 1..12;
YearN : integer);
end;
Const
Count = 10;
Var
Katalog : array [1..count] of Litter;
NumArray : 1..count;
YesLitter : Boolean;
Vybor : byte;
Edition : Type_Publ;
CountFind : integer;
Procedure InputData;
146
Begin
writeln;
writeln('Введите данные о литературе ', NumArray,' :');
write('Введите число, указывающее вид издания: ');
Write('1-книга, 2-журнал, 3-газета : ');
readln(Vybor);
case Vybor of
1 : Katalog[NumArray].v:=Book;
2 : Katalog[NumArray].v:=Journal;
3 : Katalog[NumArray].v:=Newspaper;
end;
with katalog[NumArray] do
begin
write('Фамилия автора? ');
readln(Author);
write('Название? ');
readln(Title);
case v of
Book
: begin
write('Год издания ? ');
readln(YearB);
end;
Journal
: begin
write('Номер ? ');
readln(Num);
write('Год издания ? ');
readln(YearJ);
end;
Newspaper : begin
write('Дата издания: День? ');
readln(Day);
write('Месяц? ');
readln(Мonth);
write('Год? ');
readln(YearN);
end;
end;
end;
End;
Procedure WriteData;
Begin
writeln;
with Katalog[NumArray] do
begin
writeln('Название : ',Тitle);
writeln('Фамилия автора: ',Аuthor);
case v of
Book
: writeln('Год издания : ',YearB);
Journal
: begin
writeln('Номер : ', Num);
writeln('Год издания : ',YearJ);
end;
Newspaper
: writeln('Дата издания: День: ',Day,' Месяц: ',Month,'Год: ',YearN);
end;
end;
Еnd;
Procedure FindLitter;
Begin
writeln('Поиск литературы по типу издания: ');
writeln;
write('1-книга, 2-журнал, 3-газета: ');
readln(Vybor);
case Vybor of
1 : Edition:=Book;
147
2 : Edition:=Journal;
3 : Edition:=Newspaper;
end;
YesLitter:=False;
CountFind:=0;
for num_array:=1 to count do
if katalog[num_array].v = edition
then
begin
YesLitter:=True;
CountFind:=CountFind+1;
WriteData;
end;
if not YesLitter
then
writeln('В иблиотеке нет такой литературы')
else
writeln('Всего в библиотеке ',CountFind,' таких изданий');
End;
Begin
ClrScr;
for NumArray:=1 to Count do
InputData;
writeln;
FindLitter;
End.
Выберите с учителем задачи для решения из предложенного списка. Задачи решайте с помощью записей с вариантами.
Для проверки учителем решения Вашей задачи приготовьте не только листинг и файл с протестированной задачей, но и 3-4
теста для демонстрации различных вариантов введения информации и вывода на экран.
1. Составьте список группы спортсменов, участвовавших в соревнованиях по спортивной гимнастике, включающей N
человек. Для каждого гимнаста указажите фамилию, имя, название общеобразовательной школы, класс, результаты по
следующим видам:
- брусья,
- вольные упражнения,
- прыжки на дорожке,
- прыжки через коня;
для юношей
- кольца,
- перекладина,
для девушек
- бревно
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте анкетные данные спортсменов,
а) показавших лучший результат по каждому виду;
б) показавших лучший результат по всем видам многоборья,
в) не получивших ни одного призового места.
2. Составьте прайс-лист магазина "Техника", включающий в себя марку предприятия-производителя, странупроизводитель и ,в зависимости от этих данных, наименования товара, его цену, количество единиц товара на складе.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран
меню, а затем информацию о товаре в зависимости от запроса покупателя.
3. Составьте прайс-лист аптеки "Эксон", включающий в себя наименования товара, страну-производитель, его цену, его
состав, рекомендации врача в зависимости от возраста больного (дозировка, наличие сопутствующих расстройств).
Информацию о каждом виде товара оформите в программе в виде записи с вариантами. Совокупность записей объедините в
массив. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите
на экран меню, а затем информацию о товаре в зависимости от запроса покупателя.
4. Составьте банк данных членов своей семьи и (или) ближайших родственников, включающий в себя имя, отчество,
степень родства, и в зависимости от введенной информации в поле <МолодойСтарый> придумайте варианты полей
(например, хобби, любимый анекдот, количество медалей, количество внуков, любимый напиток, любимая девочка, лучший
друг, объем имеющегося наследства). Информацию о каждом родственнике оформите в программе в виде записи с
вариантами. Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод полученной
148
информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию о родне в зависимости от Вашего
запроса.
5. Составьте банк данных своих одноклассников, включающий в себя фамилию, имя, почтовой и (или) электронный
адрес, телефон, а также в зависимости от поля <Друг> наличие соответствующей дополнительной информации по своему
усмотрению. Информацию о каждом товарище оформите в программе в виде записи с вариантами. Совокупность записей
объедините в массив. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде
таблицы. Выведите на экран меню, а затем информацию о друзьях в зависимости от Вашего запроса.
6. Составьте банк данных кинологов, включающий в себя фамилию и имя владельца собаки, кличку собаки, породу
собаки, день и год рождения собаки, а также в зависимости от породы наличие соответствующей дополнительной
информации по своему усмотрению. Информацию о каждом владельце оформите в программе в виде записи с вариантами.
Совокупность записей объедините в массив. Составьте программу, которая обеспечивает ввод полученной информации,
распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию в зависимости от Вашего запроса.
7. Составьте банк данных районного отдела милиции, включающий в себя фамилию, имя и отчество нарушителя, дату
рождения, и в зависимости от поля <Судимость> наличие соответствующей дополнительной информации по своему
усмотрению (например, наличие клички, мера наказания, срок заключения). Информацию о каждом нарушителе оформите в
программе в виде записи с вариантами. Совокупность записей объедините в массив. Составьте программу, которая
обеспечивает ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию в
зависимости от Вашего запроса.
8. Составить программу, которая бы считывала и анализировала введенную информацию о пользователях городской
телефонной сети. Запись должна иметь поля:
- фамилию, имя, отчество;
- номер телефона;
- адрес;
- наличие задолженности по оплате (в массиве по всем месяцам года).
Предусмотрите в программе варианты полей в зависимости от заполнения поля <Задолженность по оплате> (например,
размер долга, отключение от междугородней сети, подсчет пени и другое).
По введенной информации и запросу пользователя предусмотреть в программе вывод предупреждения абонентов,
имеющих задолженность, и какое-либо поощрение ответственным плательщикам.
9. Составить программу, собирающую данные об авиакомпаниях и выдающую справку туристу до запрашиваемого
места. Справка должна содержать:
- название авиакомпании;
- название рейса;
- номер рейса;
- тип самолета;
- даты вылета (содержатся в массиве);
- наличие мест в 1 и 2 классах;
Предусмотрите в программе варианты полей сервиса в зависимости от выбора поля <Класс>. В случае покупки билета,
массив записей должен быть соответственно измениться.
10. Познакомившись с содержанием предыдущих задач придумайте свою интересную задачу и решите ее.
Дополнительно. Решение задач
Выберите с учителем задачи для решения из предложенного списка. Для проверки учителем решения Вашей задачи
приготовьте не только листинг и файл с протестированной задачей, но и 3-4 теста для демонстрации различных вариантов
введения информации и вывода на экран.
1. Написать программу, определяющую:
а) дату следующего (предыдущего) дня;
б) дату, которая наступит через m дней;
в) дату, которая была за m дней до сегодняшнего дня;
г) количество суток, прошедших от даты t1 до даты t2.
2. Дан массив, содержащий информацию об учениках некоторой школы.
а) Заполнить второй массив данными об учениках только девятых классов.
б) Выяснить, на сколько человек в восьмых классах больше, чем в девятых.
3. Багаж пассажира характеризуется количеством вещей и общим весом вещей. Дан массив, содержащий сведения о
багаже нескольких пассажиров. Сведения о багаже каждого пассажира представляют собой запись с двумя полями: одно
поле целого типа (количество вещей) и другое - действительного типа (вес в килограммах).
149
а) Найти багаж, вес вещей в котором отличается не более, чем на 0.3 кг от общего среднего веса вещей пассажиров.
б) Найти число пассажиров, имеющих более двух вещей и число пассажиров, количество вещей которых
превосходит среднее число вещей.
в) Выяснить, имеется ли пассажир, багаж которого состоит из одной вещи весом менее 30 кг.
4. В массиве хранятся данные об учениках класса.: фамилия, имя, отчество, адрес (улица, дом, квартира) и домашний
телефон (если есть). Вывести на экран список учеников до которых нельзя дозвониться.
5. Дан массив данных о работающих на предприятии: фамилия, имя, отчество, адрес (улица, дом, квартира) и дата
поступления на работу. Во второй массив записать данные только тех из них, кто на сегодняшний день уже проработал не
менее 5 лет.
6. В массиве хранятся данные о студентах некоторого Вуза: фамилия, имя, отчество, пол, возраст, курс.
а) Определите номер курса, на котором наибольший процент мужчин.
б) Выведите на печать самое распространенные мужское и женское имена.
в) фамилии (в алфавитном порядке) и инициалы всех студенток, возраст и отчества которых являются одновременно
самыми распространенными.
7. Даны сведения предлагаемые к продаже на Нью-Йоркской фондовой бирже. В каждой группе записано наименование
держателя акций (например IBM, GTE) и два числа, такие как 31.50 и 0.15. Эти числа представляют соответственно
стоимость одной акции и размер получаемого с нее дохода (дивиденды). Программа должна определить, сколько процентов
от стоимости акции приходится на дивиденды. Если окажется, что вычисленное значение превышает 10%, необходимо
напечатать сообщение о том, что приобретение акций данной компании будет выгодной сделкой.
8. Для каждой из следующих задач предложите наилучший на ваш взгляд, способ представления информации: массив,
запись или, может быть, только простые переменные. Обоснуйте ваши ответы.
а) Найти среднее арифметическое из некоторого произвольного количества целых чисел.
б) Дан список 50 имен. Необходимо проверить, не встречается ли какое–нибудь имя дважды.
в) Составить платежную ведомость фирмы, включив в нее такие данные, как адрес, годовой доход, иждивенцы и т.п.
г) Составить список оценок студента по пяти экзаменам.
д) Найти среднюю оценку одного студента.
е) Разместить данные одного студента: фамилию, экзаменационные оценки и среднюю оценку.
ж) Разместить те же данные на 50 студентов.
Приготовьте файлы с решенными задачами, проверенные листинги и тесты к задачам.
150
ФАЙЛЫ
Занятие 1. Файлы. Виды файлов. Типизированные файлы
До сих пор мы рассматривали задачи, в которых во время выполнения программы данные поступают с клавиатуры, а
результаты выводятся на экран дисплея. Поэтому ни исходные данные, ни результаты не сохраняются. Всякий раз при
выполнении одной и той же программы, особенно во время отладки, приходится заново вводить данные. А если их очень
много? В языке Паскаль есть возможность записать их на диск. для этого необходимо оформить исходные данные и
результаты в виде файлов, которые хранятся на диске точно так же как и программы.
Понятие файла – это фундаментальное понятие информатики, вспомним же его определение.
Определение. Файлом называется область памяти жесткого диска, имеющая свое имя.
Вы знаете, различные виды физических файлов: системные, графические, текстовые и другие, зачастую созданные той
или иной прикладной программой. И любой из этих физических файлов, Вы сможете считать, проанализировать и повлиять
на его изменение и запись. Но чтобы работать с конкретным физическим файлом на диске, надо представить в программе так
называемую файловую переменную и произвести их логическую связку.
Зачем нужны файлы? Дело в том, что количество элементов файла может быть любым: число компонент файла может
изменяться (увеличиваться или уменьшаться), то есть заранее не фиксируется. Поэтому в них можно хранить достаточно
большое количество данных. После каждого элемента автоматически ставится признак конца элемента, а в конце файла
ставится признак конца файла.
Один и тот же физический файл можно по-разному представить в программе. Язык Турбо Паскаль предлагает три вида
такого представления:
- типизированные файлы,
- текстовые файлы,
- нетипизированные файлы.
И Вы, в зависимости от решаемой задачи, вольны выбирать один их трех видов, а может быть и несколько. Но чтобы
определиться, Вы должны хорошо знать не только процедуры и функции, являющиеся общими для всех видов файлов, но и
специфичные для каждого вида.
Начнем изучение файлов с типизированных.
Определение. Типизированный файл – последовательность элементов одного типа.
Описание файлового типа имеет синтаксис:
file of < тип элементов>;
Допустим, мы имеем дело с файлом, в котором записываются переменные типа Word, тогда переменная файлового типа
может быть введена двояко: с явным объявлением файлового типа:
Type
WordFile = file of word;
Var
MyFile : WordFile
или без объявления файлового типа:
Var
MyFile : file of word
Приведем примеры переменных файлового типа с другими объявлениями.
Type
Student = record
Name, SerName : string;
YearOld : byte;
Sessia : array [1..10] of byte;
end;
Var
VarFile1 : file of char;
VarFile2 : file of Student;
VarFile3 : file of string;
Файловые переменные имеют специфическое применение. Над ними нельзя выполнять никаких операций (присваивать
значение, сравнивать и др.). Их можно использовать только для выполнения операций с файлами (чтения, записи, удаления
файла и т.д.). кроме того, через файловую переменную можно получить информацию о конкретном файле (тип, параметры,
имя файла и т.д.).
151
По сути любой физический файл, Вы можете представить как последовательность блоков памяти описанного типа. Все
компоненты файла имеют общее имя, а каждый еще и имеет свой номер. Начальный элемент имеет нулевой номер.
С каждым файлом можно связать понятие текущий указатель. Это неявно описанная переменная, которая указывает на
конкретный элемент файла. Действия с файлами производятся поэлементно, причем в них участвует тот элемент, на который
"смотрит" текущий указатель, перемещающийся в результате выполнения действия на следующий элемент.
А самое основное, что Вы должны уметь делать над файлом это – записать информацию из программы в файл и считать
нужную информацию в выделенную переменную для обработки программой.
Процедуры и функции для работы с файлами любого типа
Переменные файлового типа используются в программе только в качестве параметра собственных и стандартных
процедур и функций. Все фактические действия с файлами основаны на наборе стандартных процедур языка, входящих в
состав модулей System и Dos.
Сначала рассмотрим процедуры модуля System.
Напомним, что он подключен к программам по умолчанию, то есть его не требуется подключать к программе в разделе
Uses.
До начала работы с файлами устанавливается связь файловой переменной МуFilе с именем дискового файла. Очень
важно различать собственно файл (область памяти на магнитном носителе с некоторой информацией) и переменную
файлового типа в некоторой Turbo Pascal-программе. Считается, что файловая переменная является представителем
некоторого дискового файла в программе. Для того, чтобы реализовать доступ к файлу на магнитном диске, программа
должна связать его с файловой переменной. Для этого необходимо сопоставить переменную с именем файла. Это имя
представляется в виде строки, содержащей полное имя файла и, может быть, маршрута к файлу, который формируется по
общим правилам MS-DOS.
Например,
assign (МуFilе, 'с:\МуDirectory\Result.dat');
здесь приведено полное (с указанием пути) имя пользовательского файла Result.dat.
Если путь не указан, программа будет искать файл только в своем рабочем каталоге и, как это принято в системе DOS,
по указанным в файле аutoехес.bat путям. Кроме указания имени файла на дисковом накопителе может быть указано
стандартное имя одного из устройств ввода-вывода: «соn» – консоль, то есть дисплей и клавиатура, «рrn» – или «lpt1» –
принтер.
Не разрешается связывать с одним физическим файлом различные файловые переменные в программе.
До тех пор, пока файловая переменная не связана с каким-либо дисковым файлом, никакие операции с ней в программе
невозможны. Заметим, что можно связать файловую переменную с еще не существующим дисковым файлом. Это делается в
случае последующего создания Turbo Pascal-программой файла с данным именем с помощью специальной системной
процедуры.
После того, как файловая переменная с помощью процедуры Аssign связана с конкретным дисковым файлом, можно
выполнить любую допустимую операцию с ним.
Все файлы, открытые в результате работы программы, должны быть закрыты при завершении программы процедурой
closе (МуFilе);
При выполнении этого оператора закрывается физический файл на диске и фиксируются изменения, связанные с
использованием данного файла. Обратите внимание на необходимость закрытия файлов во всех ветвях программы, в том
числе в различных аварийных ситуациях. Незакрытые файлы нарушают файловую структуру на диске, что может приводить
к серьезным проблемам с настройкой компьютера.
Открытие нового файла для записи производится процедурой, единственный аргумент которой – переменная файлового
типа, например:
rewrite (МуFilе);
Эта процедура создает на диске новый файл, имя которого связано с переменной МуFilе процедурой Аssign. Указатель
работы с файлом помещается в начальную позицию.
Внимание! Если файл с таким именем уже существует, он становится пустым, то есть его предыдущее содержание
теряется.
После выполнения процедуры rewrite файл доступен как для записи, так и для чтения.
Подготовку существующего файла для чтения и записи выполняет процедура
reset (МуFilе);
152
Эта процедура ищет уже существующий файл на диске и открывает его для работы, помещая указатель в начальную
позицию. Если файл с установленным в Аssign именем не найден, возникает ошибка ввода/вывода, контроль которой зависит
от директивы компилятора {$I} (смотрите ниже).
Внимание! Файл в данный момент времени может быть в одном из двух состояний: либо только для записи, либо
только для чтения.
Запись в файл производится процедурой
write (МуFilе, var1, var2, ...., varN);
Первый аргумент этой процедуры – переменная файлового типа, далее следует список записываемых переменных,
которые должны соответствовать обьявленному типу файла. При выполнении этой операции текущий указатель файла
смещается на число позиций, равное числу переменных.
Чтение из файла производится аналогичной процедурой:
read (МуFilе, var1, var2, ...., varN);
Положение элементов в файле нумеруется, начиная с номера 0 для первого элемента. После последнего элемента файла
автоматически записывается признак конца файла.
Функция FileSize(МуFilе) определяет число элементов в файле.
Функция логического типа ЕОF(МуFilе) имеет значение Тrие, если указатель указывает на маркер конца файла (End Of
file).
Длина файла, то есть количество элементов в этой последовательности – величина произвольная, изменяемая в процессе
работы. Работа с файлами заключается в записи и считывании элементов этой последовательности. Для того, чтобы указать,
с каким элементом файла производятся операции, существует понятие указателя на доступный элемент файла.
Пример. Приведем шаблон программы для записи данных в файл
Program Writing;
Var
FileName : string; {строка, содержащая имя файла}
FVar : file of byte; {переменная файлового типа}
Index : byte;
Begin
write ('Введите имя файла ');{предложение ввести имя файла}
readln (FileName);{ввод имени файла}
assign (FVar, FileName);{связь имени файла и переменной}
rewrite (FVar);{открытие файла для записи}
for Index := 0 to 99 do {цикл для расчетов и вывода данных в файл}
write (FVar,Index);{запись в файл FVar величины Index}
close (FVar); {закрытие файла}
End.
Примечание. В цикле могут быть вычислительные процедуры для получения данных, выводимых в файл. Мы, для
простоты, записали в файл счетчик цикла.
Внимание! Следует запомнить, что процедура rewrite обнулит файл, если файл с таким именем уже есть в рабочем
каталоге, поэтому при выборе имен файлов соблюдайте осторожность.
Задание № 1. Наберите предложенную для рассмотрения выше программу и дополните ее выводом на экран элементов
файла (воспользуйтесь процедурой считывания из файла read и вывода write). Результат покажите учителю для оценки.
Задание № 2. Создайте программу записи и чтения типизированного файла типа string.
Примеры решения задач
Рассмотрите примеры решения задач. Наберите тексты программ, проверьте их действие. Обратите внимание на
комментарий. Выполните задания к задачам.
Задача № 1. Дан файл, элементами которого являются целые числа. Найти среднее арифметическое элементов файла.
В примере решается задача считывание элементов из файла, их суммирование и нахождение среднего арифметического.
Предполагается, что типизированный файл уже создан.
Задание. Дополните содержание текста задачи созданием типизированного файла file.dat. Добавленные строчки
программы прокомментируйте.
Program Srednee;
Uses
Crt;
Var
153
Kol,
Element,
{переменная для хранения очередного элемента файла}
Summa
{переменная для хранения суммы элементов файла}
:integer;
f : file of integer;
SrAriph : real
Begin
ClrScr;
assign(f,'file.dat'); {связываем файловую переменную f с физическим файлом file.dat}
reset(f);
{открываем файл для чтения}
Summa :=0;
{обнуление суммы}
while not Еof(f) do {просматриваем файл до конца}
begin
read(f,Element);
{считываем из файла очередной элемент в переменную Element}
Inc(Kol);
{увеличиваем счетчик количества элементов файла}
Inc(Summa,Element); {увеличиваем переменную Summa на Element}
end;
SrAriph := Summa/Kol
{вычисляем среднее арифметическое чисел}
write('Среднее арифметическое элементов файла равно ',SrAriph:5:2);
close(f);
{закрываем файл}
readln;
End.
Задача №2. Наберите на компьютере и рассмотрите текст программы, сформулируйте решаемую в ней задачу,
дополните необходимыми операторами и комментарием. Покажите результат учителю для оценки.
Program FileString;
Uses
Crt;
Var
f, g : file of string;
str1, str : string;
i : integer;
Begin
ClrScr;
assign(f,'f');
rewrite(f);
assign(g,'g');
rewrite(g);
repeat
readln(str);
write(f,str);
for i:=length(str) downto 1 do
str1:=str1+str[i];
write(g,str1);
str1:='';
until str='';
close(f);
close(g);
assign(f,'f');
reset(f);
assign(g,'g');
reset(g);
while not eof(f) do
begin
read(f,str);
writeln(str);
end;
while not eof(g) do
begin
read(g,str);
writeln(str);
end;
close(f);
close(g);
readln;
End.
154
Задача № 3. Создать типизированный файл, содержащий информацию о работниках института.
Задание. Дополнить текст программы
а) нахождением среднего стажа работы в институте;
б) выводом фамилий работников, работающих инженерами;
в) выводом фамилий работников, начинающихся с заданной пользователем буквы;
г) выводом фамилий работников, у которых оклад больше заданного пользователем числа;
д) выводом фамилий работников предпенсионного возраста.
Program TipRecord;
Uses
Crt;
Type
Dann=record
stag : byte;
Surname, WorkName : string;
Oklad, Year : integer;
End;
Var
Spisok : file of Dann;
{файл типа записи Dann}
Man : Dann;
{переменная типа записи Dann для работы с файлом}
Name : string[12];
{строка для хранения имени физического файла}
Procedure VvodZap (Nomer : integer);
Begin
with Man do
begin
writeln('Введите данные ',Nomer,'-го работника');
write('Фамилия: ');
readln(Surname);
write('Год рождения:');
readln(Уear);
write('Стаж работы:');
readln(stag);
writeln('Должность:');
readln(WorkName);
write('Оклад');
readln(oklad);
write(Spisok ,Man); {записать в файл созданный элемент Man}
end;
End;
Procedure FileVvod;
Var
i, count : Integer;
Begin
write('Введите имя файла данных:');
readln(Name);
{имя физического файла}
assign(Spisok ,Name);
{связываем файловую переменную с файлом}
rewrite(Spisok );
{открываем файл для записи}
write('Введите количество работников:');
readln(count);
for i:=1 to count do
VvodZap(i);
{вызов процедуры ввода очередной информации в файл}
close(Spisok );
{закрываем файл}
readln;
End;
Begin
ClrScr;
FileVvod;
readLn;
End.
155
Занятие 2. Процедуры и функции для работы с типизированными файлами
Вспомним, что типизированный файл – это последовательность элементов одного типа. А раз так, то при
последовательном обращении к файлу текущий указатель переходит от элемента к элементу. Возникает вопрос: можно ли
игнорировать последовательный доступ к файлу и сразу, например, обратиться к третьему элементу файла? Оказывается,
можно.
Если есть необходимость нарушения последовательной записи или чтения из файла, текущий указатель, может быть
изменен процедурой
Seek (МуFilе, n)
где n – требуемое положение указателя.
Внимание! Нумерация элементов типизированного файла начинается с нуля.
Поэтому, чтобы обратиться к третьму элементу, нужно записать Seek (МуFilе, 2).
Seek (МуFilе, 0) – устанавливает указатель в начальной позиции (на первый элемент).
Seek (МуFilе, FileSize(МуFilе)) – устанавливает указатель после последнего элемента, то есть на признак конца файла.
Примечание. Функция FileSize(МуFilе) возвращает количество элементов типизированного файла МуFilе.
Текущую позицию указателя дает функция
FilePos (МуFilе).
Рассмотрите пример.
Задача. Составить программу, которая переписывает существующий файл, заменяя все латинские буквы на заглавные.
Рrogram Writing;
Var
FileName : string;
{строка, содержащая имя файла}
FVar : file of char;
{переменная файлового типа}
Index : integer;
Letter : char;
{читаемый из файла символ}
Begin
write('Enter filename: ');
{предложение ввести имя файла}
readln (FileName);
{ввод имени файла}
assign (FVar,FileName); {связь имени файла и переменной}
{$I-}
{отключен контроль ввода/вывода}
reset (FVar);
{открытие файла для чтения и записи}
{$I+}
{включен контроль ввода/вывода}
if IOResult <> 0
{выход, если файл не открыт}
then
begin
writeln ('Не открыт файл ', FileName);
Halt
end;
while not EOF (FVar) do {цикл до конца файла}
begin
read (FVar, Letter);
{чтение символа из файла}
Letter:=Upcase(Letter);
(преобразование букв)
Seek(FVar,FilePos(FVar)-1); {перемещение указателя назад на 1 позицию}
write(FVar,Letter);
{запись преобразованной буквы}
end;
{конец цикла}
close(FVar)
{закрыть файл}
End.
Функция IOResult
Как Вы уже заметили в предыдущей программе была использована функция IOResult. Рассмотрим, какую роль
выполняет эта функция.
Функция IOResult предназначена для поиска ошибок, возникающих при работе с файлами. Эта функция возвращает
результат последней операции ввода/вывода, если автоматический контроль за ошибками, возникающими при выполнении
операций ввода/вывода, отключен с помощью директивы компилятора {$I-}. При безошибочном выполнении операций
ввода/вывода функция IOResult всегда возвращает результат равный нулю. Поэтому, как правило, ее используют в операции
сравнения с нулем. При использовании функции IOResult нужно помнить о том, что она возвращает величину, которую
можно интерпретировать как флаг ошибки лишь в том случае, когда эта функция вызывается следом за операцией
ввода/вывода. А если Вы хотите провести анализ ошибки позже, Вам придется сохранить возвращаемое значение в
некоторой промежуточной переменной.
156
Просмотрите еще раз фрагмент программы, в которой посредством процедуры reset производится попытка открытия
файла. Если эта попытка не увенчалась успехом, то на экран будет выведено сообщение об ошибке.
{$I-}
{отключение контроля ввода/вывода}
reset (F,'C:\TP7\BIN\Text.txt');
{открытие файла для чтения}
if IOResult <> 0
then
writeln ('Ошибка при открытии файла');
{$I+}
{включение контроля ввода/вывода}
В своих программах Вы должны применять функцию IOResult.
Задание. Выберите с учителем одну из предложенных ниже задач.
1. Создайте файл целых чисел (числа вводятся с клавиатуры). Поменяйте местами первый и третий элементы файла,
используя в программе процедуру Seek. Выведите на экран содержимое первоначального и измененного файлов.
Предусмотрите в программе вывод соответствующего сообщения, если в файле не оказалось третьего элемента.
2. Создайте файл целых чисел (числа вводятся с клавиатуры). Выведите числа
- с четным порядковым номером,
- с нечетным порядковым номером,
- с порядковым номером, кратным 7,
- с порядковым номером, кратным 15,
используя в программе процедуру Seek.
Предусмотрите в программе вывод соответствующего сообщения, если в файле не оказалось нужных элементов.
3. Создайте файл символов (символы вводятся с клавиатуры). Выведите на экран символы
- с пятого по пятнадцатый,
- с третьего по двадцатый,
- с k-го по s-ый.
Используйте в программе процедуру Seek.
Предусмотрите в программе вывод соответствующего сообщения, если в файле не оказалось нужных элементов.
4. Создайте файл, содержащий все буквы русского алфавита. Запросите у пользователя числовой промежуток [N, M].
Выведите на экран все символы, коды которых лежат в заданном промежутке. Используйте в программе процедуру Seek.
Предусмотрите в программе вывод соответствующего сообщения, если в файле нет символов, коды которых лежат в
заданном промежутке.
5. Создайте файл, состоящий из строк. Запросите у пользователя порядковые номера двух строк и поменяйте их в файле
между собой. Дополнительный файл не создавайте. Используйте в программе процедуру Seek.
Предусмотрите в программе вывод соответствующего сообщения, если в файле не оказалось нужных строк.
6. Создайте файл произвольно выбранного типа. Введите в него некоторое количество элементов. С помощью функции
FileSize разделите файл на заданное количество частей и соедините их в другом порядке во вновь созданном файле.
Содержимое файлов выведите на экран.
7. Создайте файл символьного типа. Используя содержимое этого файла, создайте файл строкового типа. Содержимое
файлов выведите на экран.
8. Создайте файл строкового типа. Используя содержимое этого файла, создайте файл символьного типа. Содержимое
файлов выведите на экран.
9. Создайте файл, содержащий буквы русского и латинского алфавита. Используя содержимое этого файла, создайте
файл кодов символов. Содержимое файлов выведите на экран.
10. Создайте файл типа Integer. Введите в него некоторое количество элементов. С помощью функции FilePos определяя
позицию указателя на элемент файла, запишите во вновь созданном файле элементы файла и соответствующие им позиции
указателя. Содержимое файлов выведите на экран.
Занятие 3. Самостоятельное решение задач
I Выберите с учителем одну из предложенных ниже задач (тип Integer, real)
1. Создайте файл f целых чисел от А до В (значения вводятся с клавиатуры). Проанализировав в программе созданный
файл, создайте еще 3 файла:
- содержащий отрицательные числа,
- содержащий положительные числа,
157
- содержащий нуль.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
2. Создайте файл f целых чисел от А до В (значения вводятся с клавиатуры). Проанализировав в программе созданный
файл, создайте еще 3 файла:
- содержащий неположительные числа,
- содержащий четные числа,
- содержащий нечетные числа.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
3. Вводя числа с клавиатуры и анализируя их в программе создайте два файла: файл положительных чисел и файл
неотрицательных чисел. Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего
сообщения, если элементов в каком либо файле не оказалось.
4. Создайте файл f целых чисел (значения вводятся с клавиатуры). Проанализировав в программе созданный файл,
создайте файл, содержащий суммы первого и (k div 2)-го числа, второго и (k div 2+1)-го числа, третьего и (k div 2+2)-го числа
и так далее. Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
5. Создайте файл f целых чисел (значения вводятся с клавиатуры). Проанализировав в программе созданный файл,
создайте файл, содержащий произведение первого и k-го числа, второго и (k-1)-го числа, третьего и (k-2)-го числа и так
далее. Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
6. Создайте файл f целых чисел (числа вводятся с клавиатуры). Проанализировав в программе созданный файл, создайте
отсортированый файл:
- по возрастанию,
- по убыванию,
- по невозрастанию,
- по неубыванию.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод сообщения, если файл уже был упорядочен.
7. Создайте файл f действительных чисел от А до В с шагом х (значения вводятся с клавиатуры). Проанализировав в
программе созданный файл, создайте еще 3 файла:
- содержащий неположительные числа,
- содержащий числа с нулевой дробной частью,
- содержащий модули чисел.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
8. Создайте файл f действительных чисел от А до В с шагом х (значения вводятся с клавиатуры). Проанализировав в
программе созданный файл, создайте два файла:
- содержащий целые части числа,
- содержащий дробные части чисел.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
9. Создайте два файла действительных чисел. Проанализировав в программе созданные файлы, создайте файл,
содержащий суммы соответствующих чисел файлов.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
10*. Создайте два файла действительных чисел. Проанализировав в программе созданные файлы, создайте файл
строкового типа, содержащий суммы соответствующих чисел файлов в виде 2.5+3.4=5.9.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если
элементов в файле не оказалось.
II Выберите с учителем одну из предложенных ниже задач (тип char)
1. Создать файл произвольных символов. Удалить из файла каждый второй символ. Вывести на экран начальное и
конечное содержимое файла. Предусмотрите в программе вывод соответствующего сообщения, если элементов в файле не
оказалось.
158
2. Создать файл произвольных символов. Вывести на экран содержимое файла. Каждую пятерку символов вывести
перевернутой в другой файл. Вывести на экран содержимое полученного файла.
3. Создать файл произвольных символов. Вывести в один файл цифры, содержащиеся в файле, а в другой файл литеры,
сохранив первоначальный порядок. Вывести на экран содержимое файлов. Предусмотрите в программе вывод
соответствующего сообщения, если нужных символов в файле не оказалось.
4. Создать файл произвольных символов. Вывести в один файл цифры в порядке возрастания, а в другой файл литеры в
алфавитном порядке. В файлах не должно быть повторений цифр и литер. Вывести на экран содержимое файлов.
Предусмотрите в программе вывод соответствующего сообщения, если нужных символов в файле не оказалось.
5. Создать файл произвольных символов. Создать файл символов, встречающихся в заданном файле один раз. Вывести
на экран содержимое файлов.
6. Создать файл произвольных символов. Проанализировав файл в программе, переписать в конец исходного файла все
знаки препинания и посчитать их количество. Вывести на экран содержимое файлов. Предусмотрите в программе вывод
соответствующего сообщения, если нужных символов в файле не оказалось.
7. Создать файл произвольных символов. Удалить из файла элементы, находящиеся между первой и второй точками.
Выведите на экран содержимое файла. Предусмотрите в программе вывод соответствующего сообщения, если элементов в
файле не оказалось.
8. Создать файл произвольных символов. Заменить в нем каждую из групп стоящих рядом точек одной звездочкой.
Дополнительный файл не создавать. Выведите на экран содержимое файла. Предусмотрите в программе вывод
соответствующего сообщения, если ни одной группы точек в файле не оказалось.
9. Создать файл произвольных символов. Найти длину наибольшей последовательности упорядоченных по возрастанию
символов и скопировать эту последовательность в другой файл. Выведите на экран содержимое файла.
10. Создать файл произвольных символов. Все найденные программой буквы русского алфавита перенести в начало
файла, а цифры – в конец. Все символы, не являющиеся буквой русского алфавита или цифрой, переписать в другой файл.
Выведите на экран содержимое файлов. Предусмотрите в программе вывод соответствующего сообщения, если нужных
символов в файле не оказалось.
III Выберите с учителем одну из предложенных ниже задач (тип string)
1. По введенной дате рождения (день и месяц, форма ввода в файл произвольная) дополнить файл строками
соответствующего знака Зодиака:
20.01-18.02 – Водолей
19.02-20.03 - Рыбы
21.03-19.04 – Овен
20.04-20.05 – Телец
21.05-21.06 – Близнецы
22.06-22.07 – Рак
23.07-22.08 – Лев
23.08-22.09 – Дева
23.09-22.10 – Весы
23.10-22.11 – Скорпион
23.11-21.12 – Стрелец
22.12-19.01 – Козерог
2. Создать файл, содержащий произвольные строки. Обработать строки таким образом, чтобы между словами не было
больше одного пробела и выполнить правое выравнивание строк файла. Обработанный текст записать в новый файл.
Вывести на экран его содержимое.
3. Создать файл, содержащий произвольные строки. Запросите произвольное слово, посчитайте количество таких слов в
файле и замените их на другое введенное пользователем слово. Вывести на экран содержимое первоначального и
измененного файлов.
4. Создать файл, содержащий произвольные строки. Поменяйте строки файла так, чтобы их порядок был следующим:
1,к,2,к-1,3,к-2,4,к-3,5,к-4,...к/2.
Вывести на экран содержимое первоначального и измененного файлов.
5. Создать файл, содержащий произвольные строки. Поменяйте строки файла так, чтобы их порядок был следующим:
2,1,4,3,6,5,...
Вывести на экран содержимое первоначального и измененного файлов.
6. Создать файл, содержащий произвольные строки. Поменяйте строки файла так, чтобы их порядок был следующим:
к-1,к,к-3,к-2,к-5,к-4,...
7. Создать файл, содержащий строки, представляющие собой арифметические выражения, состоящие из чисел, знаков
арифметических действий{+,-,*,/} и открывающихся и закрывающихся круглых скобок. Проверьте его корректность.
8. Создать файл, содержащий произвольные строки. Отсортируйте файл по возрастанию длин строк. Вывести на экран
содержимое первоначального и измененного файлов.
9. Создать файл, содержащий произвольные строки. Отсортируйте файл по возрастанию длин строк и каждую строку по
возрастанию длин слов. Вывести на экран содержимое первоначального и измененного файлов.
159
10. Создать файл, содержащий произвольные строки. Проверить правописание сочетаний жи-ши, ча-ща, чу-щу. Если
найдены ошибки, исправить их и подчеркнуть исправленный слог. Вывести на экран содержимое первоначального и
измененного файлов.
IV Выберите с учителем одну из предложенных ниже задач (тип record)
1. Составьте список группы спортсменов, участвовавших в гонках на спортивных машинах, включающей N человек.
Для каждого гонщика укажите фамилию, имя, название страны, номер автомашины, наличие наград на предыдущих
состязаниях, результаты гонки. Информацию о каждом спортсмене оформите в программе в виде записи. Совокупность
записей объединить в файл. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде
таблицы, а также распечатайте анкетные данные спортсменов,
а) показавших лучший результат;
б) показавших три лучших результата,
в) не получивших ни одного призового места.
2. Составьте прайс-лист магазина "Техника", включающий в себя наименования товара, марку предприятияпроизводителя, страну-производитель, его цену, количество единиц товара на складе. Информацию о каждом виде товара
оформите в программе в виде записи. Совокупность записей объедините в файл. Составьте программу, которая обеспечивает
ввод полученной информации, распечатку ее в виде таблицы. Выведите на экран меню, а затем информацию о товаре в
зависимости от запроса покупателя.
3. Составить список учебной группы, включающей N человек. Для каждого учащегося указать дату рождения, год
поступления в техникум, курс, группу, оценки каждого года обучения. Информацию о каждом учащемся оформить в
программе в виде записи. Совокупность записей объединить в файл. Составить программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать список студентов, фамилии которых
начинаются на буквы Б и В, и их оценки за последнюю сессию.
4. Составьте список учебной группы, включающей N человек. Для каждого учащегося укажите фамилию, имя, отчество,
дату рождения, год поступления в ВУЗ, факультет, отделение, курс, группу. Информацию о каждом учащемся оформите в
программе в виде записи. Совокупность записей объедините в файл. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатать по выбору пользователя анкетные данные
студентов нужного курса.
5. Составьте список учебной группы, включающей N человек. Для каждого учащегося укажите фамилию, имя, отчество,
дату рождения, год поступления в ВУЗ, факультет, отделение, курс, группу. Информацию о каждом учащемся оформите в
программе в виде записи. Совокупность записей объедините в файл. Составьте программу, которая обеспечивает ввод
полученной информации, распечатку ее в виде таблицы, а также распечатайте по выбору пользователя анкетные данные
студентов нужного факультета.
6. Составьте список учебной группы школы юного программиста, включающей N человек. Для каждого учащегося
укажите фамилию, имя, отчество, название общеобразовательной школы, класс, год поступления в школу, количество
сданных зачетов. Информацию о каждом учащемся оформите в программе в виде записи. Совокупность записей объединить
в файл. Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте по выбору пользователя анкетные данные учащихся, сдавших нужное количество зачетов.
7. Составьте список учебной группы школы юного программиста, включающей N человек. Для каждого учащегося
укажите фамилию, имя, название общеобразовательной школы, класс, количество сданных зачетов, оценку за итоговый
экзамен. Информацию о каждом учащемся оформите в программе в виде записи. Совокупность записей объединить в файл.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте анкетные данные учащихся, успешно сдавших экзамен.
8. Составьте список группы спортсменов, занимающихся легкой атлетикой, включающей N человек. Для каждого
спортсмена укажите фамилию, имя, название общеобразовательной школы, класс, результаты по следующим дисциплинам:
- бег 100м,
- бег 3000м,
- прыжки в высоту,
- прыжки в длину,
- прыжки с шестом,
- метание ядра,
- метание копья,
- метание диска.
Информацию о каждом спортсмене оформить в программе в виде записи. Совокупность записей объединить в файл.
Составить программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатать анкетные данные спортсменов, занявших 1 место по каждой дисциплине.
9. Составьте список группы спортсменов, участвовавших в соревнованиях по плаванию, включающей N человек. Для
каждого пловца укажите фамилию, имя, название общеобразовательной школы, класс, результаты по следующим
дисциплинам:
- кроль на груди,
160
- кроль на спине,
- баттерфляй,
- комплексное плавание.
Информацию о каждом спортсмене оформите в программе в виде записи. Совокупность записей объедините в файл.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатайте анкетные данные спортсменов,
а) занявших 1 место по каждому стилю плавания;
б) показавших лучшее время по всем видам плавания,
в) не получивших ни одного призового места.
10. Составьте список группы спортсменов, участвовавших в соревнованиях по спортивной гимнастике, включающей N
человек. Для каждого гимнаста указажите фамилию, имя, название общеобразовательной школы, класс, результаты по
следующим видам:
- кольца,
- брусья,
- перекладина,
- вольные упражнения,
- прыжки на дорожке,
- прыжки через коня.
Информацию о каждом спортсмене оформить в программе в виде записи. Совокупность записей объединить в файл.
Составьте программу, которая обеспечивает ввод полученной информации, распечатку ее в виде таблицы, а также
распечатать анкетные данные спортсменов,
а) показавших лучший результат по каждому виду;
б) показавших лучший результат по всем видам многоборья,
в) не получивших ни одного призового места.
Задание. (на усмотрение учителя) Познакомившись с содержанием предыдущих задач придумайте свою интересную
задачу и решите ее.
Занятие 4. Процедуры и функции работы с файлами. Решение задач
Изменение имени файла производится процедурой
rename(МуFilе, FileName);
первый аргумент которой – переменная файлового типа, а второй аргумент – строкового типа – новое имя файла,
которое может быть сокращенным или полным (с указанием пути). Действие этой процедуры эквивалентно действию
аналогичной процедуры DOS.
Уничтожение части файла от текущего положения до конца производится процедурой
truncate(МуFilе).
Уничтожение всего файла производится процедурой
erase(МуFilе),
действие которой эквивалентно удалению файла в операционной системе DOS.
Примечание. Физические файлы на магнитных дисках и переменные файлового типа в программе на Паскале – объекты
различные. Переменные файлового типа в Паскале соответствуют не только физическим файлам, но и логическим
устройствам, связанным с вводом и выводом информации. Клавиатуре и экрану дисплея соответствуют файлы со
стандартными именами Input и Output.
Задание. Рассмотрите предложенный ниже текст программы. Сформулируйте решенную задачу. Создайте расширенный
вариант подобной задачи. результат покажите учителю для оценки.
Program Files;
Uses
Crt;
Var
F,Fnew : file of string;
Name,NewName : string[12];
Text : string;
Ch : char;
Procedure ReadText;
Begin
161
repeat
write('Введите имя файла>');
readln(Name);
assign(F,Name);
reset(F);
if IOresult<>0
then
begin
writeln('Ошибка чтения');
close(F);
end;
until IOresult=0;
writeln('Содержание файла ',Name,':');
while not Eof(F) do
begin
readln(F,Tеxt);
writeln(Tеxt);
end;
close(F);
End;
Procedure EraseFile;
Begin
erase(F);
writeln('Файл удален');
End;
Procedure ReNameFile;
Begin
write('Введите новое имя файла:');
readln(NewName);
rename(F,NewName);
writeln('Файл ',Name,' переименован в файл ',NewName);
End;
Procedure CopyFile;
Begin
write('Введите имя копии файла ',Name,'>');
readln(NewName);
reset(F);
assign(Fnew,NewName);
rewrite(Fnew);
while not Eof(f) do
begin
readln(F,Text);
writeln(Fnew,Text);
end;
close(F);
close(F_new);
writeln('Файл',Name,' скопирован в файл ',NewName);
End;
Begin
ClrScr;
readTеxt;
repeat
writeln('Удаление файла (D),переименование файла(R)');
writeln('Копирование файла (C), выход из программы (Е)');
write('Введите символ нужной операции - ');
readln(ch);
case ch of
'D','d': EraseFile;
'R','r': ReNameFile;
'C','c': CopyFile;
end;
until (ch='E') or (ch='e');
162
read;
End.
Выберите с учителем одну из предложенных ниже задач
1. Даны два отсортированных типизированных файла (тип выбрать произвольно). Получить новый типизированный
файл слиянием двух исходных в отсортированном виде. Алгоритм слияния должен предусматривать, что исходные файлы
могут содержать очень большое число элементов.
2. Проверить, является ли один типизированный файл частью другого. Если является, то его распечатать на принтере.
3. Сделать один типизированный файл частью другого, начиная с N-ой позиции (N задает пользователь).
4. Один типизированный файл вставить в другой, чередуя элементы обоих файлов. Элементы вставляемого файла
начинайте вводить с конца файла.
5. Сравнить содержание файлов. Количество сравниваемых файлов задает пользователь.
Приготовьте листинги решенных и проверенных учителем задач. Проверьте свои знания, ответив на ниже следующие
вопросы.
Контрольные вопросы
1. Что называется файлом? как его описать в программе?
2. Какие действия можно производить с файлами?
3. Как записать файл? Какие процедуры или функции надо применить? Как производится запись?
4. Как прочитать файл? Какие процедуры или функции используются? Как происходит чтение данных из файла?
5. Как закончить работу с файлом?
6. Как обратиться к компоненте с заданным номером?
7. Как подсчитать, сколько элементов в данном файле?
8. Верно ли, что элементы файла должны быть одного типа и что файл отличается от массива только тем, что размер
(количество элементов) файла произволен, а размер массива фиксирован?
9. Можно ли, считав из файла пятый элемент, затем сразу же считать второй? Если нет, то какой можно?
10. Верно ли, считав из файла пятый элемент, затем уже никогда нельзя считать его второй элемент?
11. В какое место файла можно добавлять новые элементы: в начало, в середину, в конец, куда угодно, никуда?
12. Если не переписывать файл заново, то значения каких его элементов можно менять: только первого, только
последнего, каких угодно, никаких? А какие элементы можно удалять?
13. Верно ли, что в одно и то же время нельзя считывать из файла и записывать в него? верно ли, что, начав считывать
из файла, затем уже никогда нельзя записывать в него? А наоборот?
14. Можно ли сравнивать файлы или присваивать один файл другому?
163
ТEКСТОВЫЕ ФАЙЛЫ
Занятие 1. Тeкстовые файлы, их описание и основные отличия от типизированных файлов.
Наряду с описанными типами файлов Pascal имеет средства взаимодействия с файлами несколько иной структуры–так
называемыми текстовыми файлами. Введение текстовых файлов несколько нарушает стройность языка, однако позволяет
использовать Pascal при программировании широкого класса задач, имеющих нечисловой характер и связанных с
обработкой текстовой информации.
Во многих версиях языка допускается хранение файлов на диске как символьных данных. При считывании файла в
оперативную память машины символы файла преобразуются в тот тип данных, который объявлен в программе. Файлы
символьных данных называются текстовыми файлами. Текстовые файлы имеют тип text.
Структура текстовых файлов отличается от структуры обычных файлов (которые представляют из себя линейную
последовательность элементов одного типа) тем, что содержимое текстового файла рассматривается как последовательность
строк переменной длины, разделённых специальной комбинацией, называемой "конец строки". Как правило, эта комбинация
строится из управляющего кода "перевода каретки" (CR, Carriage Return, символ #13), за которым, возможно, следует
управляющий код "перевод строки" (LF, Line Feed, символ #10). Признаком конца строки считается нажатие клавиши ввода.
Текстовый файл завершается специальным кодом "конец файла" (символ #26). В большинстве случаев знание
конкретной кодировки управляющих символов не обязательно ввиду наличия файловых операций, автоматически
учитывающих эти символы.
Таким образом, текстовый файл структурно несколько похож на "файл из байтов" (file of byte) с той разницей, что в нем,
помимо содержательной информации, встречаются символы специального назначения.
Его можно схематически представить в следующем виде:
. . . . . . . . . . . . . .#13#10
. . . . . . . . . . . . . . . . . . . .#13#10
. . . . . . . . . . . . . . . . .#13#10
. . . . . . . . . . . .#13#10
. . . . . . . . . . . . . . . . . . . . . . . . . .#13#10
#26
Описанная структура текстовых файлов хорошо согласуется с интуитивно понимаемым построением текстовой
информации и полностью совпадает со стандартной структурой текстов, принятой в MS-DOS, используемой во многих
текстовых редакторах, понимаемой компиляторами с языков программирования и т.д.
С каждым файлом на диске должна быть связана файловая переменная, которая описывается в соответствии с типом
файла на диске. Представителем же текстового файла в Pascal-программе является переменная файлового типа, которая
должна быть описана с указанием стандартного типа text:
Var
TextFile : text;
Примечание. Слово text не является зарезервированным словом, а считается идентификатором стандартного типа,
наряду с идентификаторами integer, real и т.д.
Обращение к файлу в дальнейшем идёт через файловую переменную.
Далее доступ к файлу требуется открыть. Открыть любой файл можно на чтение и на запись. Для этого существуют
процедуры reset, rewrite.
К примеру, пусть на диске создан текстовой файл text.txt.
Для Turbo Pascal описание и связывание файловой переменной f с файлом text.txt, будет выглядеть так :
Var
f: text;
Begin
assign(f, 'd:\tp7\bin\text.txt'); {Полный путь до файла }
reset(f);{Открыть на чтение]
...
End.
assign([файл. пер. ], [полный путь до файла на диске])–связывает файл на диске с файловой переменной f типа текст.
Примечание. Процедура assign не должна использоваться для открытого файла.
Когда имя файла на диске не указывается, то параметр f оказывается связанным со стандартным вводом/выводом. Если
присвоено пустое имя, то после обращения к reset(f) f будет указывать на стандартный файл ввода, а после обращения к
rewrite(f) f будет указывать на стандартный файл вывода.
164
reset([ файловая переменная ]); –открывает файл на чтение.
Ввод-вывод для текстовых файлов подчиняется тем же общим правилам, что и для обычных типизированных файлов;
однако имеется несколько важных особенностей.
Во-первых, для одного текстового файла нельзя одновременно производить операции и ввода, и вывода. Это означает,
что после открытия текстового файла процедурой reset возможно только чтение информации из файла, после процедуры
rewrite – только запись в файл.
Во-вторых, обмены с текстовыми файлами всегда являются строго последовательными, то есть после чтения из файла
элемента с порядковым номером N следующая операция чтения даст элемент с номером N+1. Иными словами, прямой
доступ к любому элементу текстового файла невозможен; для текстовых файлов не допускаются вызовы Seek, FilePos,
FileSize.
Под чтением файла понимают ввод данных из внешнего файла, находящегося на диске, в оперативную память машины.
Данные файла становятся доступными программе. Внешний файл, из которого читаются данные, часто называют входным
файлом.
Базовой техникой обменов с текстовыми файлами является посимвольный ввод-вывод. При этом производится чтение
или запись всех символов, как информационных, так и специальных.
Покажем простую программу, выполняющую чтение некоторого текста. Эта программа выводит на экран
последовательность кодов символов, составляющих файл text.txt.
Program TextFile1;
Var
f : text; {Читаемый текст}
S : char; {Очередной прочитанный символ}
Begin
assign(f, 'text.txt'); {Связываем файл text.txt с переменной f}
reset(f,); {Открываем файл text.txt для чтения}
while not Eof(f) do{Пока нет конца файла делай...}
begin
readln(f, S);{Читаем из файла очередной символ в переменную а}
writeln(a);{Печатаем код символа на экран}
end;
close(f);{Закрываем файл}
readln
End.
Задание. Наберите текст программы и запустите программу на выполнение. Просмотрите результат работы программы.
Найдите выведенные на экран коды специальных символов.
Еще одной особенностью работы с текстовыми файлами является возможность непосредственных обменов значениями
различных базовых типов (для обычных типизированных файлов тип параметров read и write должен совпадать с базовым
типом файла). Так, в текстовый файл можно записать6 например, целое или вещественное число. При этом его внутреннее
представление будет автоматически преобразовано в строчку символов, образующих изображение этого числа.
Рассмотрите простую программу, выполняющую чтение из текстового файла целых чисел и вывод на печать только
четных чисел.
Program TextFile2;
Var
f : text;
Put : string;
a : integer;
Begin
Put := 'D:\TP7\BIN\Primer2'; {Полный путь до файла }
assign(f, Put); {Связываем файл с переменной f}
reset(f); {Открываем файл на чтение.}
while not Eof(f) do{Пока нет конца файла делай...}
begin
readln(f, a);{Считываем число в переменную а}
if not odd(a) {Если число нечетное,}
then
writeln(a);{То выводим его на экран}
end;
close(f);
readln
End.
Задание. Напишите программу, с помощью которой можно сформировать текстовый файл, содержащий
165
- значения целого типа;
- значения вещественного типа;
- значения булева типа.
Для описанных выше случаев записи произвольной информации в текстовый файл в языке имеются дополнительные
возможности, которые заключаются в задании размера поля записи. Если после записываемой переменной или выражения
поместить символ двоеточия, а после него – любое выражение целого типа, то для выводимого значения будет отведено
поле, размер которого (число символов) будет равен значению выражения. Следующая тривиальная программа наглядно
показывает действие указателя поля:
Program TextFile3;
Var
f : text;
V : real;
i : word;
Put : string;
Begin
Put := 'D:\TP7\BIN\Primer3'; {Полный путь до файла }
assign(f, Put); {Связываем файл с переменной f}
rewrite(f); {Открываем файл на запись}
V := 123.456;
write(f, V,#13#10);{выводим без указателя поля на экран}
for i := 8 to 12 do
write(f, V:i,#13#10);{динамически изменяем размер поля}
close(f);
End.
Задание. Наберите программу, дополните ее выводом содержимого текстового файла на экран. Проанализируйте
полученные результаты выполнения программы.
Управление размещением значений в текстовых файлах очень удобно при формировании структурированных файлов
(списков, таблиц и т.п.), так как если изображение значения меньше размера поля, то оно всегда "прижимается" к его
правому краю.
Кроме того, для вещественных типов имеется дополнительная возможность, позволяющая выводить число в формате с
фиксированной точкой, что более наглядно по сравнению с форматом с плавающей точкой, который предусмотрен по
умолчанию. Если после указателя размера поля задать через двоеточие еще одно выражение целого типа, то оно будет
интерпретироваться как указание числа позиций для дробной части числа.
Занятие 2. Способы обмена с текстовыми файлами.
На этом занятии мы обобщим уже известные операции чтения и записи текстовых файлов и остановимся на
специфичных операциях обмена информацией между программой и текстовым файлом.
Операции чтения из файла
reset(f) - открывает существующий файл на чтение. Файловая переменная должна быть связана с внешним файлом с
помощью процедуры assign.
Если существующий файл уже открыт, то он закрывается, а затем открывается вновь. Текущая позиция в файле
устанавливается на начало файла.
Если f было присвоено пустое имя (например, assign((f),' '), то после обращения к процедуре Rezet(f) будет ссылкой на
стандартный файл ввода (канал 0).
Текстовой файл становится доступным только по чтению.
При указании директивы компилятора {$I–} функция IoResult будет возвращать значение 0 в том случае, если операция
завершилась успешно, и ненулевой код ошибки в противном случае.
readln([f : text],[v1,v2,....vn]) – выполняет процедуру read, затем переходит к следующей строке файла.
Процедура readln является расширением процедуры read и определена для текстовых файлов. Вызов readln(f) без
параметров приводит к перемещению текущей позиции файла на начало следующей строки, если она имеется, в противном
случае происходит переход к концу файла. Процедура readln без параметров полностью соответствует стандартному вводу.
При указании директивы компилятора {$I-} функция IoResult будет возвращать значение 0 в том случае, если операция
завершилась успешно, и ненулевой код ошибки в противном случае.
Примечание: Функция работает только для тектовых файлов, включая стандартный ввод. Файл должен быть открыт для
ввода.
166
Процедура readln является очень удобным аналогом read. В случае использования readln после чтения из файла
очередной порции символов (и, быть может, преобразования их в значение подходящего типа) текущий указатель файла
будет перемещен на начало его следующей строки. Иными словами, часть строки после прочитанного значения будет
пропущена.
Очень часто используется следующий способ чтения из текстового файла. В качестве параметра процедуры readln
задается переменная типа string; в этом случае вся очередная строка файла целиком считывается в поданную переменную,
длина которой автоматически устанавливается равной длине считанной строки. Полученная из файла строка далее может
быть обработана так, как это необходимо. Важно отметить, что при таком способе производится чтение только "значащих"
символов строки; завершающиеся символы в данном случае играют роль межстрочных разделителей и не считываются в
строковую переменную. После чтения строки текущий указатель файла устанавливается на начало следующей строки.
Операции записи в файл
rewrite(f) - cоздаёт и открывает новый файл. Файловая переменная должна быть связана с внешним файлом с помощью
процедуры assign.
Если внешний файл уже существует, то он удаляется и на его месте создаётся новый пустой файл. Если файл уже
открыт, то он закрывается, а затем открывается вновь.Текущая позиция в файле устанавливается на начало файла.
Если f было присвоено пустое имя (например, assign((f),' '), то после обращения к процедуре rewrite(f) будет ссылкой на
стандартный файл вывода (канал 1).
Текстовой файл становится доступным только по записи.
write([f : text],[v1,v2,....vn]) – записывает одно или более значений из одной или более переменных в текстовой файл.
Если параметр f не указан, то подразумевается использование стандартной файловой переменной Output. Каждый
параметр v является вводимым выражением, значение которого должно быть записано в файл. Каждое вводимое выражение
должно быть символьного, целого, вещественного, строкового или булевого типа.
Параметр v имеет вид:
<вводимое выражение : мин.размер : десятичных знаков>
Например:
Var
a:real;
.......
write(f, a: 5: 2)
Такая запись означает, что мы в файл записываем действительное (не целое) число а, размером 5 знаков, 2 знака под
дробную часть.
writeln([f : text],[v1,v2,....vn]) – выполняет процедуру write, а затем записывает в файл метку конца строки (перевод
строки).
При вызове данной процедуры без параметров writeln(f), в файл записывается метка конца строки. Процедура writeln без
параметров полностью соответствует стандартному выводу на экран.
Примечание: файл должен быть открыт для вывода.
Логическая функция Eoln
Часто для обработки текстовых файлов используется специфичная для них функция Eoln, позволяющая определить
достигнут ли конец строки. Если достигнут – значение функции равно True, а если нет – False. Таким образом, для анализа
конкретных символов строк файла можно применить вложенный цикл типа:
while not Eof(NameFale) do {пока нет конца файла NameFale делай}
while not Eoln(NameFale) do {пока нет конца строки файла NameFale делай}
begin
{группа операторов обработки символов очередной строки}
end;
Процедура открытия файла для дополнения
append(f : Тext) – процедура открывает существующий файл для присоединения. Если файл уже открыт, то он сначала
закрывается, а затем открывается заново. Текущая позиция устанавливается на конец файла.
Если в последнем блоке файла размером 128 байтов присутствует символ Сtrl+Z (26 в коде ASCII), то текущая позиция
устанавливается в файле таким образом, что при записи первым в блоке будет "затираться" символ Сtrl+Z.
Если переменной f было присвоено пустое имя assign(f,' '), то после обращения к процедуре append f будет указывать на
стандартный выходной файл.
167
После обращения к append файл f становится доступным только по записи и Eof(f) принимает всегда значение
True(истина).
Рассмотрите несколько примеров простых программ.
Program TextFile4;
{Задача. Дан файл Primer1 на диске. Считать из него информацию и записать во вновь созданный файл Primer2 }
Var
f, t: text;
Put1, Put2, d: string;
s : char;
Begin
Put1 := 'D:\TP7\BIN\Primer1';{Путь до файла Primer на диске}
assign(f, Put1 );
reset(f);{Открыть файл c файловой пер. f на чтение }
Put2 := 'D:\TP7\BIN\Primer2';{Путь где будет создан файл}
assign(t, Put2);
rewrite(t);{ Открыть файл c файловой пер. t на создание и запись }
while Not Eof(f) Do
begin
while Not Eoln(f) do
begin
read(f, s); {Cчитывать из f в переменную s}
write(t, s);{ Записывать в t значение s}
end;
readln(f); {Переходим к чтению следующей строки файла f}
writeln(t);{Переходим к записи следующей строки файла t}
end;
close(t);{Закрытие файла Primer1}
close(f);{Закрытие файла Primer2}
End.
Program TextFile5;
{Задача. Дан файл Primer2 со скобками. Проверить численное соответствие закрытых и открытых скобок}
Var
f : Тext;
Put, s : string;
a, i : integer;
Begin
a := 0; {Обнуляем счетчик скобок}
Put := 'D:\TP7\BIN\Primer2'; {Полный путь до файла }
assign(t, Put);
reset(f); {Открываем файл на чтение.}
while Not Eof(f) do {Пока нет конца файла делай...}
begin
readln(f, s); {Считываем cтроку в переменную s}
for i := 1 to Length(s) do {Просматриваем строку до конца}
begin
if s[i] = '(' {Если встретилась открытая скобка,}
then
Inc(a,1);{то счетчик увеличиваем на 1}
if s[i] = ')' {Если встретилась закрытая скобка,}
then
Dec(a,1);{то счетчик уменьшаем на 1}
end;
end;
close(f);{Закрытие файла}
if a <> 0{Если скобок одинаковое кол-во, то а=0}
then
writeln('No')
else
writeln('Yes');
readln
End.
Program TextFile6;
{Задача. Проиллюстрировать работу процедуры append.}
Var
f: text;
168
Begin
assign(f, 'text.txt'); {создаем текстовый файл}
rewrite(f);{ Открыть файл c файловой пер. t на создание и запись }
writeln(f, 'Исходный текст');{ Записывать в него cтроку}
close(f);{Закрываем сформированный файл}
append(f); {Вновь открываем этот же файл для добавления}
writeln(f, 'Добавляемый текст');{ Пишем в конец файла cтроку}
close(f);{Закрываем файл}
End.
Задачи для самостоятельной работы
1. Создать текстовый файл, содержащий произвольное количество гласных букв русского алфавита. Длину каждой
строки должен определять пользователь. Просчитать количество символов каждой буквы и дописать в файл полученную
информацию.
2. Создать текстовый файл, содержащий произвольное количество букв русского алфавита. Длину каждой строки
должен определять пользователь. Просчитать количество символов гласных и согласных букв и дописать в файл полученную
информацию.
3. Создать текстовый файл, содержащий произвольное количество символов. Длину каждой строки должен определять
пользователь. Просчитать количество символов каждой буквы русского алфавита и дописать в файл полученную
информацию.
4. Создать текстовый файл, содержащий произвольное количество символов. Длину каждой строки должен определять
пользователь. Просчитать количество цифр и дописать в файл полученную информацию.
5. Создать текстовый файл, содержащий произвольное количество символов. Длину каждой строки должен определять
пользователь. Просчитать количество символов каждой буквы латинского алфавита и дописать в файл полученную
информацию.
Занятие 3. Стандартные текстовые файлы Input и Output. Примеры задач
В Паскале существуют два стандартных текстовых файла Input и Output. Эти файлы считаются известными в любой
Pascal-программе (иными словами, они описаны в стандартном модуле System). Они обозначают (по терминологии MS-DOS)
соответственно стандартный файл ввода и стандартный файл вывода. Обычно эти стандартные файлы связаны с
конкретными физическими устройствами компьютера. Так, файловая переменная Input связана с клавиатурой, файловая
переменная Output – с экраном дисплея. эти файлы считаются заранее открытыми, а соответствующие идентификаторы
можно использовать в операциях ввода-вывода.
Рассмотрим, например, следующий оператор:
writeln (Output, 'Результат равен ', (X+Y)*2)
В соответствии с общими правилами, этот оператор выведет значения двух последних операндов в текущую строку
заданного файла, а затем произведет переход к следующей строке. В применении к стандартному файлу Output эти действия
будут выглядеть как появление в текущей строчке дисплея литеральных изображений указанных значений, после чего
курсор будет перемещен в первую позицию следующей строки.
Аналогично, оператор read (Input, X1, X2); будет выполняться таким образом: система перейдет в состояние ожидания
ввода с клавиатуры двух значений. Типы вводимых значений должны совпадать с типами переменных Х1 и Х2. Эти значения
при вводе должны отделяться друг от друга одним или несколькими пробелами, а ввод должен быть завершен нажатием
клавиши Enter. В процессе ввода значений набираемые на клавиатуре символы отображаются на экране. После нажатия Enter
введенные значения будут присвоены переменным Х1 и Х2, и выполнение программы будет продолжено.
Для стандартных файлов Input и Output допускается сокращенная форма записи операций ввода-вывода. Так, если в
процедурах read и readln первый параметр опущен, то по умолчанию подразумевается файл Input. Аналогично, отсутствие в
процедурах write и writeln первого параметра означает вывод в стандартный файл Output. Вывод в стандартный файл Output
используется очень часто – всегда, когда необходимо выдать некоторую информацию из программы на экран.
В соответствии с общими правилами MS-DOS стандартные файлы ввода-вывода могут быть "переназначены", то есть
связаны с другими физическими устройствами или дисковыми файлами. Простейшим способом переназначения является
использование для этой цели процедуры assign, например,
assign (Output,'MyFile.out')
После выполнения такого оператора стандартный файл вывода будет переназначен, то есть файловая переменная Output
будет связана с дисковым файлом MyFile.out из текущего каталога. Все операции вывода, явно или неявно работающие с
файлом Output, будут выводить информацию в указанный дисковый файл.
Задание. Рассмотрите предложенные программы, наберите их на компьютере, выделите необходимые части алгоритма в
подпрограммы, сформулируйте решаемые ими задачи, дополните необходимыми операторами и комментарием.
169
Примечание. Если Вы можете решить выше поставленные задачи устно, то поставьте в известность учителя и
приготовьтесь к ответу.
Program StringCount;
Uses
Crt;
Var
i : integer;
s : string;
f : text;
Begin
ClrScr;
readln(s);
assign(f,s);
reset(f);
while not Eof(f) do
begin
readln(f,s);
i:=i+1;
end;
close(f);
readln;
End.
Program Zamen;
Uses
Crt;
Var
s : string;
f, d : text;
Begin
ClrScr;
readln(s);
assign(f,s);
readln(s);
assign(d,s);
reset(f);
rewrite(d);
while not Eof(f) do
begin
readln(f,s);
while Pos('o',s)>0 do
s[Pos('o',s)]:='a';
writeln(d,s);
end;
close(f);
close(d);
readln;
End.
Program MaxInFile;
Uses
Crt;
Var
i, j, r, Code : integer;
s : string;
f : text;
Begin
ClrScr;
readln(s);
assign(f,s);
reset(f);
while not Eof(f) do
begin
readln(f,s);
j:=0;
for i:=1 to Length(s) do
begin
170
Val(s[i],r,Code);
if r>j
then
j:=r;
end;
writeln(j);
end;
close(f);
readln;
End.
Занятие 4. Самостоятельное решение задач
Выберите с учителем задачи для самостоятельного решения из предложенного ниже списка.
1. Посчитать количество строк, находящихся между строками максимальной и минимальной длины текстового файла.
Вывести эти строки на экран в обратном порядке. Если все строки файла одинаковы, вывести на экран соответствующее
сообщение. В программе используйте подпрограммы.
2. Упорядочить лексикографически строки текстового файла. Вывести на экран первоначальный файл и
преобразованный. Если все строки файла одинаковы, вывести на экран соответствующее сообщение. В программе
используйте подпрограммы.
3. Удалите из текстового файла одинаковые строки. Если в файле нет одинаковых строк, вывести на экран
соответствующее сообщение. Вывести на экран первоначальный файл и преобразованный. В программе используйте
подпрограммы.
4. Сформировать текстовый файл, содержащий строки исходного файла, встречающиеся в нем один раз. Вывести
содержимое файлов на экран. В программе используйте подпрограммы.
5. Найти и вывести на экран самое большое симметричное слово текста. Если симметричных слов в тексте нет, вывести
соответствующее сообщение. В программе используйте подпрограммы.
6. В каждом слове текстового файла поменять местами первый и последний символы. Вывести на экран первоначальный
файл и преобразованный. В программе используйте подпрограммы.
7. Сравните соответствующие строки двух текстовых файлов. Если строки совпали, то запишите эту строку в
результирующий текстовый файл. Вывести на экран данные файлы и полученный. Если полученный файл пуст, вывести
соответствующее сообщение. В программе используйте подпрограммы.
8. Создайте текстовый файл, содержащий гласные буквы каждой нечетной строки исходного файла и цифры каждой
четной строки файла. В программе используйте подпрограммы.
9. Создайте текстовый файл, содержащий в начале каждой строки гласные буквы соответствующей строки данного
текстового файла, а в конце строки – согласные буквы. В середине строки расположите все остальные встретившиеся
символы, заключив их в круглые скобки.
11. Удалить из середины каждой строки текстового файла заданное пользователем количество символов. Создайте
текстовый файл, содержащий удаленные символы. Вывести на экран первоначальный файл и преобразованный. В программе
используйте подпрограммы.
12. Для каждого символа текста указать, сколько раз он встречается в тексте и вывести в текстовый файл слово, в
котором этот символ встречается наиболее часто. Если таких слов несколько, вывести
- первое встретившееся,
- последнее встретившееся,
- все слова.
В программе используйте подпрограммы.
13. Проанализировав длины строк текстового файла, объедините соседние строки так, чтобы длина строк файла была в
заданном пользователем промежутке [а, b]. Если строк для объединения нет, предусмотрите в программе вывод
соответствующего сообщения. Вывести на экран первоначальный файл и преобразованный. В программе используйте
подпрограммы.
14. Проанализировав созданный текстовый файл, найдите в нем ошибки на правописание чк-чн, нч-нщ. Создайте
текстовый файл слов с ошибками. Исправьте ошибки в исходном файле. Если ошибок в файле нет, предусмотрите в
программе вывод соответствующего сообщения. Вывести на экран первоначальный файл и преобразованный. При выводе на
экран содержания измененного файла, слова, где была ошибка, высветите красным цветом. В программе используйте
подпрограммы.
171
15. Вывести на экран и в текстовый файл строки данного текстового файла, содержащие одинаковые слова. Если таких
строк нет, предусмотрите в программе вывод соответствующего сообщения. В программе используйте подпрограммы.
Творческое задание. Придумайте собственную задачу по данной теме и решите ее.
Приготовьте листинги решенных и проверенных учителем задач. Проверьте свои знания, ответив на ниже следующие
вопросы.
Контрольные вопросы
1. Что общего в организации работы с текстовыми файлами и типизированными?
2. Какие специфичные для текстовых файлов функции и процедуры Вы знаете?
3. Какую информацию можно хранить в текстовом файле? Сколько способов просмотра текстового файла Вы
использовали?
4. Можно ли, пользуясь средствами Norton Commander создать текстовый файл, который можно было бы обработать в
Паскаль-программе? Если – да, то какое расширение он должен иметь?
5. Какие процедуры и функции модуля CRT Вы применяли в своих программах? С какой целью?
Для любознательных. Текстовый режим. Модуль CRT. Работа с цветом. Работа с экраном и курсором
Средства управления экраном образуют один из важнейших элементов программирования для IBM-совместимых
персональных компьютеров, что обусловлено прежде всего необходимостью организации удобного взаимодействия
программы с ее пользователем. Любая сколько нибудь серьезная программа в настоящее время должна иметь достаточно
развитый и продуманный экранный "видеообраз", с помощью которого реализуется интерфейс с пользователем.
Рассмотрим общие принципы организации отображения информации на экран дисплея. Формирование изображений на
экране производится дисплейным адаптером, который представляет собой специализированный микропроцессор с
собственной памятью, регистрами и наборами команд. Интерфейс с адаптером реализуется ядром операционной системы
(BIOS), который управляет адаптером, записывая значения в его память, устанавливая состояние регистров и инициируя
выполнение команд. Со своей стороны BIOS предоставляет прикладным программам (и операционной системе) возможности
управления дисплейным адаптером посредством функций прерывания 10h (видеосервис). Некоторые из них мы рассмотрим.
Заметим, что память дисплейного адаптера включена в общее пространство компьютера и тем самым доступна
напрямую и для прикладных программ. Данное обстоятельство весьма существенно, так как содержимое этой памяти
непосредственно отображается на экране. Зная правила "кодирования" изображения в памяти адаптера и адреса этой памяти,
можно формировать картину на экране, записывая в оперативную память те или иные значения.
Дисплейная аппаратура ориентирована на два режима работы: текстовый и графический. В текстовом режиме рабочее
пространство экрана рассматривается как совокупность строк, каждая из которых содержит определенное число позиций
(знакомест). В каждой позиции может быть отображен один из 256 стандартных ASCII-символов. Текстовый режим может
иметь несколько вариантов, различающихся количеством и длиной экранных строк (наиболее распространенным является
размер 25 строк по 80 символов в каждой).
Текстовый режим является как сравнительно простым для понимания, так и несложным и эффективным в реализации.
Вместе с тем он сильно ограничен по свои возможностям. Необходимая программная поддержка этого режима со стороны
операционной системы является минимальной и в то же время позволяет разрабатывать развитые и эффективные
интерфейсы.
Модуль CRT
Модуль CRT представляет собой библиотеку функций и процедур, предназначенных для увеличения возможностей
текстового ввода-вывода данных. В отличие от стандартного ввода-вывода, когда он осуществляется через операционную
систему, подпрограммы модуля CRT работают с BIOS, и даже непосредственно с видеопамятью.
Для того чтобы стали доступны находящиеся в модуле процедуры и функции, необходимо явно указать модуль CRT
командой
Uses
Crt;
Модуль CRT сравнительно невелик и содержит средства, позволяющие:
- устанавливать определенный текстовый режим;
- управлять перемещением курсора на экране;
- выводить на экран информацию;
- задавать цветовые атрибуты выводимых символов;
- организовывать простой оконный дизайн экрана.
Кроме этого, в модуле имеются средства взаимодействия с клавиатурой, процедуры элементарного управления звуком, а
также некоторые другие примитивы.
172
Примечание. Относительная компактность модуля CRT находится в очевидном противоречии с весьма широким
спектром возможностей современных адаптеров. Иными словами, за рамками этого модуля остается много средств
управления экраном. Поэтому, практически любая программа с развитой экранной компонентой использует, наряду со
штатными средствами модуля CRT, дополнительные возможности адаптера, не поддерживаемые этим модулем. Многие
сервисные пакеты независимых фирм, ориентированные на Turbo Pascal (например, Power Tools Plus, Object Professional),
содержат расширенные варианты модуля CRT. На следующем занятии мы рассмотрим некоторые дополнительные
возможности управления экраном, существенные в практической работе.
Итак, мы уже знаем, что при работе с экраном через модуль CRT весь экран разбивается на отдельные строки, а каждая
строка на отдельные позиции, в каждую из которых можно поместить один символ. Таким образом экран разбивается на
отдельные прямоугольные элементы.
Рассмотрим допустимые текстовые режимы адаптера и технику их установки в Turbo Pascal- программах.
В общем случае модуль CRT поддерживает пять базовых вариантов текстового режима и еще несколько
дополнительных.
Для установки одного из текстовых режимов предназначена процедура
Procedure TextMode (Mode : word);
где Mode – код текстового режима, который может принимать следующие значения:
- BW40=0 – 40х25 черно-белый режим для цветного адаптера,
- CO40=1 – 40х25 цветной режим для цветного адаптера,
- BW80=2 – 80х25 черно-белый режим для цветного адаптера,
- CO80=3 – 80х25 цветной режим для цветного адаптера,
- MONO=7 – 80х25 монохромный для черно-белого адаптера,
Например,
TextMode (СО80);
TextMode (7);
Перечисленные режимы действительны для двух наиболее распространенных в настоящее время адаптеров VGA и EGA.
Кроме данных режимов, для VGA/EGA-адаптеров допускаются их модификации, дающие возможность увеличит
количество строк, выводимых на экран. Дело в том, что разрешающая способность этих адаптеров (то есть число пикселов
по горизонтали и вертикали) позволяет строить символы в виде матриц пикселов 8х14 (для EGA) и 8х16 (для VGA). Иными
словами, каждый символ строится из 14 или 16 рядов пикселов. Если же использовать для символов сокращенные матрицы
размером 8х8 пикселов, то на экране можно разместить соответственно 43 или 50 строк символов, что дает возможность
выводить на экран значительно больше информации.
Чтобы переключиться на уплотненный режим, необходимо подать в процедуру TextMode модифицированный параметр
– значение требуемого режима, увеличенное на 256. Для удобства и большей наглядности в модуле имеется
соответствующая константа:
- FONT8X8=256 – используется для загружаемого шрифта в режиме 80х43 или 80х50 с адаптерами VGA и EGA.
Рассмотрите пример переключения дисплея в режим цветного отображения с 43/50 строками:
TextMode (СО80+FONT8X8)
Примечание. Многие программные системы допускают возможность настройки на тот или иной режим. В частности,
интегрированная среда Turbo Pascal позволяет устанавливать как обычный, так и уплотненный режимы дисплея
(переключатель Screen sizes диалоговом окне Preferences – команда Options/Environment/Preferences).
При инициализации программы, использующей модуль CRT, значение текстового режима устанавливается
автоматически, исходя из реальной аппаратуры компьютера.Текущее значение установленного режима всегда хранится в
переменной LastMode из интерфейса модуля CRT. Даже в случае переключения в графический режим это значение
сохраняется и может быть использовано для возврата в текстовый режим, например, TextMode (LastMode).
Рассмотрим подробнее процедуры и функции модуля CRT.
Процедуры управления цветом
TextBackGround(Color : byte) – процедура задает цвет фона Color.
TextColor(Color : byte) – процедура задает цвет символов Color.
HighVideo – процедура устанавливает высокую яркость символов (заменяет цвета 0-7 на цвета 8-15), выводимые далее
на экран.
LowVideo – процедура устанавливает малую яркость символов (заменяет цвета 8-15 на цвета 0-7), выводимые далее на
экран.
NormVideo - процедура устанавливает первоначальную яркость символов, выводимые далее на экран.
173
Управление цветом
Использование цвета при разработке видеоинтерфейсов программ, отображение результатов и т.п. является важным
средством повышения удобства работы с программой, улучшения восприятия информации и в конечном итоге служит
повышению производительности труда. Разумное и продуманное использование цвета может заметно повысить
привлекательность программы и более наглядно выявить ее преимущества.
Цветные дисплеи персональных компьютеров позволяют в текстовом режиме выводить информацию на экран,
используя фиксированный набор цветов. Различаются цвета самих символов и цвета фонов символов – областей знакомест,
не занятых символами.Возможно независимое управление цветовыми характеристиками всех знакомест экрана. Базовый
набор допустимых цветов составляет 16 цветов для символов, 8 цветов из этого набора можно задавать для фонов символов.
Цвета кодируются последовательными числами от 0 до 15; эта кодировка определяется устройством дисплейной аппаратуры
компьютера и поэтому не зависит от языка программирования.
Сonst
{Коды, допустимые для текста и фона}
Black
=0;
{Черный}
Blue
=1;
{Синий
Green
=2;
{Зеленый}
Cyan
=3;
{Голубой}
Red
=4;
{Красный}
Maganta
=5;
{Пурпурный}
Brown
=6;
{Коричневый}
LightGray =7;
{Серый}
{Коды, допустимые только для текста}
DarkGray =8;
{Темно-серый}
LightBlue =9;
{Ярко-синий}
LightGreen
=10;
{Ярко-зеленый}
LightCyan =11;
{Ярко-голубой}
LightRed
=12;
{Ярко-красный}
LightMaganta
=13;
{Ярко-пурпурный}
Yellow
=14;
{Ярко-желтый}
White
=15;
{Белый}
Для того, чтобы вывести на экран текст с определенными цветовыми характеристиками, в языке Turbo Pascal принята
следующая техника: сначала устанавливаются текущие цветовые атрибуты, после чего все тексты, выводимые процедурами
write и writeln на экран, используют заданные текущие атрибуты, до тех пор, пока они не будут переопределены. Текущий
цвет и фон символов задаются процедурами TextColor и ТextBackground, которые устанавливают соответственно, текущий
цвет для выводимых символов и текущий фон для них. Эти процедуры вызываются с одним параметром, который
представляет значение нужного цвета (можно использовать одну из представленных выше констант, ее числовое значение
или произвольное выражение, вырабатывающее целое значение в диапазоне от 0 до 15).
Помимо цвета, для символов можно задавать периодическое изменение яркости свечения, которое воспринимается как
мерцание символа (мерцает только символ; фон остается неизменным). Как правило, кратковременная установка мерцания
используется для вывода важных сообщений, имитации работающих электронных часов и т.п. Чтобы задать мерцание для
выводимого далее текста, нужно увеличить значение параметра процедуры TextColor на 128; для большей наглядности этой
операции наряду с кодами цветов в модуле CRT имеется соответствующая константа мерцания:
Const
Blink =128;
Задание. Наберите на компьютере и внимательно рассмотрите представленную ниже простую демонстрационную
программу, иллюстрирующую технику управления цветами.
Program DemoColors;
Uses
Crt;
Begin
writeln('По умолчанию выводятся белые символы на черном фоне');
TextColor(Yellow);
ТextBackground(Blue);
writeln('Желтые символы на синем фоне');
TextColor(Red);
ТextBackground(LightGray);
writeln('Красные символы на сером фоне');
TextColor(White+Blink);
ТextBackground(Red);
writeln('Белый мерцающий текст на красном фоне');
TextColor(Yellow);
ТextBackground(Blue);
174
writeln('A');
TextColor(Red);
ТextBackground(LightGray);
writeln('B');
TextColor(White);
ТextBackground(Red);
writeln('C');
End.
Процедуры и функции работы с экраном и курсором
ClrEol – процедура удаляет все символы от курсора (включительно) до конца строки, заполняя этот участок строки
цветом фона.
ClrScr – процедура очищает текущее окно, заполняя его цветом фона и помещает курсор в его верхний левый угол с
координатами (1, 1).
DelLine – процедура удаляет строку, в которой находится курсор.
GoToXY(X, Y : byte) – процедура перемещает курсор к элементу экрана с заданными координатами X и Y. Если хотя бы
одна координата недопустима, процедура не выполняется.
InsLine – процедура вставляет пустую строку на экране в месте расположения курсора и заполняет ее цветом фона.
WhereX (Function WhereX : byte) – возвращает значение горизонтальной кооординаты.
WhereY(Function WhereY : byte) – возвращает значение вертикальной кооординаты.
Управление курсором
В текстовом режиме на экране, как правило, присутствует курсор – мерцающий служебный элемент, назначением
которого является указание позиции на экране, начиная с которой будет производиться вывод или ввод информации.
Положение курсора на экране можно проверять и изменять, используя подпрограммы CRT. Чтобы установить курсор в
некоторой конкретной позиции, используется процедура GoToXY, два параметра которой определяют позицию знакоместа
на экране, в которую будет перемещен курсор. Первый параметр задает номер позиции по горизонтали (номер колонки),
второй параметр – номер по вертикали (номер строки). Строки и колонки нумеруются от единицы.
Например, вызов процедуры GoToXY(1,1) переместит курсор в крайнюю левую верхнюю позицию экрана, а вызов
процедуры GoToXY(80,25) – в нижнюю правую.
Заметим, что второй вызов даст такой эффект только в том случае, когда текущий текстовый режим равен BW80, CO80,
Mono. В общем случае необходимо учитывать симло строк и столбцов для конкретного режима. Если, например, действует
режим CO80+Font8x8 для адаптера VGA (50 строк по 80 символов), то приведенный выше вызов процедуры переместит
курсор примерно в середину правой крайней колонки.
Чтобы определить текущее положение курсора, можно использовать две функции без параметров - WhereX и WhereY,
которые как видно из их названий, возвращают, соответственно, горизонтальную и вертикальную координаты курсора.
Задание. Наберите, протестируйте и рассмотрите небольшую иллюстративную программу, приведенную ниже.
Program Count;
Uses
Crt;
Var
i : word;
Begin
GotoXY(1,WhereY);
write('
');
for i := 1 to 1000 do
begin
GotoXY(1,WhereY);
write(i);
Delay(100);
end;
End.
Прием, используемый в этой программе, можно применять для нужд трассировки. Например, при обработке очень
больших файлов, которая может продолжаться довольно долгое время, имеет смысл выводить "успокаивающую"
информацию, наглядно показывающую пользователю, что компьютер не "завис" (некоторые системы выдают процент
сделанной работы или что-либо подобное).
Текстовый режим. Модуль CRT. Работа с окнами. Управление звуком
Модуль CRT позволяет работать не только со всем экраном, но и выделять в нем прямоугольные окна. Любое окно
задаётся своим верхним левым и правым нижним углами. Эти углы, так же как и положение любого объекта на экране,
175
задаются двумя координатами: Х и Y. В качестве координаты Х выступает номер позиции в строке (нумерация начинается с
1 и идет слева направо), а в качестве координаты Y - номер строки (нумерация начинается с 1 и идет сверху вниз). При
работе в окне координаты отсчитываются от левого верхнего угла окна. При запуске программы выделенное окно совпадает
по размеру со всем экраном. Если режим работы адаптера 25 строк по 80 позиций, то координаты такого окна (1, 1) и (80,
25).
Window(X1, Y1, X2, Y2 : byte) – определяет текстовое окно на экране.
Смысл выполнения процедуры заключается в том, что все последующие действия по выводу информации действуют в
пределах данного окна. Кроме того, системные процедуры, работающие с курсором - GotoXY, WhereX, WhereY, также
интерпретируют свои параметры относительно левого верхнего угла последнего установленного окна. Далее, процедура
ClrScr, заполняет пробелами не весь экран, а текущее окно.
Значения параметров процедуры Window выбираются очевидным образом; например, вызов
Window(35,11,45,13);
определяет окно высотой в две строки и длиной в десять символов примерно посередине экрана.
После выполнения процедуры Window курсор устанавливается в позицию окна с координатами (1,1). Кроме этого,
эффект данной процедуры на экране никак не проявляется. Результат ее работы бывает виден только при выполнении какихлибо процедур вывода или управления курсором. Хорошей иллюстрацией механизма окон является следующая простая
программа, которая в цикле производит создание очередного окна, случайным образом задавая его размеры м
местоположение, а затем выводит в него серию случайных символов.
Задание. Наберите и протестируйте предложенную программу. Дополните ее своими операторами и комментарием. В
целях большей наглядности употребите процедуру Delay и увеличьте длительность цикла вывода символов.
Program Windows;
Uses
Crt;
Procedure RandomWindow;
Var
X1, Y1, X2, Y2 : byte;
Begin
X1 := Random(40)+1;
Y1 := Random(12)+1;
X2 := X1+Random(40);
Y2 := Y2+Random(12);
TextColor(Random(15));
Window(X1, Y1, X2, Y2);
ClrScr;
End;
Procedure WorkWindow;
Var
i : integer;
Begin
for i := 0 to Random(1000)+500 do
write(Chr(Random(224)+32));
End;
Procedure Finish;
Var
i : integer;
Begin
Window(1, 1, 80, 25);
ClrScr;
if ReadKey = #0
then
ReadKey;
End;
Begin
ClrScr;
Randomize;
repeat
RandomWindow;
WorkWindow
until KeyPressed;
Finish;
End.
176
Модуль CRT содержит две интерфейсные переменные типа word, которые хранят в упакованном виде координаты двух
углов текущего активного окна:
Var
WindMin : word; {координаты левого верхнего угла окна}
WindMax : word; {координаты правого нижнего угла окна}
Посредством стандартных функций Hi и Lo можно извлечь из этих переменных горизонтальные и вертикальные
координаты углов. Наличие этих переменных избавляет от необходимости хранить информацию об активном окне в самой
программе.
Наблюдая работу программы Windows, можно заметить, что, когда в процессе вывода производится заполнение
последней позиции окна, его содержимое сдвигается на одну строку вверх (при этом верхняя строка пропадает) и, тем
самым, нижняя строка освобождается для последующего вывода. Этот механизм является естественным обобщением
знакомых правил работы процедур write и writeln на случай вывода в окна. В модуле Crt имеются две дополнительные
процедуры, позволяющие несколько расширить и усилить возможности прокручивания("скроллинга") содержимого окон –
DelLine и InsLine.
Процедура DelLine удаляет строку окна, на которой находится курсор, и перемещает все строки ниже этой строки на
одну строку вверх. При этом нижняя строка очищается и тем самым допускает ввод очередной порции информации. На
основе этой процедуры удобно задавать прокрутку текстов в окне в направлении снизу вверх.
Задание. Наберите и протестируйте предложенную программу. Дополните ее своими операторами и комментарием.
Program ScrollUp;
Uses
Crt;
Var
i : word;
Begin
Window(5,10,65,14);
ClrScr;
writeln('Cтрока 1');
writeln('Cтрока 2');
writeln('Cтрока 3');
writeln('Cтрока 4');
writeln('Cтрока 5');
for i := 6 to 26 do
begin
GotoXY(1,1);
DelLine;
GotoXY(1,5);
write('Строка ',i);
Delay(300);
end;
Delay(500);
Window(1, 1, 80, 25);
ClrScr;
End.
Процедура InsLine вставляет пустую строку в позиции курсора. При этом все строки окна, расположенные ниже новой
строки, сдвигаются вниз (нижняя строка пропадает).Легко видеть, что эта процедура позволяет организовать прокрутку
содержимого окна (или части окна) в направлении сверху вниз.
Задание. Наберите и протестируйте предложенную программу. Дополните ее своими операторами и комментарием.
Program ScrollDown;
Uses
Crt;
Var
i : word;
Begin
Window(5,10,65,19);
ClrScr;
writeln('Данные строки окна');
writeln('остаются неизменными.');
writeln('В пяти нижних строках');
writeln('организована прокрутка');
writeln('в направлении сверху вниз');
for i := 1 to 40 do
177
begin
GotoXY(1,6);
InsLine;
write('Строка ',i);
Delay(300);
end;
Delay(500);
Window(1, 1, 80, 25);
ClrScr;
End.
Процедуры управления звуком
Sound(Hz : word) – процедура включает источник звука с частотой Hz герц.
NoSound – процедура выключает источник звука.
Процедуры для работы со звуком позволяют получить доступ ко встроенному динамику компьютера. Процедура Sound
включает динамик, который начинает генерировать звук с заданной в герцах частотой тона. Это никак не отражается на
работе программы, которая не будет остановлена и может продолжать нормально работать одновременно с подачей
звуковых сигналов до тех пор, пока не встретится вызов процедуры NoSound, которая отключает динамик.
Процедуры работы со звуком надо использовать аккуратно. Если после процедуры Sound не вызвать процедуру
NoSound, то звук будет производится после завершения программы, и, чтобы его отключить, придется либо перезагружать
компьютер, либо заново перекомпилировать и запустить программу, предварительно добавив в нее вызов процедуры
NoSound.
Процедура NoSound может следовать после нескольких процедур Sound, которые изменяют частоту тона.
Очень часто процедуры Sound и NoSound используются совместно с процедурой Delay(ms : word), которая
останавливает выполнение программы на указанное в параметре время.
Процедура Delay использует для отсчета времени встроенную микросхему таймера, которая вычисляет десятые и сотые
доли секунды недостаточно точно, поэтому не следует применять эту процедуру для точного вычисления времени.
Рассмотрите пример использования звуковых процедур. Программа генерирует последовательность звуков,
представляющих обычную гамму.
Program Gamma;
Uses
Crt;
Const
Nota : Array [0..7] of word = (262, 294, 330, 349, 392, 440, 494, 524);
Var
i : byte;
Begin
GotoXY(35,5);
write('Гамма');
repeat
for i := 0 to 7 do
begin
Sound(Nota[i]);
Delay(500);
NoSound;
end;
until KeyPressed;
End.
Функции работы с клавиатурой
KeyPressed (Function KeyPressed : boolean) – определяет, была ли нажата клавиша на клавиатуре.
ReadKey (Function ReadKey : char) – читает значение нажатой клавиши.
Эти функции были подробно рассмотрены в теме "Циклы" первого года обучения. Поэтому здесь мы останавливаться на
их изучении не будем.
Внимание! Дополните любую решенную Вами задачу рассмотренными в этом занятии процедурами и функциями.
НЕТИПИЗИРОВАННЫЕ ФАЙЛЫ
178
Занятие 1. Нетипизированные файлы. Их отличия. Процедуры blockread и blockwrite.
Нетипизированные файлы – это файлы, поддержка которых осуществляется с максимально возможной скоростью.
Введение таких файлов в систему Турбо Паскаль было вызвано стремлением повысить эффективность программ,
участвующих в интенсивном обмене с внешними наборами данных.
Эти файлы в отличие от уже рассмотренных не имеют строго определенного типа.
Нетипизированный файл рассматривается в Паскале как совокупность символов или байтов. Представление char или
byte не играет никакой роли, важен лишь объем занимаемых данных.
Такое представление стирает различия между файлами независимо от типа их объявления. На практике это приводит к
тому, что любой файл, подготовленный как текстовый или типизированный, можно открыть и начать работу с ним, как с
нетипизированным набором данных.
Для определения в программе нетипизированного файла служит зарезервированное слово file:
Var
MyFile : file;
Внутренняя поддержка таких файлов выглядит наиболее близкой к аппаратной поддержке работы с внешними
носителями. За счет этого достигается максимально возможная скорость доступа к наборам данных. Для нетипизированных
файлов не нужно терять время на преобразование типов и поиск управляющих последовательностей, достаточно считать
содержимое файла в определенную область памяти.
Нетипизированный файл является файлом прямого доступа, что говорит о возможности одновременного использования
операций чтения и записи.
Для таких файлов самым важным параметром является длина записи в байтах. Открытие нетипизированного файла с
длиной записи в 1 байт можно выполнить следующим образом:
rewrite(MyFile, 1) или reset(MyFile, 1)
Второй параметр, предназначенный только для использования с нетипизированными файлами, задает длину записи
файла на сеанс работы.
Особенность аппаратной поддержки заключается в том, что при обращении к внешнему устройству минимально
возможным объемом для считывания являются 128 байт. В стремлении добиться наибольшей эффективности файловых
операций в Турбо Паскале принято соглашение, по которому длина записи нетипизированного файла по умолчанию
составляет 128 байт. Поэтому после открытия файла с помощью вызовов:
rewrite(MyFile) или reset(MyFile)
все процедуры и функции, обслуживающие файлы прямого доступа, работают с записями длиной 128 байт. Каждый
пользователь для своих программ может выбрать наиболее подходящий размер записи.
Турбо Паскаль не накладывает каких-либо ограничений на длину записи нетипизированного файла, за исключением
требования положительности и ограничения максимальной длины 65535 байтами (емкость целого типа word). При этом
следует учитывать два обстоятельства.
Во-первых, для обеспечения максимальной скорости обмена данными следует задавать длину, которая была бы кратна
длине физического сектора дискового носителя информации (512 байт).
С другой стороны, нужно помнить, что общий размер файла может не быть кратен выбранному размеру записи
(последняя запись может быть неполной). Для того, чтобы гарантированно обеспечить полное чтение всего файла,
рекомендуется установить размер записи равным 1.
Более того, фактически пространство на диске выделяется любому файлу порциями – кластерами, которые в
зависимости от типа диска могут занимать 2 и более смежных секторов. Как правило, кластер может быть прочитан или
записан за один оборот диска, поэтому наивысшую скорость обмена данными можно получить, если указать длину записи,
равную длине кластера.
При работе с нетипизированными файлами могут применяться все процедуры и функции, доступные типизированным
файлам. Напомним эти процедуры и функции.
assign (МуFilе, 'с:\МуDirectory\result.dat') - процедура связывания логической файловой переменной МуFilе с
конкретным физическим файлом на дисковом носителе информации;
closе (МуFilе) - процедура, закрывающая открытый файл;
rewrite (МуFilе) – процедура, создающая новый файл и открывающая его для записи или чтения; эта процедура имеет
дополнительный параметр при работе с нетипизированными файлами, который будет рассмотрен позднее;
reset (МуFilе) – процедура, открывающая существующий файл данных; эта процедура имеет дополнительный параметр
при работе с нетипизированными файлами, который будет рассмотрен позднее;
eof (МуFilе) – логическая функция, проверяющая, достигнут ли конец файла;
179
seek (МуFilе, n) - процедура, позволяющая явно изменить значение текущего указателя файла, установив его на элемент
с номером n;
filesize(МуFilе) - функция, возвращающая позицию указателя по файлу; нумерация начинается с нуля;
filepos (МуFilе) - функция, возвращающая количество элементов файла;
rename(МуFilе, FileName) - процедура, позволяющая переименовать существующий файл;
truncate(МуFilе) - процедура, позволяющая удалить часть существующего файла, начиная с текущей позиции;
erase(МуFilе) - процедура, стирающая указанный файл,
Вы должны были заметить, что в списке нет процедур read и write. Для чтения информации из нетипизированного файла
и записи информации в него только для данного типа файлов в Турбо Паскаль введены две новые процедуры,
поддерживающие операции ввода-вывода с более высокой скоростью.
Процедура BlockRead
Формат обращения:
blockread(Var F : file; Var Buf; Kolblocks : word; result : word);
Процедура считывает из файла F определенное число блоков в память, начиная с первого байта переменной Buf.
Параметр Buf представляет любую переменную, которая будет участвовать в обмене данными с дисками. Эту
переменную нужно описать в программе так, чтобы ее размер не был меньше размера записи, установленного в параметрах
rewrite или reset (как правило, для этих целей используется некоторый массив).
Параметр Kolblocks задает число считываемых блоков, которые должны быть прочитаны за одно обращение к диску.
Параметр result является необязательным и содержит после вызова процедуры число действительно считанных записей.
Использование параметра result подсказывает, что число считанных блоков может быть меньше, чем задано параметром
Kolblocks. Если result указан при вызове, то ошибки ввода-вывода в такой ситуации не произойдет. Для отслеживания этой и
других ошибок чтения можно использовать опции {$I-}, {$I+} и функцию IOresult.
Кроме того, что переменная F должна быть описана как нетипизированный файл, она должна быть связана с
конкретным физическим диском процедурой assign. Файл должен быть открыт процедурой reset.
Процедура BlockWrite.
Формат обращения:
blockwrite(Var F : file; Var Buf; Kolblocks : word; result : word);
Процедура предназначена для быстрой передачи в файл F определенного числа записей из переменной Buf. Все
параметры процедуры blockwrite аналогичны параметрам процедуры blockread. Разница лишь в том, что файл должне быть
подготовлен для записи процедурой rewrite. Содержимое переменной Buf целиком помещается в файл, начиная с текущей
записи.
Обе процедуры выполняют операции ввода-вывода блоками. Объем блока в байтах определяется по формуле:
Объем = Kolblocks * recSize,
где recSize – размер записи файла, заданный при его открытии. Суммарный объем разового обмена не должен
превышать 64 Кбайт. Помимо скорости передачи данных преимущество этих процедур заключается в возможности
пользователя самостоятельно определять размер буфера для файловых операций. Эта возможность играет значительную роль
в тех задачах, где необходимо жесткое планирование ресурсов. Программист должен позаботиться о том, чтобы длина
внутреннего представления переменной Buf была достаточной для размещения всех байт при чтении информации с диска.
Дело в том, что чтение информации из файла в буфер, равно как и запись из буфера в файл, производится без типового
контроля. Поэтому несоблюдение указанного условия может привести к порче соседних с буфером данных или к помещению
на файл посторонней информации.
Если при чтении указана переменная Buf недостаточной длины или если в процессе записи на диск не окажется нужного
свободного пространства, то произойдет следующее. Если последний параметр result в этих вызовах не задан, то возникает
ошибка ввода-вывода; если параметр result задан, то ошибка не будет зафиксирована, а после выполнения процедуры его
значение не будет совпадать с значением параметра Kolblocks. Последнее обстоятельство можно проверить, сравнив два
указанных значения.
После завершения процедуры указатель смещается на result записей.
Рассмотрите примеры простых задач.
Задача № 1. Составить программу, которая создает нетипизированный файл из 100 чисел и выводит на экран k-ый
элемент.
Program Netipiz1;
Uses
180
Crt;
Type
FileType = file;
Var
f : FileType;
P, B, k : byte;
Begin
ClrScr;
assign(F, 'MyFile');
rewrite(F,1);
Randomize;
for k := 1 to 100 do
begin
P := Random(100);
blockwrite(F, P, 1);
end;
close(F);
reset(F,1);
for k := 1 to 100 do
begin
blockread(F, P, 1);
write(p,' ');
end;
write('Введите номер нужного элемента ');
readln(k);
Seek(F, k-1);
blockread(F, P, 1);
writeln(k,'-ий элемент файла равен ', P);
close(F);
End.
Задача № 2. Составить программу, которая создает копию элементов нетипизированного файла f и помещает в файл g.
Program Netipiz2;
Uses
Crt;
Var
f, g : file;
Stroka1, sб Stroka2 : string;
Begin
ClrScr;
write('Введите имя исходного файла');
read(Stroka1);
assign(f, Stroka1);
rewrite(f,1);
write('Введите содержимое файла ');
repeat
readln(s);
blockwrite(f, s, 1);
until readKey = #27;
close(f);
reset(f,1);
write('Введите имя конечного файла');
read(Stroka2);
assign(g, Stroka2);
rewrite(g,1);
while not Eof(f) do
begin
blockread(f, s, 1);
blockwrite(g, s, 1);
end;
close(f);
close(g);
write('Содержимое конечного файла:');
while not Eof(g) do
begin
blockread(g, s, 1);
181
write(s);
end;
readln;
End.
Задача № 3. Составить программу, которая создает массив целых чисел и записывает его в нетипизированный файл, а
также вычисляет среднее арифметическое элементов файла.
Program Netipiz3;
Uses
Crt;
Var
f : file;
i, k, s : integer;
Mas : Array [1..10] of byte;
Begin
ClrScr;
Randomize;
for i := 1 to 10 do
Mas[i] := Random(10);
assign(f, 'file.dat');
rewrite(f,1);
blockwrite(f, Mas, 10);
close(f);
reset(f,1);
while not Eof(f) do
begin
blockread(f, k, 1);
s:= s+k;
Inc(i);
end;
close(f);
write(s/i:5:2);
readln;
End.
Задание. Наберите программу, содержащую все рассмотренные выше задачи, усовершенствуйте решение, разбейте ее
на процедуры (ввод, вывод, поиск), дополните комментариями. Проверьте правильность работы программы. Покажите
учителю рабочий файл и листинг программы для оценки.
Занятие 2. Решение задач
Выберите с учителем задачи для самостоятельного решения из предложенного ниже списка.
1. Создать нетипизированный файл, содержащий произвольную информацию в виде символов. Создать
нетипизированный файл, являющийся копией этого файла. Задайте число считываемых блоков, которые должны быть
прочитаны за одно обращение к диску, равное единице. В программе используйте процедуры и функции.
2. Создать нетипизированный файл, содержащий произвольную информацию в виде символов. Создать
нетипизированный файл, являющийся копией этого файла. Задайте число считываемых блоков, которые должны быть
прочитаны за одно обращение к диску, не равное единице. В программе используйте процедуры и функции.
3. Создать нетипизированный файл, содержащий произвольную информацию в виде символов. Выведите на экран
первые N символов (N задает пользователь). Задайте число считываемых блоков, которые должны быть прочитаны за одно
обращение к диску, равное единице. В программе используйте процедуры и функции.
4. Создать нетипизированный файл, содержащий произвольную информацию в виде символов. Выведите на экран
символы построчно, в каждой строке N символов (N задает пользователь). Задайте число считываемых блоков, которые
должны быть прочитаны за одно обращение к диску, равное N. В программе используйте процедуры и функции.
5. Создать нетипизированный файл, содержащий произвольную информацию в виде символов. Выведите на экран
только символы, являющиеся гласными буквами. В другой нетипизированный файл поместите согласные буквы. В
программе используйте процедуры и функции.
6. Создать нетипизированный файл, содержащий целые числа. Разделите этот файл на два файла по желанию
пользователя, запросив у него имена файлов и спрашивая в какой файл записать очередное считанное число. В программе
используйте процедуры и функции.
182
7. Создайте нетипизированный файл, содержащий произвольные символы международной таблицы кодов обмена
информации. Создайте на базе этого файла два нетипизированных файла, один из которых содержал бы буквы и цифры, а
другой – все остальные символы. В программе используйте процедуры и функции.
8. Создайте нетипизированный файл, содержащий произвольную числовую информацию. Создайте на базе этого файла
два нетипизированных файла, которые бы заполнялись по очереди (количество одновременно обрабатываемых блоков задает
пользователь). Например, 5 блоков – в один файл, 5 блоков – во второй файл, и так далее до конца файла. В программе
используйте процедуры и функции.
9. Создайте нетипизированный файл, содержащий произвольную числовую информацию. Создайте на базе этого файла
нетипизированный отсортированный по возрастанию файл. В программе используйте процедуры и функции.
10. Создать нетипизированный файл, содержащий произвольную символьную информацию. Создайте на базе этого
файла нетипизированный отсортированный по возрастанию кодов символов файл. В программе используйте процедуры и
функции.
Занятие 3. Использование типизированных файлов в качестве нетипизированных
Задачи для самостоятельного решения
Выберите с учителем задачи из предложенного ниже списка.
1. Создайте типизированный числовой файл. Используя способы обработки нетипизированного файла создать
текстовый файл, содержащий ту же информацию. В программе используйте подпрограммы.
2. Создайте символьный файл. Преобразуйте его в строковый файл (длину строки указывает пользователь), используя
способы обработки нетипизированного файла. В программе используйте подпрограммы.
3. Создайте типизированный числовой файл. Используя способы обработки нетипизированного файла создать
текстовый файл, содержащий четные числа и типизированный строковый файл, содержащий нечетные числа. В программе
используйте подпрограммы.
4. Создайте типизированный строковый файл, содержащий слова. Используя способы обработки нетипизированного
файла создать текстовый файл, в котором слова были бы записаны через запятую, а за последним словом стояла бы точка. В
программе используйте подпрограммы.
5. Создайте типизированный строковый файл, содержащий предложения. Используя способы обработки
нетипизированного файла создать типизированный строковый файл, в котором каждым элементом являлось бы слово . В
программе используйте подпрограммы.
6. Создайте типизированный числовой файл. Используя способы обработки нетипизированного файла создать
текстовый файл, содержащий строки по 10 чисел в каждой. В программе используйте подпрограммы.
7. Создайте типизированный числовой файл. Используя способы обработки нетипизированного файла создать
текстовый файл, содержащий две строки. В одной строке была бы записана и посчитана сумма чисел, а в другой строке разность. В программе используйте подпрограммы.
8. Создайте файл комбинированного типа, каждый элемент которого содержит следующие поля: номер участника
соревнования, его фамилия, имя, страна и показанный результат. Создать нужное количество файлов комбинированного типа
(количество файлов зависит от количества участвующих в соревнованиях стран), в которых содержалась бы следующая
информация: фамилия, имя участника и показанный результат. Именем файла должно быть название страны. В программе
используйте способы обработки нетипизированного файла и подпрограммы.
9. Создайте файл комбинированного типа, каждый элемент которого содержит следующие поля: фамилия, имя студента
и результаты сессии. Создать файл комбинированного типа, в котором содержалась бы следующая информация: фамилия,
имя студента и среднее арифметическое его оценок за сессию. В программе используйте способы обработки
нетипизированного файла и подпрограммы.
10. Познакомившись с содержанием предыдущих задач придумайте свою интересную задачу и решите ее.
Занятие 4. Использование текстовых файлов в качестве нетипизированных.
Рассмотрите пример.
Задача . Из текстового файла прочитать находящиеся там символы, заменить их на символы, отличающиеся своими
кодами от исходных на определенную величину, меняющуюся от символа к символу (шифрация методом простой
одноалфавитной подстановки). Поместить эти символы в новый файл, разместив в нем предварительно число
перекодированных символов и таблицу смещений кодов.
Program Kodirovka;
Const
183
NofCod = 20;
{Размер таблицы смещений кодов}
Var
FirstFile : text;
{Исходный файл}
SecondFile : file;
{Результирующий файл}
FirstName, SecondName : string;
IOres : byte;
{Код результата работы с файлом}
NofSymb : LongInt;
{Число символов в файле}
Codes : Array[1..NofCod] of byte; {Таблица смещений кодов символов}
Buffer : Array [1..NofCod] of char; {Буфер для символов}
i : word;
{Процедура записи в файл с проверкой}
Procedure WriteAndControl (Var Buf, Amount : word);
Var
result : word;
{Число переданных символов}
Begin
blockwrite (SecondFile, Buf, Amount, result);
if result <> Amount
then
begin
writeln('Нет места на диске ');
Halt;
end;
End;
Begin
{Связь с исходным текстовым файлом для чтения}
repeat
{$I-}
write('Имя исходного файла: ');
readln(FirstName);
assign(FirstFile, FirstName);
reset(FirstFile);
{$I+}
IOres := IOresult;
if IOres <> 0
then
writeln('Такого файла нет ');
until IOres =0;
{Связь с результирующим файлом без типа для записи}
repeat
{$I-}
write('Имя результирующего файла: ');
readln(SecondName);
assign(SecondFile, FirstName);
rewrite(SecondFile, 1);
{Размер блока в один байт}
{$I+}
IOres := IOresult;
if IOres <> 0
then
writeln('Неправильное имя файла ');
until IOres =0;
{Установка счетчика символов и запись его в файл}
NofSymb := 0;
WriteAndControl(NofSymb, 4);
{Задание таблицы смещений кодов символов, запись ее в файл}
Randomize;
for i := 1 to NofCod do
Codes[i] := Random(256);
{Перекодировка символов и запись содержимого полных буферов в файл}
i := 0;
while not Eof(FirstFile) do
begin
Inc(NofSymb);
Inc(i);
if Eoln(FirstFile)
then
begin
184
Buffer[i] := Chr((13+Codes[i]) mod 256);
if i=NofCod
then
begin
writeAndControl(Buffer, NofCod);
i := 0;
end;
Inc(i);
Buffer[i] := Chr((10+Codes[i]) mod 256);
readln(FirstFile);
end;
else
begin
read(FirstFile, Symbol);
Buffer[i] := Chr((Ord(Symbol)+Codes[i]) mod 256);
end;
if i = NofCod
then
begin
writeAndControl(Buffer, NofCod);
i := 0;
end;
{Запись в файл завершающей части символов}
if i <> 0
then
begin
writeAndControl(Buffer, i);
{Запись числа символов}
NofSymb := FileSize(SecondFile)-NofCod-4;
Seek(SecondFile, 0);
writeAndControl(NofSymb, 4);
{Завершение программы}
close(SecondFile);
writeln('Конец работы программы ');
readln;
End.
В этой программе в результирующий файл окончательно будут записаны: общее количество перекодированных
символов, таблица смещений кодов символов и перекодированные символы. Файл используется как файл без типа с
размером блока в 1 байт, который устанавливается процедурой rewrite.
Задачи для самостоятельного решения
1. Текстовый файл преобразовать в файл целого типа следующим образом: гласные буквы заменить на число 0,
согласные буквы на число 1, а все остальные символы – на число 2. Подсчитать количество согласных букв. Если в
текстовом файле согласных не обнаружено, выдайте на экран соответствующее сообщение. В программе используйте
способы обработки нетипизированного файла и подпрограммы.
2. Текстовый файл преобразовать в файл символьного типа, игнорируя символы, не являющиеся буквой. Если в
текстовом файле букв не обнаружено, выдайте на экран соответствующее сообщение. В программе используйте способы
обработки нетипизированного файла и подпрограммы.
3 Текстовый файл преобразовать в файл строкового типа, игнорируя пустые строки. В каждой строке файла,
являющимся результатом выполнения программы, должно быть одно предложение. Если в текстовом файле предложений не
обнаружено, выдайте на экран соответствующее сообщение. В программе используйте способы обработки
нетипизированного файла и подпрограммы.
4. Текстовый файл, содержащий числовую информацию преобразовать в файл целого типа. Каждый элемент
типизированного файла должен содержать цифру. В программе используйте способы обработки нетипизированного файла и
подпрограммы.
5. Текстовый файл, содержащий числовую и текстовую информацию преобразовать в файл целого и символьного типа.
Каждый элемент типизированного файла должен содержать цифру или символ. Если в текстовом файле числовой или
текстовой информации не обнаружено, выдайте на экран соответствующее сообщение. В программе используйте способы
обработки нетипизированного файла и подпрограммы.
6. Из текстового файла выделить числовую информацию и поместить ее в файл целого типа. Каждый элемент
типизированного файла должен содержать цифру. Если в текстовом файле числовой информации не обнаружено, выдайте на
экран соответствующее сообщение. В программе используйте способы обработки нетипизированного файла и
подпрограммы.
185
7. Создайте текстовый файл, содержащий фамилии, имена и отчества сотрудников некоторого предприятия.
Преобразуйте этот текстовый файл в файл комбинированного типа. Каждый элемент типизированного файла должен
содержать фамилию, имя и отчество одного сотрудника. В программе используйте способы обработки нетипизированного
файла и подпрограммы.
8. Создайте текстовый файл, каждая строка которого содержала бы фамилию, имя, отчество сотрудника некоторого
предприятия и его оклад. Преобразуйте этот текстовый файл в файл комбинированного типа. Найдите в полученном файле
сотрудника с самым высоким окладом. В программе используйте способы обработки нетипизированного файла и
подпрограммы.
9. Создайте текстовый файл, каждая строка которого содержала бы наименование товара некоторого предприятия и его
цену. Преобразуйте этот текстовый файл в файл комбинированного типа. Найдите в полученном файле самый дорогой и
самый дешевый товар. В программе используйте способы обработки нетипизированного файла и подпрограммы.
10. Познакомившись с содержанием предыдущих задач придумайте свою интересную задачу и решите ее.
Занятие 5. Примеры решения творческих задач
Рассмотрите решение творческих заданий учащихся. Наберите программы на компьютере и просмотрите их действие.
Подумайте, как ребятам удалось придумать и выполнить такие работы. Эти программы помогут Вам определиться с
выбором своей творческой работы.
Задача № 1. С помощью нетипизированного файла проанализировать файлы с расширением .mp3 в заданном
пользователем каталоге и создать текстовый файл, содержащий следующую информацию: название песни, исполнитель, имя
файла.
Program SedihGetTag;
{$I-}
Uses
Crt;
Var
f : file;
c : char;
S : string;
i : LongInt;
DirInfo : seachrec;
Txt : text;
Procedure Extract;
Begin
assign(f, DirInfo.name);
reset(f, 1); {размер буфера записи равен 1 байту}
l := FileSize(f); {переменной l присваиваем размер файла в байтах}
Seek(f, l-125); {ставим указатель, на 125 символов отступив от конца файла}
{вычислил сам, проанализировав файл данного типа}
while not Eof(f) do
Begin
blockread(f, c, 1); {читаем посимвольно}
S := S + c; {формируем строковую переменную, содержащую нужный тэг}
end;
close(f);
writeln(Txt, copy(S, 1, 30)+'-'+copy(S, 31, 30)+'-'+DirInfo.Name);
{записываем выделенную информацию в файл)}
End;
Begin
ClrScr;
assing(txt,'list.txt');
rewrite(txt);
FindFirst('*.mp3', Arhive, DirInfo);
while DosError=0 do
begin
S := '';
Extract;
FindNext(DirInfo);
end;
close(Txt);
End.
186
Задача № 2. С помощью нетипизированного файла проанализировать файлы-архивы (архиватор WinRar) и вывести на
экран имена заархивированных файлов.
Program LipovcevMaksim;
Uses
Crt;
Var
i, pos : integer;
f : file;
FileName, Ima : string;
s : char;
Procedure Name(Var s : char); Forward;
Procedure Poisk(Var s : char);
Begin
case Ord(s) of
20 : begin
blockread(f, s, 1);
case Ord(s) of
20 : Poisk(s);
48..57 : begin
blockread(f, f, S, 1);
case Ord(S) of
20 : Poisk(S);
1..19 : Name(S);
21..32 : Name(S);
end;
end;
end;
end;
end;
End;
Procedure (Name(Var S : char);
Var
k : integer;
Begin
k:=0;
for i := 1 to 5 do
blockread(f, S, 1);
while (S<>'.') and (k<9) do
begin
blockread(f, S, 1);
k := k+1;
ima := Ima+S;
if S='\'
then
k := 0;
end;
if Pos('.', Ima)<>0
then
begin
for i := 1 to 3 do
begin
blockread(f, S, 1);
Ima := Ima+S;
end;
writeln(Ima);
end;
Ima := '';
End;
Begin
ClrScr;
writeln('Введите полное имя архивного файла RAR');
write('->');
readln(FileName);
reset(f, 1);
writeln('Имена заархивированных файлов:');
while not EOF(f) do
187
begin
blockread(f, S, 1);
Poisk(S);
end;
close(f);
readKey;
End.
Задача № 3. С помощью нетипизированного файла преобразовать файл c расширением .BMP следующим образом:
разделить рисунок на две части по горизонтали, верхнюю часть поместить на место нижней, разделить её на две части
по вертикали и поменять их местами.
Примечание. При исследовании файлов с расширением ВМР выяснилось следующее их описание в зависимости от
количества употребляемых цветов:
16 цветов - 118 байт, 256 цветов - 1086 байт, 24 бита - 55 байт. Это колисемтво байт влияет на значение переменное Кol в
программе.
Program BaranovA;
Uses
Crt;
Const
n=1234; {установка размера буфера}
Kol=118;
Var
F1, F2 : file;
Name1, Name2 : string;
Buf : Array [1..n] of byte;
AllSize, PicSize, HalfSize : LongInt;
i : integer;
Begin
write('Имя файла >');
readln(Name1);
Name2 := Name1;
if Pos('.', Name2) <> 0
then
begin
Delete(Name2, Pos('.', Name2), Lenth(Name2)-Pos('.', Name2)+1);
Name2 := Name2+'.tmp';
assign(F1, Name1);
reset(F1, 1);
assign(F2, Name2);
rewrite(F2, 1);
AllSize := FileSize(F1); {размер всего файла}
PicSize := AllSize-Kol; {размер всего файла без описания}
HalfSize := PicSize div 2; {половина файла}
blockread(F1, Buf, Kol);
blockwrite(F2, Buf, Kol);
seek(F1, Kol+HalfSize-1);
for i := 1 to HalfSize div n do
begin
blockread(F1, Buf, n); {считываем и записываем из середины файла}
blockwrite(F2, Buf, n);
End;
blockread(F1, Buf, HalfSize mod n); {переписываем оставшиеся байты из не полностью заполненного буфера}
blockwrite(F2, Buf, HalfSize mod n);
Seek(F1, Kol-1);
blockread(F1, Buf, HalfSize mod n);
blockwrite(F2, Buf, HalfSize mod n);
close(F1);
close(F2);
end;
End.
Задание. Выбрав какую-либо категорию файлов, проанализировать их в своей программе, пользуясь возможностями
обработки нетипизированного файла, и решить некоторую поставленную Вами задачу. Протестированную программу и
листинг покажите учителю для оценки.
188
Приготовьте рабочие программы и оцененные листинги для проверки учителем.
Проверьте свои знания по теме, ответив на следующие вопросы:
1. Дайте определение нетипизированному файлу.
2. В чем Вы видите преимущества и недостатки работы с нетипизированными файлами по сравнению с
типизированными и текстовыви файлами?
3. Объясните назначение параметров специфических для нетипизированных файлов процедур чтения и записи.
4. Какой вид файлов из рассмотренных выше Вам понравился больше и почему?
5. Объясните назначение процедур Аssign, Сlosе, Eof и их параметров.
6. В чем особенность применения процедуры rewrite и какой дополнительный параметр при работе с
нетипизированными файлами она имеет?
7. В чем особенность применения процедуры reset и какой дополнительный параметр при работе с нетипизированными
файлами она имеет?
8. Объясните назначение процедур Seek, FileSize, FilePos и их параметров.
9. Объясните назначение процедур rename, Truncate, Еrase и их параметров.
10. Расскажите как Вы работали над творческим заданием.
Для любознательных. Дополнительные процедуры и функции работы с файлами
Рассмотрим некоторые процедуры работы с файлами, входящие в модуль Dos. Напомним, что для его подключения
требуется указать
Uses
Dos.
Ряд свойств файла, хранящегося на диске, кодируются так называемыми атрибутами. Атрибуты файла записываются не
в сам файл, а в информационный раздел каталога, в котором хранится файл. Для хранения атрибутов отводится один байт,
единица в определенном бите которого означает наличие свойства, а нуль – отсутствие. Соответствие битов и свойств
показывает схема, приведенная на рисунке.
7 6 5 4 3 2 1 0
0 – Только чтение readOnly=1,
1 – Скрытый файл Hidden=2,
2 – Системный файл Sysfile=4,
3 – Метка томаVolumeID=8,
4 – Подкаталог Directory=16,
5 – Архивный файл Arhive=32.
Каждому атрибуту соответствует определенная константа, равная 2 k, где k – номер бита. Эти константы описаны в
модуле Dos, их значения и имена приведены на схеме. В целом байт атрибутов образуется как сумма соответствующих ему
констант. Установка атрибута «только чтение» приводит к невозможности изменения содержимого файла или его удаления.
Скрытые файлы игнорируются некоторыми командами операционной системы, в частности, они не показываются по
команде Dir. Системные файлы – файлы операционной системы Dos. Атрибут «Архивный» означает, что для этого файла не
была создана резервная копия командой BackUp.
Большинство файлов имеют этот атрибут. Определить атрибуты файла можно с помощью процедуры
GetFAttr(MyFile,Attr);
которая возвращает переменную Attr, содержащую код атрибутов файла.
Например, проверить свойство «только для чтения» можно процедурами
GetFAttr(MyFile,Attr);
if Odd(Attr)
then
write ('Только для чтения')
else
write(' Не только для чтения').
Установка требуемых атрибутов файла производится процедурой
setFAttr (MyFile,Attr);
189
Процедуры для поиска на диске требуемых файлов используют специальный тип записи Seachrecord, определенный
в модуле Dos. Запись
Туре
Seachrecord= record
Fill : аrrау [1..21] оf bytе;
Attr : bytе;
Time : longint;
Size : longint;
Name : string[12]
end;
Первое поле записи – массив Fill – используется операционной системой и не должно изменяться в пользовательских
программах. Содержание поля Attr – атрибуты файла, рассмотренные выше. Поле Time содержит время записи файла в
упакованном виде. Упакованный вид записи времени может быть получен из даты, часов, минут, секунд и сотых долей
секунды процедурой РасkTime. Size – размер файла в байтах. Name – имя файла, включая разделительную точку и
расширение.
Процедура
FindFirst (SeachPath, Аttr, Seachresult);
ищет в каталоге первый файл, удовлетворяющий заданной спецификации. Параметры SeachPath и Аttr содержат
исходные данные для поиска. Возвращаемый результат поиска – Seachresult. SeachPath – строка, содержащая полное имя
файла, в том числе каталог, в котором необходимо искать файл, и имя файла. Имя файла (но не путь) может содержать
символы звездочки и вопросительного знака, которые, соответственно, заменяют любую последовательность символов или
один произвольный символ.
Если путь не приводится, поиск идет в рабочем каталоге. Следовательно, SeachPath = '*.dat' указывает на все файлы с
расширением "dat" в текущем каталоге.
Процедура FindNext(Seachres) употребляется только после процедуры FindFirst и продолжает последовательно поиск
файлов с определенным процедурой FindFirst шаблоном.
Функция FSeach(SeachString, DirList) ищет файл, заданный строкой SeachString, в заданном списке каталогов DirList.
Список каталогов записывается так же, как в команде DOS Path, то есть различные каталоги разделены точкой с запятой.
Результат этой функции – полное имя файла, если он найден по указанным путям.
Функция FExpand(FileName), получив имя файла FileName, расширяет его до полного имени, используя для этого
текущий каталог. Если в качестве FileName задано имя с полным путем, функция не изменяет его. Если задано только имя
файла, то дописывается текущий каталог. Если запись FileName начинается с символа "обратный слэш", то берется текущий
диск и к нему дописывается имя FileName. Если запись FileName начинается с символов "..", то берется часть текущего
каталога на уровень выше.
Процедура FSplit(WholeFileName, Dir, Name, Ext), получив в качестве аргумента полное имя файла WholeFileName,
разделяет его на три составные части и возвращает переменные параметры Dir – каталог, Name – имя файла, Ext –
расширение. Для каталога, имени файла и расширения в модуле DOS предусмотрены специальные типы – строки
ограниченной длины: PathStr, NameStr, ExtStr.
Обратим внимание, что типизированные переменные пишутся в файл в том виде, в каком они используются в памяти
ЭВМ. Если мы пытаемся прочитать содержимое такого файла обычными средствами DOS, например, нажав F3 в Norton
Commander, или непосредственно в среде Паскаль, то каждый байт этих записей воспроизведется как соответствующий
символ кодовой таблицы ASCII. Например, если файл имеет байтовый тип, и в него пишутся числа 65, 66, 67, то при его
чтении мы увидим АВС. Такая запись данных компактна и удобна, если создаваемые файлы читаются другими
программами, для которых эта кодировка естественна. В тех случаях, когда файлы предназначены для просмотра человеком,
требуется перевод данных в текстовую форму.
Внешние устройства в качестве файлов.
Связь с внешними устройствами в языке Паскаль осуществляется также через файловые переменные.
В Турбо Паскале существует два типа внешних устройств: устройства операционной системы и текстовые устройства.
Устройства операционной системы, с которыми осуществляется обмен информацией, могут быть описаны как файлы со
стандартными именами. Эти имена следующие:
– консоль (клавиатура, дисплей). С этим устройством
стандартно связаны файловые переменные Input и Output.
LPT1, LPT2, LPT3 – печатающие устройства. Если в системе один принтер, то
он будет иметь имя LPT1. Если в программе используется
стандартный модуль Printer (указан в разделе Uses), можно
использовать для вывода на принтер стандартную файловую
переменную Lst.
CON
190
PRN
COM1, COM2
AUX
NUL
– синоним LPT1.
– имена двух портов.
– синоним COM1.
– фиктивное внешнее устройство.
К текстовым устройствам относятся устройства, не поддерживаемые операционной системой или имеющие другие
способы обращения. Например, устройство CRT, поддерживаемое стандартным модулем Сrt. Оно эквивалентно CON в
операционной системе, но более быстродействующее и позволяет использовать разные цвета и окна.
С текстовым устройством нельзя связаться процедурой assign. Для связи с ним служит специальная модификация этой
процедуры, например, для связи с устройством CRT следует использовать процедуру AssignCrt в модуле Crt.
ГРАФ
Занятие 1. Основные понятия.
Граф – это непустое множество точек (вершин) и множество отрезков (ребер), концы которых принадлежат заданному
множеству точек.
Если на каждом ребре задать направление, то граф будет ориентированным.
Если, двигаясь по ребрам графа в заданном направлении, можно попасть из заданной вершины 1 в заданную вершину 2,
то говорят, что эти вершины соединены путем.
Замкнутый путь, состоящий из различных ребер, называется циклом.
Граф называется связным, если любые две его вершины соединены путем.
çÂÒ‚½ÁÌÞÈ „¾‡Ù
낽ÁÌÞÈ „¾‡Ù
Связный граф без циклов называется деревом.
С каждой вершиной дерева связывается конечное число отдельных деревьев, называемых поддеревьями.
Рассмотрите пример дерева, в узлах которого располагаются символы.
191
A
B
C
F
H
D
G
E
Y
K
J
Для дальнейшей работы с деревьями необходимо определить ряд понятий.
• Вершина у, находящаяся непосредственно ниже вершины х, называется непосредственным потомком х, а вершина х
называется предком у.
• Если вершина не имеет потомков, то она называется терминальной вершиной или листом, если имеет, то называется
внутренней вершиной.
•
Количество непосредственных потомков внутренней вершины называется ее степенью.
•
Степенью дерева называется максимальная степень всех вершин.
Например,
•
•
•
•
•
вершины F, D, E являются непосредственными потомками вершины В;
вершины F, D, E являются листьями;
вершины C, G, H – внутренние;
степень вершины В – 3, а вершины Н – 1;
степень дерева равна 3.
Определение. Двоичное дерево – это дерево, в котором из каждой вершины исходит не более двух ребер.
Задание. Наберите текст программы на компьютере и рассмотрите ее действие. Данная программа демонстрирует
создание произвольного двоичного дерева.
Program DemidenkoS;
Uses
Crt, Graph;
Const
Arr : array [1..6] of integer=(160,80,40,20,10,5);
Arr1 : array [1..6] of integer=(120,80,70,60,50,40);
Type
ss=^sp;
sp=record
elem:byte;
Next : array[1..2] of ss;
end;
Var
a, b, c, d : longint;
s : string;
grDriver : integer;
grMode : integer;
a1, b1 : real;
x, Some, Max, Min : ss;
Procedure Zap(y : ss; n : integer);
Var
aa,bb:integer;
Begin
y^.elem:=random(99)+1;
bb:=random(3);
if n<1
then
bb:=2;
if n<a
then
for aa : =1 to bb do
begin
192
new(y^.next[aa]);
y^.next[aa]^.next[1]:=nil;
y^.next[aa]^.next[2]:=nil;
zap(y^.next[aa],n+1);
end;
End;
Procedure Strel(x1, y1 : integer; k : Real);
Var
aa : Real;
Begin
aa:=arctan(k);
if k>0
then
begin
line(x1,y1,x1+round(10*cos(aa+pi/18)),y1-round(10*sin(aa+pi/18)));
line(x1,y1,x1+round(10*cos(aa-pi/18)),y1-round(10*sin(aa-pi/18)));
line(x1+round(10*cos(aa+pi/18)),y1-round(10*sin(aa+pi/18)),x1+round(10*cos(aa-pi/18)),y1-round(10*sin(aa-pi/18)));
end
else
begin
aa:=-aa;
line(x1,y1,x1-round(10*cos(aa+pi/18)),y1-round(10*sin(aa+pi/18)));
line(x1,y1,x1-round(10*cos(aa-pi/18)),y1-round(10*sin(aa-pi/18)));
line(x1-round(10*cos(aa+pi/18)),y1-round(10*sin(aa+pi/18)),x1-round(10*cos(aa-pi/18)),y1-round(10*sin(aa-pi/18)));
end
end;
Procedure Wiv(y : ss; n, x1, y1 : integer);
Var
spi : ss;
Begin
SetColor(n+1);
Circle(x1,y1,10);
Str(y^.elem, s);
if length(s)=2
then
OutTextXY(x1-6, y1-2, s)
else
OutTextXY(x1-3, y1-2, s);
if n<a
then
begin
if y^.next[1]<>nil
then
begin
SetColor(n+1);
Line(x1,y1+10,x1-(arr[n] div 2),y1+((arr1[n]-20) div 2)+10);
SetColor(n+2);
Line(x1-(arr[n] div 2),y1+((arr1[n]-20) div 2)+10,x1-arr[n],y1+arr1[n]-10);
Strel(x1-arr[n],y1+arr1[n]-10,(arr1[n]-20)/arr[n]);
Wiv(y^.next[1],n+1,x1-arr[n],y1+arr1[n]);
end;
if y^.next[2] <> nil
then
begin
SetColor(n+1);
Line(x1,y1+10,x1+arr[n],y1+arr1[n]-10);
SetColor(n+2);
Line(x1+(arr[n] div 2),y1+((arr1[n]-20) div 2)+10,x1+arr[n],y1+arr1[n]-10);
Strel(x1+arr[n],y1+arr1[n]-10,-(arr1[n]-20)/arr[n]);
Wiv(y^.next[2],n+1,x1+arr[n],y1+arr1[n]);
end;
end;
end;
Begin
ClrScr;
Randomize;
193
Repeat
new(x);
a:=6;
x^.next[1]:=Nil;
x^.next[2]:=Nil;
Zap(x,0);
Max:=x;
Min:=x;
writeln;
grDriver := Detect;
InitGraph(grDriver, grMode,'c:\tp7\bgi\');
SetFillStyle(solidfill,15);
SetColor(15);
Wiv(x,1,320,50);
Delay(5000);
until KeyPressed;
End.
Задание. Поэкспериментируйте над предложенной программой, внося свои изменения. Результат покажите учителю.
Занятие 2. Представление деревьев. Основные операции над деревом.
Дерево – это сложная динамическая структура данных, применяющаяся для эффективного хранения информации.
Очевидно, что для описания требуются ссылки. Опишем, как переменные с фиксированной структурой – сами вершины,
тогда степень дерева будет определять число ссылочных компонент, указывающих на вершины поддеревьев. В бинарном
дереве их два: левое и правое.
Type
TreeLink = ^Tree;
Tree = Record
Data : <тип данных>;
Left, Right : TreeLink;
End;
Корень дерева опишем в разделе описания переменных:
Var
kd : TreeLink;
К основным операциям над деревьями относятся:
•
•
•
занесение элемента в дерево;
обход дерева;
удаление элемента из дерева.
Рассмотрим вставку и обход дерева на примере следующей задачи.
Задача. Создать и вывести на экран дерево, элементы которого вводятся с клавиатуры и имеют целый тип. Причем для
каждой вершины дерева во всех левых вершинах должны находиться числа меньшие, а в правой большие, чем числа,
хранящиеся в этой вершине. Такое дерево называется деревом поиска.
Опишем процедуру вставки в дерево новой вершины. При вставке в дерево вершина вставляется либо как поддерево
уже существующей вершины или как единственная вершина дерева. Поэтому и левая и правая связи новой вершины должны
быть Nil. Когда дерево пусто, значение передаваемое в виде параметра ссылки равно Nil. В этом случае нужно изменить ее
так, чтобы она указывала на новую вершину, которая была вставлена как корневая. При вставке второго элемента
переданный из основной программы параметр t уже не будет равен Nil, и надо принимать решение о том, в какое поддерево
необходимо вставить новую вершину.
Procedure InsTree(n : integer; Var t : TreeLink);
Begin
if t=nil
then
begin
new(t);
with t^ do
begin
Left := nil;
Right := nil;
Data := n;
194
end;
end;
else
if n<=t^.data
then
InsTree(n, t^.Left)
else
InsTree(n, t^.Right)
End;
Опишем процедуру вывода значений элементов двоичного дерева на экран. Для этого необходимо выполнить полный
обход дерева. При обходе дерева его отдельные вершины посещаются в отдельном порядке. Вывод двоичного дерева можно
производить рекурсивно, выполняя для каждой вершины три действия:
•
•
•
вывод числа, хранящегося в узле;
обход левого поддерева;
обход правого поддерева.
Порядок выполнения этих действий определяет способ обхода дерева. Способы вывода:
•
•
•
прямой вывод (сверху вниз);
обратный вывод (слева направо);
концевой вывод (снизу вверх).
Процедура обратного вывода дерева имеет следующий вид:
Procedure PrintTree(t : TreeLink);
Begin
if t<>Nil
then
begin
PrintTree(t^.Left);
Write(t^.Data:3);
PrintTree(t^.Right);
end;
End;
Задание. Написать процедуры прямого и концевого вывода значений элементов дерева.
Основная программа осуществляет ввод чисел с клавиатуры. Используются: переменная nd типа TreeLink – значение
указателя на корень дерева; переменная Digit типа integer для хранения очередного введенного числа.
Begin
writeln('Вводите вершины дерева. Окончание ввода – 0');
kd := nil;
read(Digit);
while Digit <> 0 do
begin
InsTree(Digit, kd);
writeln(' Введите очередное число ');
read(Digit);
end;
PrintTree(kd);
End.
Задание. Напишите программу создания и вывода на экран двоичного дерева, используя свою процедуру вывода.
Протестируйте программу и представьте учителю файл и листинг для оценки.
Занятие 3. Самостоятельное решение задач.
Выберите с учителем одну из предложенных задач.
1. Создайте программой числовое двоичное дерево. Опишите рекурсивную логическую функцию, проверяющую
наличие заданного числа в сформированном дереве. В программе используйте подпрограммы.
2. Создайте программой числовое двоичное дерево. Опишите рекурсивную числовую функцию, подсчитывающую
сумму элементов дерева. В программе используйте подпрограммы.
3. Создайте программой числовое двоичное дерево. Опишите функцию, которая находит наибольший элемент непустого
дерева. В программе используйте подпрограммы.
195
4. Напишите программу, содержащую процедуру, которая каждый отрицательный элемент дерева заменяет на
положительный, а положительный превращает в ноль.
5. Напишите программу, содержащую процедуру, которая каждый элемент дерева возводит в квадрат.
6. Создайте программой символьное двоичное дерево. Опишите функцию, возвращающую строку, сформированную на
базе этих символов. В программе используйте подпрограммы.
7. Создайте программой символьное двоичное дерево. Опишите логическую функцию, проверяющую, есть ли в
непустом дереве хотя бы два одинаковых символа. В программе используйте подпрограммы.
8. Создайте строковое двоичное дерево. Опишите функцию, возвращающую строку, сформированную на базе символов,
встречающихся в каждой строке дерева. В программе используйте подпрограммы.
9. Создайте двоичное дерево записей. Проверьте выбранное поле записей на равенство. В программе используйте
подпрограммы.
10. Создайте программой два числовых двоичных дерева. Опишите рекурсивно и нерекурсивно логическую функцию,
входными параметрами которой являются два дерева, проверяющую на равенство эти деревья. В программе используйте
подпрограммы.
Занятие 4. Идеально сбалансированное дерево.
В дереве поиска можно найти место каждого элемента, двигаясь от корня и переходя на левое или правое поддерево в
зависимости от значений встречающихся данных.
Использование деревьев поиска значительно сокращает время решения задачи.
Правильно организованным деревом считается идеально сбалансированное дерево, то есть для каждой его вершины
количество вершин в левом и правом поддереве различаются не более чем на 1.
Сформируем идеально сбалансированное дерево, элементами которого являются N чисел, вводимых с клавиатуры.
Поскольку требуется построить идеально сбалансированное дерево, то его узлы в процессе построения должны
распределяться равномерно. Сформируем правило равномерного распределения узлов при известном их числе:
•
•
•
Взять один узел в качестве корня.
Построить левое поддерево с числом узлов n1=N div 2 тем же способом.
Построить правое поддерево с числом узлов n2=N-n1-1 тем же способом.
Program BalansTree;
Uses
Crt;
Type
Pt = ^Node;
Node = record
Data : integer;
Left, Right : Pt;
end;
Var
n : integer;
kd : Pt;
f : text;
Function Tree(n : integer) : Pt;
Var
NewNode : Pt;
x, n1, n2 : integer;
Begin
if n=0
then
Tree := Nil
else
begin
n1 := n Div 2;
n2 := n–n1–1;
read(f,x);
new(NewNode);
with NewNode^ do
begin
Data := x;
Left := Tree(n1);
196
Right := Tree(n1);
end;
Tree := NewNode;
end;
End;
Procedure PrintTree(t : Pt; h : integer);
Var
i : integer;
Begin
if t<>nil
then
with t^ do
begin
PrintTree(Left, h+1);
for i := 1 to h do
write(' ');
writeln(Data:6);
PrintTree(Right, h+1);
end;
End;
Begin
ClrScr;
assign(f, 'c:\f.pas');
reset(f);
write('n=');
readln(n);
kd := Tree(n);
PrintTree(kd, 0);
readln;
End.
Задание. Наберите программу, протестируйте ее, вставьте комментарий, приготовьтесь объяснить учителю принцип
построения идеально сбалансированного дерева.
Поиск и включение элемента в дерево.
Задача. Задана последовательность слов. Определить частоту вхождения каждого из слов в последовательности.
Для решения задачи любое слово ищется в дереве, которое на начальном этапе пусто. Если слово найдено, то счетчик
его вхождений увеличивается на 1, если нет, то слово включается в дерево с единичным значением счетчика.
Program Poisk;
Uses
Crt;
Type
Words = ^WordTree;
WordTree = record
Data : string;
k : integer;
Left, Right : Words;
end;
Var
n : integer;
kd : Words;
x : string;
f : text;
Procedure Tree(x : string; Var p : Words);
Begin
if p=nil
then
begin
new(p);
with p^ do
begin
k := 1;
Data := x;
Left := Nil;
Right := Nil;
end;
197
end;
else
if x>p^.Data
then
Tree(x. p^.Left)
else
if x<p^.Data
then
Tree(x. p^.Right)
else
Inc(p^.k);
End;
Procedure PrintTree(t : Words; h : integer);
Var
i : integer;
Begin
if t <> Nil
then
with t^ do
begin
PrintTree(Left, h+1);
for i := 1 to h do
write(' ');
writeln(Data, ',(', k, ')');
PrintTree(Right, h+1);
end;
End;
Begin
ClrScr;
assign(f, 'c:\f.dan');
reset(f);
write('n=');
readln(n);
kd := Nil;
while n>0 do
begin
readln(f,x);
Tree(x, kd);
Dec(n);
end;
close(f);
PrintTree(kd, 0);
readln;
End.
Эта задача называется задачей поиска по дереву с включением.
Задание. Наберите программу, протестируйте ее, вставьте комментарий, приготовьтесь объяснить учителю принцип
поиска по дереву с включением. По желанию можете усложнить текст задачи, усовершенствовать ее решение или внести еще
какие-либо изменения.
Удаление из дерева.
Непосредственное удаление элемента из упорядоченного дерева реализуется достаточно просто, если эта вершина
является конечной или из нее выходит только одно ребро. Для этого нужно изменить соответствующую ссылку у
предшествующей вершины.
Если же из удаляемой вершины выходит две ветви, то нужно найти подходящую вершину дерева, которую можно было
бы вставить на место удаляемой вершины.
198
100
20
100
120
20
15
120
15
35
50
30
25
55
35
30
25
60
55
33
60
33
Çˉ ‰Â¾Â‚‡ ‰Ó Û‰‡ÎÂÌ˽
Çˉ ‰Â¾Â‚‡ ÔÓÒΠۉ‡ÎÂÌ˽
Из вышесказанного следует, что процедура удаления элемента из дерева должна различать три случая.
1. Удаляемая вершина имеет два поддерева. В этом случае удаляемый элемент нужно заменить либо на самый правый
элемент его левого поддерева, либо на самый левый элемент его правого поддерева. При этом они должны иметь не больше
одного потомка.
2. Удаляемая вершина имеет не более одного поддерева (0 или 1).
3. Удаляемой вершины в дереве нет.
Просмотрите рекурсивную процедуру DelTree, которая отыскивает элемент с заданным ключом и удаляет его. В
процедуре DelTree описана процедура d1, которая работает только в первом из трех перечисленных случаев.
Вспомогательная процедура d1 "движется" по правой ветви левого поддерева исключаемого элемента q^ и заменяет
значение ключа в q^ на соответствующее значение из самого правого элемента r^ левого поддерева.
Type
Pt = ^Node;
Node = Record
Data : integer;
Left, Right : Pt;
End;
Procedure DelTree(x : integer; Var p : Pt);
Var
q : Pt;
Procedure D1(Var r : Pt);
Begin
if r^.Right <> Nil
then
d1(r^.Right)
else
begin
q^.Data := r^.Data;
q := r;
r := r^.Left;
Dispose(q);
end;
End;
Begin
if p=nil
then
writeln('Элемента с ключом ', x, 'в дереве нет.')
else
if x<p^.Data
199
then
DelTree(x, p^.Left)
else
if x>p^.Data
then
DelTree(x, p^.Right)
else
begin
q := p;
if q^.Right = Nil
then
begin
p := q^.Left;
dispose(q);
end;
else
if q^.Left = Nil
then
begin
p := q^.Right;
dispose(q);
end;
else
D1(q^.Left)
end;
End;
Задание. Наберите программу, протестируйте ее, вставьте комментарий, приготовьтесь объяснить учителю принцип
удаления элемента из дерева.
Выберите задачу для решения из предложенных ниже.
1. Удалите из дерева все равные между собой элементы. В программе используйте подпрограммы.
2. Удалите из дерева все повторяющиеся элементы. В программе используйте подпрограммы.
3. Постройте два дерева. Проверьте, является ли одно из них поддеревом другого. Если "да", то удалите это поддерево. В
программе используйте подпрограммы.
4. Постройте два дерева. Проверьте, является ли одно из них поддеревом другого. Если "нет", то включите это
поддерево. В программе используйте подпрограммы.
5. Используя очередь или стек, вычислите среднее арифметическое всех элементов непустого дерева Т и удалите все
элементы меньшие этого числа. В программе используйте подпрограммы.
6. Используя очередь или стек, поменяйте местами максимальный и минимальный элементы непустого дерева Т, все
элементы которого различны. В программе используйте подпрограммы.
7. Используя очередь или стек, напечатайте все элементы дерева Т по уровням: сначала – из корня дерева, затем (слева
направо) – из вершин, дочерних по отношению к корню, затем (также слева направо) – из вершин, дочерних по отношению к
этим вершинам, и т.д. В программе используйте подпрограммы.
8. Используя очередь или стек, найдите в непустом дереве Т длину (число ветвей) пути от корня до ближайшей вершины
с элементом Е. Если такого элемента не обнаружено, то выдайте на экран соответствующее сообщение. В программе
используйте подпрограммы.
9. Используя очередь или стек, подсчитайте число вершин на n-ом уровне непустого дерева Т (корень считайте
вершиной 0-го уровня). В программе используйте подпрограммы.
10. Объедините два дерева в одно идеально сбалансированное. В программе используйте подпрограммы.
Задачи для самостоятельного решения (на усмотрение учителя)
1. Напишите программу, содержащую процедуру или функцию, которая присваивает параметру Е элемент из самого
левого листа непустого дерева (лист – вершина, из которой не выходит ни одной ветви), используя очередь или стек. В
программе используйте подпрограммы.
2. Напишите программу, содержащую процедуру или функцию, которая находит в непустом дереве длины (число
ветвей) путей от корня до всех вершин, используя очередь или стек. В программе используйте подпрограммы.
3. Напишите программу, содержащую процедуру или функцию, которая подсчитывает число вершин на каждом уровне
непустого дерева (корень считать вершиной 0-го уровня). В программе используйте подпрограммы.
200
4. Напишите программу, содержащую процедуру или функцию, которая определяет максимальную глубину непустого
дерева Т, т.е. число ветвей в самом длинном из путей от еорня дерева до листьев. В программе используйте подпрограммы.
5. Напишите программу, содержащую процедуру, которая строит Т1 – копию дерева Т. В программе используйте
подпрограммы.
6. Напишите программу, содержащую процедуру Create(T,n), где n – положительное целое число, которая строит Т –
дерево, изображенное на рисунке. В программе используйте подпрограммы.
n
n-1
n-1
2
1
2
1
1
1
7. Напишите программу, содержащую процедуру Create(T,n), где n – положительное целое число, которая строит Т –
дерево, изображенное на рисунке. В программе используйте подпрограммы.
1
2
2
n-1
n-1
n
n
n
n
8. Формулу вида
<формула>::=<терминал>|(<формула><знак><формула>)
<знак>::=+|-|*
<терминал>::=0|1|2|3|4|5|6|7|8|9
можно представить в виде двоичного дерева ("дерева-формулы") с элементами типа char согласно следующим правилам:
формула из одного терминала (цифры) представляется деревом из одной вершины с этим терминалом, а формула вида (f1sf2)
– деревом, в котором корень – это знак s, а левое и правое поддеревья – это соответствующие представления формул f1 и f2.
Для примера посмотрите как будет выглядеть дерево, соответствующее формуле (5*(3+8)).
Опишите рекурсивную функцию или процедуру, которая:
а) вычисляет (как целое число) значение дерева-формулы Т);
б) по формуле из текстового файла f строит соответствующее дерево-формулу Т;
в) печатает дерево-формулу Т в виде соответствующей формулы;
г) проверяет, является ли двоичное дерево Т деревом-формулой.
9. Пусть в дереве-формуле (см. предыдущую задачу) в качестве терминалов используются не только цифры, но и буквы,
играющие роль переменных. Опишите процедуру, которая:
а) упрощает дерево-формулу Т, заменяя в нем все поддеревья, соответствующие формулам (f+0), (0+f), (f-0), (f*1), (1*f)
на поддеревья, соответствующие формуле f, а поддеревья, соответствующие формулам (f*0) и (0*f), на вершину с 0;
б) преобразует дерево-формулу Т, заменяя в нем все поддеревья соответствующие формулам ((f1+f2)*f3, (f1-f2)*f3) и
(f1*(f2+f3), f1*(f2-f3)) на поддеревья, соответствующие формулам ((f1*f3)+(f2*f3), (f1*f3)-(f2*f3)) и ((f1*f2)+(f1*f3), (f1*f2)(f1*f3)).
10. Во внешнем текстовом файле записана (без ошибок) некоторая программа на языке Паскаль. Известно, что в этой
программе каждый идентификатор (служебное слово или имя) содержит не более 9 латинских букв и/или цифр. Напечатайте
в алфавитном порядке все различные идентификаторы этой программы, указав для каждого из них число его вхождений в
201
текст программы. Необходимо учесть, что в идентификаторах одноименные прописные и строчные буквы отождествляются,
что внутри литерных значений, строк-констант и комментариев последовательности из букв и цифр не являются
идентификаторами и что в записи вещественных чисел может встретиться буква Е или е.
202
СТЕК
Занятие 1. Стек. Отличия стека от списка. Основные операции со стеком.
На предыдущих занятиях мы уже рассматривали однонаправленный список. Здесь Вы познакомитесь с двумя
разновидностями обычного линейного списка – стеком и очередью. В программировании наиболее часто используемой
структурой является стек.
Стек – это линейный список, в котором добавление новых элементов и удаление существующих производится только с
одного конца, называемого вершиной стека.
Стек часто называют структурой LIFO [сокращение LIFO означает Last In – First Out (последний пришел, первый
вышел)]. Это сокращение представляет удобный способ запомнить механизм работы стека
Изобразим стек графически:
Head
Data
Data
Data
Next
Next
Next
Nil
При программировании на Паскале стек реализуется чаще всего в виде однонаправленного списка. Каждый элемент
структуры содержит указатель на следующий. Считается лишь, что для этого списка не существует обход элементов.
Доступ возможен только к верхнему элементу структуры.
Стек предполагает вставку и удаление элементов, поэтому он является динамической, постоянно меняющейся
структурой.
Стеки довольно часто встречаются в практической жизни. Простой пример: детская пирамидка. Процесс ее сборки и
разборки подобен процессу функционирования стека.
Итак, если стек – это список, то добавление или извлечение элементов происходит с начала и только с начала (или
возможно с конца и только с конца) списка.
Значением указателя, представляющего стек, является ссылка на вершину стека, каждый элемент стека содержит поле
ссылки.
Таким образом, описать стек можно следующим образом:
Type
EXST = ^ST;
ST = record
Data : integer;
Next : EXST;
end;
Var
203
Stack : EXST;
{Текущая переменная}
Если стек пуст, то значение указателя равно Nil.
Рассмотрим возможные операции со стеком.
Занесение элемента в стек
Занесение элемента в стек производится аналогично вставке нового элемента в начало списка. Процедура занесения
элемента в стек должна содержать два параметра: первый задает вершину стека, в который нужно занести элемент, второй –
заносимое значение элемента стека.
Процедура формирования стека будет иметь следующий вид:
Procedure FormStack;
Var
Stack : EXST;
{Текущая переменная}
Digit : integer;
Procedure writeStack(Var u : EXST; Digit : integer);
Var
x : EXST;
Begin
new(x);
{выделяем память под хранение нового элемента стека}
x^.Data := Digit; {заполняем поле данных элемента}
x^.Next := u;
{новый элемент "связываем" со стеком}
u := x;
{созданный элемент определяем как вершину стека}
End;
Begin
Stack := Nil; {инициализация стека}
writeln('Введите элементы стека. Окончание ввода – 0');
read(Digit);
while Digit <> 0 do
begin
writeStack(Stack, Digit);
read(Digit);
end;
End;
Извлечение элемента из стека
В результате выполнения этой операции некоторой переменной i должно быть присвоено значение первого элемента
стека и значение указателя на начало списка должно быть перенесено на следующий элемент стека.
Procedure readStack(Var u : EXST; Var i : integer);
Var
x : EXST;
Begin
i := u^.Data; {считываем значение поля данных в переменную}
x := u; {запоминаем адрес вершины стека}
u := u^.Next; {переносим вершину стека на следующий элемент}
dispose(x); {освобождаем память, занятую уже ненужным элементом стека}
End.
Недостатком описанной процедуры является предположение о том, что стек не пуст. Для его исправления следует
разработать логическую функцию проверки пустоты обрабатываемого стека.
Function FreeStack(u : EXST) : boolean;
Задание. Описать функцию и закончить программу, для чего описать процедуру вывода значений элементов стека на
экран (она аналогична выводу списка). Протестировать программу, дополнить комментарием и показать файл и листинг
учителю для оценки.
Чтобы наглядно рассмотреть работу стека, наберите следующую программу.
Program Demidenko;
Uses
Crt, Graph;
Type
sp=^spis;
ecord
elem : byte;
next : sp;
204
End;
Var
a, b : byte;
s : string;
gd, gm, c : integer;
head, some, x : sp;
bol : boolean;
ch : char;
Procedure OutX(x, y : integer);
Begin
Line(x+50,y+10,x+70,y+10);
Line(x+50,y+10,x+55,y+10-3);
Line(x+50,y+10,x+55,y+10+3);
Line(x+55,y+13,x+55,y+10-3);
OutTextXY(x+70,y+10,'x');
End;
Procedure Wiv (x, y : integer; ss : sp);
Begin
Line(x,y,x+50,y);
Line(x,y,x,y+20);
Line(x,y+20,x+50,y+20);
Line(x+50,y,x+50,y+20);
Line(x+30,y,x+30,y+20);
if some=ss
then
Begin
Line(x+50,y+10,x+70,y+10);
Line(x+50,y+10,x+55,y+10-3);
Line(x+50,y+10,x+55,y+10+3);
Line(x+55,y+13,x+55,y+10-3); End;
Str(ss^.elem, s);
OutTextXY(x+10,y+10,s);
if (ss^.next<>nil)
then
Begin
Line(x+40,y+10,x+40,y+40);
Line(x+40,y+40,x+37,y+40-5);
Line(x+40,y+40,x+43,y+40-5);
Line(x+43,y+40-5,x+37,y+40-5);
Wiv(x,y+40,ss^.next);
End
else
Begin
Line(x+40,y+10,x+40,y+30);
Line(x+40,y+30,x+37,y+25);
Line(x+40,y+30,x+43,y+25);
Line(x+43,y+25,x+37,y+25);
Line(x+35,y+32,x+45,y+32);
Line(x+36,y+35,x+44,y+35);
Line(x+38,y+38,x+42,y+38);
End;
End;
Procedure Insertsp(x : byte);
Begin
Cleardevice;
OutTextXY(50,20,'NEW(X)');
new(some);
Line(20,100,20+50,100);
Line(20,100,20,100+20);
Line(20,100+20,20+50,100+20);
Line(20+50,100,20+50,100+20);
Line(20+30,100,20+30,100+20);
Outx(20,100);
if head<>nil
then
Wiv(20,140,head);
205
Delay(1000);
Cleardevice;
OutTextXY(50,20,'X^.NEXT:=TAIL');
OutTextXY(50,40,'TAIL:=X');
some^.next:=head;
head:=some;
Wiv(20,100,head);
Delay(1000);
Cleardevice;
Str(x,s);
OutTextXY(50,20,'SOME^.ELEM:='+s);
some^.elem:=x;
Wiv(20,100,head);
Delay(1000);
End;
Procedure DelSp;
Begin
Cleardevice;
if head=nil
then
Begin
Y(50,20,'Элемент не существует!');
Delay(1000);
End
else
if head^.next<>nil
then
Begin
OutTextXY(50,20,'X:=TAIL');
OutTextXY(50,40,'TAIL:=TAIL^.NEXT');
some:=some^.next;
Wiv(20,100,head);
OutX(20,100);
Delay(1000);
Cleardevice;
OutTextXY(50,20,'DISPOSE(X)');
Wiv(20,100,head);
OutX(20,100);
Setcolor(red);
Line(20,90,70,130);
Line(70,90,20,130);
Setcolor(white);
Delay(1000);
Cleardevice;
head:=head^.next;
some:=head;
Wiv(20,100,head);
End
else
Begin
OutTextXY(50,20,'DISPOSE(TAIL)');
Wiv(20,100,head);
Setcolor(red);
Line(20,90,70,130);
Line(70,90,20,130);
Setcolor(white);
Delay(1000);
ClearDevice;
head:=nil;
some:=head;
End;
End;
Begin
ClrScr;
bol:=false;
gD := Detect;
206
InitGraph(gD, gM,'c:\tp7\bgi\');
TextBackGround(black);
Setbkcolor(black);
Head:=nil;
Some:=head;
Repeat
OutTextXY(250,200,'1 * Добавить элемент');
OutTextXY(250,220,'2 * Удалить элемент');
OutTextXY(250,240,'Esc Выход');
ch:=readkey;
case ch of
'1' : Begin
OutTextXY(250,260,'Введите число:');
gotoxy(48,17);
readln(b);
InsertSp(b);
End;
'2' : delsp;
#27 : Begin
CloseGraph;
Halt;
End;
End;
until bol;
CloseGraph;
End.
Примеры решения задач.
Пример 1. Используя стек, напечатать содержимое текстового файла, выписывая литеры каждой его строки в обратном
порядке.
Program MordovskihK;
Type
EXST = ^ST;
ST = record
Data : char;
Next : EXST;
End;
Var
Stack : EXST;
{Текущая переменная}
i : integer;
f : text;
Stroka : string;
c : char;
Procedure writeStack(Var u : EXST; Simvol : char);
Var
x : EXST;
Begin
new(x);
x^.Data := Simvol;
x^.Next := u;
u := x;
End;
Procedure Print(Var u : EXST);
Begin
while u <> Nil
Begin
write (u^.Data);
u := u^.Next;
End;
End;
Begin
Stack := Nil;
Assign(f, 'c:\autoexec.bat');
Reset(f);
while Not Eof(f) do
207
Begin
readln (f, Stroka);
For i := 1 to Length(Stroka) do
writeStack(Stack, Stroka[i]);
End;
close(f);
Print(Stack);
End.
Пример 2. Написать программу, проверяющую своевременность закрытия скобок в строке символов.
Для решения задачи определим стек, элементами которого являются символы:
Type
EXST = ^ST;
ST = record
Data : char;
Next : EXST;
End;
Будем двигаться по строке а : string до ее конца. Если в процессе просмотра встретится одна из закрывающихся скобок
({, (, [ ), занесем ее в стек. При обнаружении закрывающейся скобки, соответствующей скобке, находящейся в вершине
стека, последняя удаляется. При несоответствии скобок выдается сообщение об ошибке.
Пусть факт наличия ошибки хранится в переменной логического типа f, то есть f=True, пока ошибка не найдена и
f=False в противном случае. Тогда условие работы цикла будет выглядеть так:
while (i<>Length(a)) and f do ...
Осталось выяснить, как определить, соответствует ли очередная закрывающаяся скобка скобке, находящейся в вершине
стека. Можно заметить, что коды соответствующих друг другу скобок отличаются не более чем на 2, что можно проверить с
помощью функции Ord(x)):
{}
[]
()
123–125
91–93
40–41
Причем код открывающейся скобки меньше. То есть можно записать следующее условие соответствия:
if (Ord(a[i]–Ord(stack^.Data))<=2
then
...
А теперь просмотрите полный текст программы:
Program Skobki;
Type
EXST = ^ST;
ST = record
Data : char;
Next : EXST;
end;
Var
a : string;
f : boolean;
i : integer;
Procedure writeStack(Var x1 : EXST; c : integer);
Var
u : EXST;
Begin
new(u);
{создание нового элемента стека}
u^,Data := c;
u^.Next := x1;
x1 := u;
{созданный элемент определить как вершину стека}
End;
Procedure DelStack(Var x1 : EXST); {процедура удаления верхнего элемента стека}
Var
u : EXST;
Begin
u := x1;
x1 := x1^.Next;
dispose(u);
208
End.
Procedure Solve(a : string); {процедура правильности расстановки скобок}
Var
Stack : EXST;
Begin
Stack := Nil;
i := 1;
while (i<=Length(a)) and f do
begin
if (a[i]='(') or (a[i]='{') or (a[i]='[')
then
writeStack(Stack , a[i])
else
if (a[i]=')') or (a[i]='}') or (a[i]=']')
then
if Ord(Stack ^.Data)–Ord(a[i])<=2
then
DelStack(Stack)
else
f := False;
Inc(i);
end;
End.
Begin
writeln('Введите строку');
readln(a);
f := True;
if a<>' '
then
begin
Solve(a);
if f
then
writeln('Все скобки расставлены верно')
else
writeln('Скобка ',a[i-1],' закрыта преждевременно');
end
else
writeln('Строка пуста');
readln;
End.
Задание. Объясните учителю алгоритмы решения предложенных задач.
Занятие 2. Самостоятельное решение задач
1. Создать текстовый файл, содержащий текстовую и числовую информацию. Используя стек, создать другой текстовый
файл, в котором числа были бы записаны в обратном порядке.
2. Создать текстовый файл, содержащий текстовую информацию. Используя стек, создать другой текстовый файл, в
котором слова были бы записаны в обратном порядке.
3. Создать текстовый файл, содержащий некоторую информацию. Используя стек, создать другой текстовый файл, в
котором строки были бы записаны в обратном порядке.
4. Создать текстовые файлы, содержащие один текстовую, а другой числовую информацию (количество слов и чисел
должно быть одинаковым). Используя стек, создать другой текстовый файл, в котором числа и слова чередовались и были бы
записаны в обратном порядке.
5. Создать текстовые файлы, содержащие один текстовую, а другой числовую информацию (количество слов и чисел
должно быть одинаковым). Используя стек, создать другой текстовый файл, в котором числа и слова чередовались, а порядок
чисел и слов был бы сохранен.
6. Создать текстовые файлы, содержащие один текстовую, а другой числовую информацию (количество слов и чисел
может быть неодинаковым). Используя стек, создать другой текстовый файл, в котором числа и слова чередовались и были
бы записаны в обратном порядке ("лишние" числа или слова были бы записаны в конец файла).
209
7. В файле находится текст программы на Паскале. Используя стек, проверить правильность вложений циклов в этой
программе.
8. В файле находится текст программы на Паскале. Используя стек, проверить правильность вложений операторных
скобок (begin - end) в этой программе.
9. В файле записан текст, сбалансированный по круглым скобкам. Требуется для каждой пары соответствующих
открывающей и закрывающей скобок напечатать номера их позиций в тексте, упорядочив пары номеров по возрастанию
номеров позиций закрывающих скобок. Напимер, для текста a+(45-f(x)*(b-c)) на до напечатать 8 10, 12 16, 3 17.
10. В текстовом файле без ошибок записано логическое выражение следующего вида:
<лог.выр>::=true | false | <лог.выр> and <лог.выр> | <лог.выр> or <лог.выр>
Используя стек, вычислить значение этого выражения с учетом общепринятого приоритета операций.
Занятие 3. Очереди. Основные операции над очередью.
Очередь – линейный список, элементы в который добавляются только в конец, а исключаются из начала.
Изобразим очередь графически:
Head
Data
Next
Data
Next
Data
Next
Nil
При программировании на Паскале также считается, что для очереди не существует обход элементов. Доступ возможен
только к нижнему элементу структуры.
Итак, очередь – это вид связанного списка, в котором извлечение элементов происходит с начала списка, а добавление
новых элементов – с конца.
Очередь является динамической структурой – с течением времени изменяется и ее длина, и набор составляющих ее
элементов.
Опишем очередь на языке программирования:
Type
EXO = ^O;
O = record
Data : integer;
Next : EXO;
end;
Над очередью определены две операции: занесение элемента в очередь и извлечение элемента из очереди.
В очереди, в силу ее определения, доступны две позиции: ее конец, куда заносятся новые элементы, и ее начало, откуда
извлекаются элементы. Поэтому для работы с очередью необходимо описать две переменные:
Var
BeginO, EndO : EXO;
где BeginO – соответствует началу очереди и будет использоваться для вывода элемента из очереди, EndO –
соответствует концу очереди и будет использоваться для добавления новых элементов в очередь.
210
Занесение элемента в очередь
Занесение элемента в очередь соответствует занесению элемента в конец списка. Рассмотрите процедуру, описанную
ниже.
Procedure writeO(Var BeginO, EndO : EXO; c : integer);
Var
u : EXO;
Begin
new(u);
u^.Data := c;
u^Next := Nil;
if BeginO =Nil {проверяем пуста ли очередь}
then
BeginO := u {ставим указатель начала очереди на первый созданный элемент}
else
EndO^.Next := u;
{ставим созданный элемент в конец очереди}
EndO := u; {переносим указатель конца очереди на последний элемент}
End;
Задание. Создайте программу формирования очереди с использованием предложенной процедуры.
Извлечение элемента из очереди
Процедура извлечения элемента из очереди аналогична удалению элемента из начала списка. Поскольку извлечение
элемента из пустой очереди осуществить нельзя, опишем логическую функцию, проверяющую, есть ли элементы в очереди.
Procedure readO(Var BeginO, EndO : EXO; Var c : integer);
Var
u : EXO;
Function FreeO(x1 : EXO): boolean;
Begin
FreeO := (x1=Nil);
End;
Begin
if FreeO(BeginO)
then
writeln('Очередь пуста');
else
begin
c := BeginO^.Data; {считываем искомое значение в переменную с}
u := BeginO; {ставим промежуточный указатель на первый элемент очереди}
BeginO := BeginO^.Next;{указатель начала переносим на следующий элемент}
dispose(u); {освобождаем память, занятую уже ненужным первым элементом}
end;
End;
Задание. Напишите программу, содержащую все необходимые процедуры и функции работы с очередью.
Задание. Чтобы наглядно рассмотреть работу очереди, наберите следующую программу.
Program Demidenko;
Uses
Crt, Graph;
Type
sp=^spis;
spis=record
elem : byte;
next : sp;
End;
Var
a,
b : byte;
s : string;
gd, gm, c : integer;
head, some, x : sp;
bol : boolean;
ch : char;
Procedure OutHead(x, y : integer);
Begin
211
Line(x+20,y+35,x+20,y+20);
Line(x+20,y+20,x+17,y+25);
Line(x+20,y+20,x+23,y+25);
Line(x+23,y+25,x+17,y+25);
OutTextXY(x+6, y+38, 'head');
End;
Procedure OutX(x, y : integer);
Begin
Line(x+40,y-15,x+40,y);
Line(x+40,y,x+37,y-5);
Line(x+40,y,x+43,y-5);
Line(x+43,y-5,x+37,y-5);
OutTextXY(x+28,y-25,'x');
End;
Procedure wiv(x,y:integer;ss:sp);
Begin
Line(x,y,x+50,y);
Line(x,y,x,y+20);
Line(x,y+20,x+50,y+20);
Line(x+50,y,x+50,y+20);
Line(x+30,y,x+30,y+20);
if some=ss
then
Begin
Line(x+40,y-15,x+40,y);
Line(x+40,y,x+37,y-5);
Line(x+40,y,x+43,y-5);
Line(x+43,y-5,x+37,y-5);
OutTextXY(x+28,y-25,'tail');
End;
if ss^.elem<255
then
Begin
str(ss^.elem,s);
outtextxy(x+10,y+10,s);
End;
if ss^.next<>nil
then
Begin
Line(x+40,y+10,x+60,y+10);
Line(x+60,y+10,x+60,y-10);
Line(x+60,y-10,x+100,y-10);
Line(x+100,y-10,x+100,y);
Line(x+100,y,x+97,y-5);
Line(x+100,y,x+103,y-5);
Line(x+103,y-5,x+97,y-5);
Wiv(x+70, y, ss^.next);
End
else
Begin
Line(x+40,y+10,x+40,y+30);
Line(x+40,y+30,x+37,y+25);
Line(x+40,y+30,x+43,y+25);
Line(x+43,y+25,x+37,y+25);
Line(x+35,y+32,x+45,y+32);
Line(x+36,y+35,x+44,y+35);
Line(x+38,y+38,x+42,y+38);
End;
End;
Procedure InsertOch(x : byte);
Begin
Cleardevice;
OutTextXY(50,20,'NEW(SOME^.NEXT)');
new(some^.next);
some^.next^.next:=nil;
some^.next^.elem:=255;
212
Wiv(20,100,head^.next);
OutHead(20,100);
Delay(1000);
Cleardevice;
OutTextXY(50,20,'SOME:=SOME^.NEXT');
some := some^.next;
some^.next := nil;
Wiv(20,100,head^.next);
OutHead(20,100);
Delay(1000);
Cleardevice;
Outtextxy(50,20,'SOME^.NEXT:=NIL');
Str(x,s);
OutTextXY(50,40,'SOME^.ELEM:='+s);
some^.elem := x;
Wiv(20,100,head^.next);
OutHead(20,100);
Delay(1000);
end;
Procedure DelOch;
Begin
Cleardevice;
if head^.next^.elem=255
then
Begin
OutTextXY(50,20,'Элемент не существует!');
Delay(1000);
End
else
if head^.next^.next<>nil
then
Begin
OutTextXY(50,20,'X:=HEAD');
OutTextXY(50,40,'HEAD:=HEAD^.NEXT');
Wiv(20,100,head^.next);
OutX(15,100);
OutHead(90,100);
Delay(1000);
Cleardevice;
OutTextXY(50,20,'DISPOSE(X)');
Wiv(20,100,head^.next);
OutX(20,100);
OutHead(90,100);
Setcolor(red);
Line(20,90,70,130);
Line(70,90,20,130);
Setcolor(white);
Delay(1000);
Cleardevice;
head:=head^.next;
Wiv(20,100,head^.next);
OutHead(20,100);
End
else
Begin
OutTextXY(50,20,'DISPOSE(HEAD)');
Wiv(20,100,head^.next);
OutHead(20,100);
setcolor(red);
Line(20,90,70,130);
Line(70,90,20,130);
setcolor(white);
delay(1000);
cleardevice;
OutHead(20,100);
head^.next^.elem:=255;
213
some:=head;
End;
End;
Begin
TextBackGround(black);
ClrScr;
bol:=false;
gD := Detect;
InitGraph(gD, gM,'c:\tp7\bgi\');
new(head);
some:=head;
some^.next:=nil;
Repeat
OutTextXY(50,200,'1 * Добавить элемент');
OutTextXY(50,220,'2 * Удалить элемент');
OutTextXY(50,240,'Esc Выход');
ch:=readkey;
case ch of
'1' : Begin
OutTextXY(50,260,'Введите число:');
Gotoxy(23,17);
readln(b);
InsertOch(b);
End;
'2' : DelOch;
#27 : Begin
CloseGraph;
Halt;
End;
End;
until bol;
CloseGraph;
End.
Примеры решения задач
Задание. Рассмотрите приведенные примеры задач. Наберите программы на компьютере, дополните их комментарием и
протестируйте их. Имейте в виду, что уже рассмотренные выше подпрограммы в текстах задач пропущены. Будьте готовы
объяснить учителю алгоритмы решения задач и продемонстрировать их графически.
Пример 1. За один просмотр файла действительных чисел и с использованием очереди напечатать элементы файла в
следующем порядке: сначала – все числа, меньшие а, затем – все числа из отрезка [а, b], и наконец – все остальные числа,
сохраняя исходный порядок в каждой из этих трех групп чисел. Числа а и b задает пользователь.
Program MordovskihK;
Type
EXO = ^O;
O = record
Data : integer;
Next : EXO;
End;
Var
i : Real;
Min, Vibr, Other, EndMin, EndVibr, EndOther : EXO;
f : File of real;
Stroka : string;
Procedure writeO(Var BeginO, EndO : EXO; c : real);
. . .
Procedure PrintO(u : EXO);
. . .
Begin
Min := Nil;
Vibr := Nil;
Other := Nil;
EndMin := Nil;
EndVibr := Nil;
EndOther := Nil;
writeln ('Введите имя файла >');
214
readln(Stroka);
writeln ('Введите промежуток >');
readln(a, b);
assign(f, Stroka);
reset(f);
while not Eof(f) do
begin
read(f, i);
if i<a
then
writeO(Min, x, i)
else
if (i>=a) and (i<=b)
then
writeO(Vibr, x, i)
else
writeO(Other, x, i)
end;
close(f);
writeln('Числа, меньшие ', а);
Print(Min);
writeln('Числа из промежутка [', а, b, ']');
Print(Vibr);
writeln('Числа, большие ', b);
Print(Other);
End.
Пример 2. Из заданного текста перенести все цифры в конец каждой строки, сохранив их порядок.
Program BaranovA;
Type
EXO = ^O;
O = record
Data : integer;
Next : EXO;
End;
Var
i : integer;
O1, EndO1, O2, EndO2 : EXO;
f1, f2 : text;
Name, NewName, Stroka, NewStroka : string;
Procedure writeO(Var BeginO, EndO : EXO; k : char);
. . .
Procedure readO(u : EXO);
. . .
ModifStr(St : string, NewSt : string);
Var
l : char;
O1 := Nil;
EndO1 := Nil;
O2 := Nil;
EndO2 := Nil;
NewSt := '';
for i := 1 to Length(St) do
if St[i] in ['1', '2', '3', '4', '5', '6', '7', '8', '8', '9', '0']
then
writeO(O2, EndO2, St[i])
else
writeO(O1, EndO1, St[i]);
while O1 <> Nil do
begin
readO(O1, EndO1, l);
NewSt := NewSt + l;
end;
while O2 <> Nil do
begin
readO(O2, EndO2, l);
215
NewSt := NewSt + l;
end;
End;
Begin
write('Введите имя исходного файла: ');
readln(Name);
write('Введите имя файла-результата: ');
readln(NewName);
assign(f1, Name);
assign(f2, NewName);
reset(f1);
rewrite(f2);
while not Eof(f1) do
begin
readln(f1, Stroka);
ModifStr(Stroka, NewStroka);
writeln(f2, NewStroka);
end;
close(f1);
close(f2);
End.
Занятие 4. Самостоятельное решение задач
Задачи для самостоятельного решения:
1. Дан текстовый файл. Проанализировав в программе содержимое файла, выберите из него числа и занесите в очередь.
Выведите содержимое очереди на экран и посчитайте сумму этих чисел. Решение в программе оформляйте через
подпрограммы.
2. Дан текстовый файл. Проанализировав в программе содержимое файла, выберите из него имена и занесите в очередь.
Выведите содержимое очереди на экран и посчитайте количество элементов образованной очереди. Решение в программе
оформляйте через подпрограммы.
3. Проверьте на равенство две очереди. Решение в программе оформляйте через подпрограммы.
4. Найдите среди трех (4, 5) очередей две одинаковые. Решение в программе оформляйте через подпрограммы.
5. Организовать три очереди с одинаковым количеством элементов, содержащие соответствено имена, отчества и
фамилии людей. Составьте очередь из элементов, содержащих наиболее полную информацию о людях, воспользовавшись
уже созданными очередями и запросив какую-то дополнительную информацию. Решение в программе оформляйте через
подпрограммы.
6. Создайте файл символьного типа. Организовывая очереди по N элементов, cоздайте файл слов по N символов в
каждом. Решение в программе оформляйте через подпрограммы.
7. Создайте файл целого типа. Проанализировав в программе содержимое файла, создайте одну очередь однозначных
чисел, а вторую очередь двузначных чисел. Перемножьте соответственные элементы двух очередей и организуйте третью
очередь. Результат выведите в текстовый файл. Решение в программе оформляйте через подпрограммы.
8. Используя очередь, проверьте, какие строки текстового файла являются симметричными. Решение в программе
оформляйте через подпрограммы.
9. Используя очередь, проверьте на равенство два текстовых файла. Решение в программе оформляйте через
подпрограммы.
10. Создайте две очереди. Проверьте, является ли одна из очередей частью другой. Решение в программе оформляйте
через подпрограммы.
Занятие 5. Кольцо. Формирование кольца. Основные операции над кольцом.
Koльцо - это вид связанного списка, в котором указатель последнего элемента ссылается на первый элемент.
Рассмотрите его графическое представление.
216
u
Data Next
Data Next
Data Next
Data Next
При программировании на Паскале считается, что для кольца существует обход элементов. Доступ возможен к любому
элементу структуры.
Кольцо является динамической структурой – в зависимости от пользователя программы может изменяется длина и
набор составляющих его элементов.
Опишем кольцо на языке программирования:
Type
TypeCircle = ^K;
K = record
Data : integer;
Next : TypeCircle;
End;
Var
Circle1 : TypeCircle;
Формирование кольца
Рассмотрите процедуру формирования кольца. Для работы этой процедуры заводятся две локальные переменные типа
TypeCircle для хранения адресов промежуточного и завершающего звена списка, последним оператором преобразуемого в
кольцо.
Procedure FofmK(Var u : TypeCircle);
Var
x, y : TypeCircle;
i, N : integer;
Begin
write('Введите количество звеньев кольца: ');
readln(N);
for i := 1 to N do
begin
new(x); {выделяем память для хранения нового элемента кольца}
write('Введите данные в звено: ');
readln(i);
x^.Data := i; {заносим информацию в поле данных}
if u=nil {если кольцо еще не создано}
then
u := x {то указатель первого элемента ставим на новый элемент}
else
y^.Next := x; {присоединяем новый элемент к последнему элементу}
y := x; {переносим указатель у на последний элемент}
end;
x^.Next := u; {преобразуем получившийся список в кольцо}
End;
Над кольцом определены три операции: занесение элемента в кольцо, извлечение элемента из кольца и обход кольца.
Задание. Составьте программу, содержащую две процедуры: процедуру занесения элемента в кольцо и процедуру
извлечения элемента из кольца по какому-либо условию. (Можно воспользоваться предыдущим текстом программы.)
Обход кольца
Для того чтобы обойти кольцо и вывести на экран содержащуюся в нем информацию, необходимо в локальной
переменной типа TypeCircle запомнить адрес первого выводимого элемента. В этом случае можно избежать повторения и
зацикливания программы. Вывод данных можно начинать с любого элемента кольца; это зависит от адреса первого элемента,
переданного в процедуру обхода.
Рассмотрите процедуру обхода кольца.
Procedure PrintК(u : TypeCircle);
Var
x : TypeCircle;
217
Begin
x := u;
repeat
write(x^.Data,' ');
x := x^.Next;
until x=u;
readln;
End;
Задание. Дополните предыдущую программу процедурой обхода кольца.
Занятие 6. Примеры решения задач с применением динамической структуры кольцо.
Творческая работа.
Задание. Рассмотрите приведенные примеры задач, решенные с помощью динамической структуры – кольцо. Наберите
их на компьютере, проверьте их действие, вставьте комментарий.
Задача 1. N ребят располагаются по кругу. Начав отсчет от первого, удаляют каждого k-го, смыкая при этом круг.
Определить порядок удаления ребят из круга.
Для хранения данных об участниках игры используется список.
Наберите предложенный ниже текст программы, проверьте его работу, дополните комментариями.
Program Schitalka;
Type
Children = ^Child;
Child = record
Data : integer;
Next : Children;
end;
Var
Circl, p, Temp : Children;
i, j, NumName : integer;
text : string;
Function NumSlov(Var S : string) : integer;
Var
i, d : integer;
Begin
d := 0;
i := 1;
while i < Length(S) do
begin
while S[i] = ' ' do
Inc(i);
while S[i] <> ' ' do
Inc(i);
d := d+1;
end;
if S[Length(S)] = ''
then
d := d-1;
NumSlov := d;
End;
Procedure AddName(Var Old, Young : Children);
Begin
Young^.Next := Old;
Young^.Prev := Old^.Prev;
Old^.Prev^.Next := Young;
Old^.Prev := Young;
End;
Procedure DeleteName(Var Old : Children);
Begin
Old^.Next^.Prev := Old^.Prev;
Old^.Prev^.Next := Old^.Next;
End;
Begin
218
new(Circl);
Circl^.Next := Circl;
Circl^.Prev := Circl;
Circl^.Name := '';
writeln('Считалка');
writeln('Введите текст считалки >');
readln(text);
writeln('Сколько человек в кругу? >');
readln(NumName);
if NumName>0
then
begin
write('Введите ',i,'-е имя: ');
new(p);
readln(p^.name);
temp := head^.next;
while temp <> head do
temp := temp^.next;
AddName(temp, p);
end;
for i := 1 to NumName-1 do
begin
temp := head;
for j := 1 to NumSlov(text) do
begin
temp := temp^.next;
if temp^.name = ''
then
temp :=temp^.next;
end;
writeln(temp^.name, '- вышел');
deleteName(temp);
end;
writeln(head^.next^.name, '- остался');
End.
Пример 2. Вывести на экран работающий светофор.
Program GrushinK;
Uses
Crt, Graph;
Type
TypeCircle = ^K;
K = record
Data : char;
Next : TypeCircle;
end;
Const
XX = 80;
R = 50;
Var
Svetofor, x : TypeCircle;
FraphDriver, GraphMode, Y : integer;
Procedure Picture;
Begin
SetViewPort(240, 1, 400, 477, ClipOff);
Line(0, 1, 0, 477);
Line(160, 1, 160, 477);
Line(0, 1, 160, 1);
Line(0, 477, 160, 477);
Line(0, 150, 156, 150);
Line(0, 330, 156, 330);
Line(-240, 480, 0, 100);
Line(400, 480, 160, 100);
Line(380, 460, 160, 460);
Line(160, 440, 368, 440);
Line(368, 440, 380, 460);
219
Line(-220, 460, -208, 440);
SetFillStyle(1, White);
FloodFill(375, 455, White);
FloodFill(-215, 455, White);
SetFillStyle(7, 6);
FloodFill(-230, 200, White);
SetColor(4);
Line(-240, 150, -120, -1);
Line(400, 150, 240, -1);
SetColor(15);
SetFillStyle(9, 4);
FloodFill(-240, 0, 4);
FloodFill(390, 10, 4);
SetFillStyle(1, 8);
FloodFill(-100, 470, White);
Y := 74;
Circle(XX, Y, R);
Y := 240;
Circle(XX, Y, R);
Y := 405;
Circle(XX, Y, R);
SetFillStyle(9, 6);
FloodFill(5, 5, White);
End;
Procedure Yellow(Y : integer);
Begin
Picture;
Y := 240;
SetFillStyle(1, 14);
FloodFill(XX, Y, 15);
Delay(850);
ClearViewPort;
End;
Procedure Green(Y : integer);
Begin
Picture;
Y := 405;
SetFillStyle(1, 2);
FloodFill(XX, Y, 15);
Delay(1500);
ClearViewPort;
End;
Procedure Red Yellow(Y : integer);
Begin
Picture;
Y := 240;
SetFillStyle(1, 14);
FloodFill(XX, Y, 15);
Delay(1500);
ClearViewPort;
End;
Procedure Red(Y : integer);
Begin
Picture;
Y := 74;
SetFillStyle(1, 4);
FloodFill(XX, Y, 15);
Delay(2000);
ClearViewPort;
End;
Procedure Vibor;
Begin
case x^.Data of
'R' : Red(Y);
'2' : Red Yellow(Y);
'G' : Green(Y);
220
'Y' : Yellow(Y);
End;
Begin
GraphDriver := Detect;
InitGraph(GraphDriver, GraphMode, '..\BGI');
new(x);
u := x;
x^.Data := 'R';
new(x^.Next);
x := x^.Next;
x^.Data := '2';
new(x^.Next);
x := x^.Next;
x^.Data := 'G';
new(x^.Next);
x := x^.Next;
x^.Data := 'Y';
x^.Next := u;
x := u;
while not KeyPressed do
begin
Vibor;
x := x^.Next;
end;
End.
Задание. Придумайте интересную задачу из жизни и решите ее с помощью динамической структуры кольцо.
221
СПИСОК
Занятие 1. Список. Создание списка путем добавления элементов в конец списка. Просмотр
списка.
Определение. Списком называется структура данных, каждый элемент которой посредством указателя связывается со
следующим элементом.
Из определения следует, что каждый элемент списка содержит поле данных (Data) (оно может иметь сложную
структуру) и поле ссылки на следующий элемент (Next). Поле ссылки последнего элемента должно содержать пустой
указатель (Nil).
Схематически это выглядит так:
Head
Data
Next
Data
Next
Data
Next
Data
Next
Nil
Попробуем вместе сформировать небольшой список путем добавления элементов в конец списка.
Задача. Сформировать список, содержащий целые числа 3, 5, 1, 9.
Для этого сначала определим запись типа S с двумя полями. В одном поле будут содержаться некоторые данные (в
нашем случае числа 3, 5 , 1 и 9), а в другом поле будет находится адрес следующего за ним элемента.
Примечание. Нужно понимать, что поле данных вообще говоря может содержать в себе сколько угодно полей; это
зависит от конкретно поставленной задачи.
Type
Ukazatel = ^S;
S = Record
Data : integer;
Next : Ukazatel ;
End;
Таким образом, мы описали ссылочный тип, с помощью которого можно создать наш связанный однонаправленный
список.
Заметим, что все элементы списка взаимосвязаны, т. е. где находится следующий элемент, "знает" только
предыдущий. Поэтому самое главное в программе, это не потерять, где находится начало списка. Поэтому на начало списка
будем ставить указатель с именем Head и следить за тем, чтобы на протяжении выполнения программы значение этого
указателя не менялось.
А теперь опишем переменные для решения нашей задачи:
Var
Head,
{указатель на начало списка}
x {вспомогательный указатель для создания очередного элемента списка}
: Ukazatel ;
Создадим первый элемент:
New(x);
x^.Data := 3;
x^.Next := Nil;
Head := x;
{выделим место в памяти для переменной типа S}
{заполним поле Data первого элемента}
{заполним поле Next первого элемента: указатель в Nil}
{поставим на наш первый элемент указатель головы списка}
222
x
Head
x^.Data
3
x^.Next
Nil
Таким образом, к выделенной области памяти можно обратиться через два указателя.
Продолжим формирование списка, для этого нужно добавить элемент в конец списка. Поэтому вспомогательная
переменная указательного типа х будет хранить адрес последнего элемента списка. Сейчас последний элемент списка
совпадает с его началом.
Поэтому можно записать равенства:
Head^.Next = x^.Next;
Head^.Data = x^.Data;
Head = x;
Выделим область памяти для следующего элемента списка.
New(x^.Next);
x
Head
x^.Data
x^.Next
3
Nil
Присвоим переменной х значение адреса выделенной области памяти, иначе, переставим указатель на вновь
выделенную область памяти:
x := x^.Next;
x
Head
x^.Data
x^.Next
3
Определим значение этого элемента списка, иначе, заполним поля:
x^.Data := 5;
x^.Next := Nil;
x
Head
x^.Data
3
5
x^.Next
Nil
Итак, теперь у нас список содержит два элемента. Понятно, чтобы создать третий и четвертый элементы, нужно
проделать те же самые операции.
Задание. Запишите в тетрадь ответы на вопросы:
1. Какие операции требуется выполнить для вставки в список его элемента?
2. Можно ли для построения списка обойтись одной переменной?
3. Сколько элементов может содержать список?
4. Когда прекращать ввод элементов списка?
223
5. Запишите в тетрадь рассмотренные операторы и дополните их операторами, создающими третий и четвертый
элементы списка (1, 9).
Теперь попробуем подытожить наши рассуждения.Оформим создание списка в виде процедуры, в которой его
элементы вводятся с клавиатуры.
Procedure Init(Var u : Ukazatel);
Var
x : Ukazatel;
Digit : integer;
{Значение информационной части элемента списка}
Begin
Writeln('Введите список ');
Head := Nil;
{Список пуст}
Writeln ('Введите элементы списка. Конец ввода 0');
Read (Digit);
if Digit <> 0
then {Формируем и вставляем первый элемент списка}
Begin
New(x);
x^.Next := Nil;
x^.Data := Digit;
Head := x
Read (Digit);
while Digit<>0 do
Begin
New(x^.Next); {Формируем и вставляем элемент в конец списка}
x := x^.Next;
x^.Next := Nil;
x^.Data := Digit;
Read(Digit);
End;
Writeln;
End;
Рассмотрите формирование списка несколько другим способом.
Procedure Init(Var u : Ukazatel);
Var
x, y : Ukazatel;
Digit : integer;
Begin
Writeln('Введите список ');
Head := Nil;
Writeln ('Введите элементы списка. Конец ввода 0');
Read (Digit);
while Digit<>0 do
Begin
New(y);
y^.Next := Nil;
y^.Data := Digit;
if u=Nil
then
u := y
else
x^.Next := y;
x := y;
Read(Digit);
End;
Writeln;
End;
Задание. Перепишите эту процедуру в тетрадь, дополните ее комментарием, составьте чертеж и приготовьте учителю
подробное объяснение работы данной процедуры.
224
Просмотр списка
Просмотр элементов списка осуществляется последовательно, начиная с его начала. Указатель р последовательно
ссылается на первый, второй, и т.д. элементы списка до тех пор, пока весь список не будет пройден. При этом с каждым
элементом списка выполняется операция вывода на экран. Начальное значение р – адрес первого элемента списка p^. Если р
указывает на конец списка, то его значение равно Nil, то есть
while p<>Nil do
Begin
Write(p^.Data, ' ');
p := p^.Next;
End;
Задание. Составьте программу, содержащую процедуру создания списка путем вставки элементов в конец списка и
процедуру просмотра списка и вывода на экран его элементов. Процедуры должны содержать параметр, в который
передается начало списка. Покажите протестированную программу и листинг учителю для оценки.
Занятие 2. Создание списка путем вставления элементов в начало.
Задание. Путем добавления элемента в начало списка получить список, изображенный на рисунке:
Head
7
3
5
1
9
Nil
Эту задачу Вы решите сами немного позже, а сейчас рассмотрим как добавить в этот список некоторый элемент,
например 2. То есть получить такой список:
Head
2
7
3
5
Выполним следующие действия:
New(x);
{Создание новой динамической переменной}
225
1
Nil
9
Head
7
3
5
1
9
Nil
x
x^.Data := 2;
x^.Next := Head;
Head
x
2
u := x;
{Информационное поле созданного элемента}
{Присоединим элементы списка и к созданному элементу}
7
3
Nil
5
1
9
5
1
9
{Изменим значение указателя начала списка}
Head
x
2
7
3
Nil
Итак, нужный элемент вставлен. Теперь Вы можете сформировать весь данный список полностью.
Задание. Написать программу, создающую произвольный список путем добавления его элементов в начало. Включите
эту процедуру в программу, решающую задачу создания списка путем добавления элементов в конец списка. Добавьте меню.
Протестируйте программу на наличие ошибок, включите в нее комментарий и покажите результат учителю.
Выберите с учителем задачи для самостоятельного решения.
1. Написать программу, содержащую процедуры формирования и просмотра списка и функцию вычисления среднего
арифметического элементов непустого списка.
2. Написать программу, содержащую процедуры формирования и просмотра списка и подпрограмму проверки наличия
в списке заданного числа.
3. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество слов списка, которые начинаются и оканчиваются одной и той же литерой.
4. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество слов списка, которые начинаются той же литерой что и следующее слово.
5. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество различных значений информационной части уже существующего списка.
226
6. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, увеличивающую
каждое значение информационной части элемента списка на предыдущее значение элемента списка. Нового списка заводить
нельзя.
7. Написать программу, содержащую процедуры формирования и просмотра списка со строковой информационной
частью. Включите в нее функцию, которая оставляет в информационной части только первое слово находящегося там
предложения.
8. Написать программу, содержащую процедуры формирования и просмотра списка со строковой информационной
частью. Включите в нее функцию, которая оставляет в информационной части только гласные буквы находящегося там
предложения.
9. Написать программу, содержащую процедуры формирования и просмотра списка со информационной частью
являющейся произвольным массивом. Включите в нее функцию, которая удаляет из информационной части отрицательные
числа.
10. Написать программу, содержащую процедуры формирования и просмотра списка со информационной частью
являющейся записью. Включите в нее функцию, которая читает и записывает в текстовый или типизированный файл
выбранную Вами информацию .
Занятие 3. Упорядочивание списка. Вставление элемента в середину списка.
Сформируем список целых чисел упорядоченный по неубыванию, т.е. каждый следующий элемент списка должен
быть больше или равен предыдущему.
Для решения этой задачи рассмотрим основные части алгоритма, который мы будем воплощать в программе.
После ввода очередного числа с клавиатуры определяем его место в списке. Заметим, что при этом элемент может
быть вставлен либо в начало списка, либо в конец его, либо во внутрь. Первый и второй случаи мы уже рассмотрели выше.
Остановимся на третьем случае.
Для того чтобы вставить в список элемент со значением Digit между двумя элементами, нужно найти эти элементы и
запомнить их адреса (первый адрес – в переменной dx, второй – в рх), после чего установить новые связи с переменной, в
которой хранится значение Digit.
Графически это можно представить так:
Head
px
dx
Nil
x
Операторы, выполняющие данную задачу будут следующими:
New(x);
x^.Data := Digit;
px^.Next := x;
x^.Next := dx;
Приведем процедуру InsInto, которая ищет место в списке и вставляет элемент, переданный ей как параметр. В
результате сразу получается упорядоченный список. Адрес первого элемента списка хранится в глобальной переменной
Head.
Procedure InsInto(Digit : integer; Var Head : Ukazatel );
Var
dx, px, x : Ukazatel ;
Begin
New(x);
x^.Data := Digit;
227
x^.Next := Nil;
if Head = Nil
then {Если список пуст, то вставляем первый элемент}
Head := x
else
{Если список не пуст, то просматриваем его до тех пор, пока не отыщется подходящее место для x^ или не закончится
список}
Begin
dx := Head;
px := Head;
while (px<>Nil) and (px^.Data<=Digit) do
Begin
dx := px;
px :=px^.Next;
End;
if px=Nil
then
{Пройден весь список}
dx^.Next := x
{Элемент добавляется в конец списка}
else
{Пройден не весь список}
Begin
x^.Next := px;
if px=Head
then
Head := x {Вставляем в начало списка}
else
dx^.Next := x;
{Вставляем внутрь списка}
End;
End;
End;
Задание. Создайте программу, формирующую упорядоченный список, вставив в нее рассмотренную выше процедуру и
процедуру просмотра и вывода на экран элементов списка. Отладьте программу, добавьте комментарий, покажите учителю
результат для оценки.
Занятие 4-5. Примеры задач, решаемых с помощью списка. Решение задач.
Задание. Просмотрите предложенные решения задач и приготовьтесь объяснить алгоритм их решения учителю. Если
необходимо, то наберите программы на компьютере и просмотрите их действие.
Задача 1. Проверить есть ли и сколько раз встречается список М1 в списке М2.
Program BaranovA;
Uses
Crt;
Type
EXS = ^ S;
S = Record
Data : integer;
Next : EXS;
End;
Var
u, x, m1, m2 : EXS;
i, Kol : integer;
Procedure Poisk(Var x1, x2 : EXS);
Var
m3, m4 : EXS;
Begin
Kol := 0;
m3 := m1;
m4 := m2;
while m4 <> Nil do
Begin
if m4^.Data = m3^.Data
228
then
Begin
m3 := m3^.Next;
m4 := m4^.Next;
if m3 = Nil
then
Begin
Kol := Kol+1;
m3 := m1;
End;
End;
else
Begin
m3 := m1;
m4 := m4^.Next;
End;
End;
End;
Procedure Init (Var u : EXS);
Var
y : EXS;
Digit : integer;
Begin
Writeln('Введите список. Конец ввода – 0');
u := Nil;
Read(Digit);
while Digit <> 0 do
Begin
New(y);
y^.Next := Nil;
y^.Data := Digit;
if u = Nil
then
u := y
else
x^.Next := y;
x := y;
Read(Digit);
End;
Writeln;
End;
Procedure Print(X : EXS);
Begin
while X <> Nil do
Begin
Write(X^.Data : 5);
X := X^.Next;
End;
Readln;
Writeln;
End;
Begin
ClrScr;
Init(m1);
Init(m2);
Writeln('***Список 1***');
Print(m1);
Writeln('***Список 2***');
Print(m2);
Poisk(m1, m2);
Writeln('Список 1 встречается в списке 2 ', Kol, ' раз(а)');
Readln;
End.
229
Задача 2. Из текстового файла, состоящего из строк, сформировать список, запросить слово и удалить это слово из
списка.
Program ;
Uses
Crt;
Type
EXS = ^ Spisok;
Spisok = Record
Data : string;
Next : EXS;
End;
Var
Golova_Spiska, Golova_Spiska_Udalen_ : EXS;
F : text;
S, St : string;
Procedure Smotr(x : EXS);
Begin
TextColor(LightRed);
Write('Ваш список...');
while x <> Nil do
Begin
Writeln (x^.Data,' ');
x := x^.Next;
End;
End;
Procedure Reading;
Begin
Reset (F);
Writeln('Ваш файл...');
while no Eof(F) do
Begin
Readln (F, St);
Writeln (St);
End;
close (F);
End;
Procedure CreateFile;
Begin
Writeln('Создание файла');
Write('Введите имя файла...');
Readln(S);
Assign (F, S);
rewrite('Вводите текст в файл (окончание ввода - <Enter>');
Repeat
Readln(St);
Writeln (F, St);
until St = '';
Write('Файл создан');
close (F);
Reading;
End;
Procedure Proverka;
Var
x, y, u : EXS;
i : integer;
Begin
Reset (F);
while not Eof (F) do
Begin
230
Readln (F, St[i]);
while i < Length (St) do
Begin
New (x);
x^.Next := Nil;
if (St[i] <> '') or (St[i] <> St[Length(St)])
then
x^.Data := x^.Data + St[i];
if u = Nil
then
u := x
else
y^.Next := x;
y := x;
End;
End;
close (F);
Smotr (u);
End;
Begin
ClrScr;
TextColor (White);
CreateFile;
Proverka;
End.
Выберите с учителем задачи для самостоятельного решения.
1. Написать программу, содержащую процедуру, которая меняет местами первый и второй элементы непустого списка.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
2. Написать программу, содержащую процедуру, которая меняет местами первый и пятый элементы непустого списка.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
3. Написать программу, содержащую процедуру, которая меняет местами первый и последний элементы непустого
списка. Если элементы не найдены, то выдать на экран соответствующие сообщение.
4. Написать программу, содержащую процедуру, которая вставляет новый элемент перед каждым вхождением заданного
элемента. Если элементы не найдены, то выдать на экран соответствующие сообщение.
5. Написать программу, содержащую процедуру, которая вставляет новый элемент за каждым вхождением заданного
элемента. Если элементы не найдены, то выдать на экран соответствующие сообщение.
6. Написать программу, содержащую подпрограмму, которая проверяет на равенство списки М1 и М2.
7. Написать программу, содержащую функцию, которая определяет, входит ли список М1 в список М2. Предполагается,
что списки существуют.
8. Написать программу, содержащую подпрограмму, которая копирует в конец непустого списка М его первый элемент.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
9. Написать программу, содержащую подпрограмму, которая копирует в начало непустого списка М его последний
элемент. Если элементы не найдены, то выдать на экран соответствующие сообщение.
10. Написать программу, содержащую процедуру, которая копирует в список М за каждым вхождением заданного
элемента все элемента списка М1.
11. Написать программу, содержащую процедуру, которая объединяет два упорядоченных по неубыванию списка М1 и
М2 в один упорядоченный по неубыванию список, построив новый список М.
12. Написать программу, содержащую процедуру, которая объединяет два упорядоченных по неубыванию списка М1 и
М2 в один упорядоченный по неубыванию список, сменив соответствующим образом ссылки в М1 и М2.
13. Написать программу, содержащую функцию, которая проверяет, упорядочены ли элементы списка по алфавиту.
231
14. Напишите программу сортировки существующего списка по алфавиту. В программе используйте подпрограммы.
15. Напишите программу, которая создавала бы файл целых чисел, а затем формировала список целых чисел файла.
Создайте в конце списка элемент, содержащий сумму всех чисел файла. В программе используйте подпрограммы.
16. Напишите программу, которая создавала бы файл целых чисел, а затем формировала список целых чисел файла.
Создайте список чисел, являющихся суммой соседних элементов. В программе используйте подпрограммы.
17. Напишите программу, которая создавала бы текстовый файл, а затем формировала список строк файла. Создайте
список обратных строк. В программе используйте подпрограммы.
18. Напишите программу, которая создавала бы текстовый файл, а затем формировала список строк файла. Создайте
отсортированный список строк. В программе используйте подпрограммы.
19. Напишите программу, которая создавала бы файл комбинированного типа, а затем формировала список, используя
какое-либо поле записи. Создайте отсортированный список. В программе используйте подпрограммы.
20. Напишите программу, которая создавала бы файл комбинированного типа, а затем формировала список элементов
файла. Создайте отсортированный по какому-либо полю список. В программе используйте подпрограммы.
Занятие 6. Удаление элемента из списка.
В результате решения задач предыдущих занятий, Вы научились создавать различными способами список,
анализировать его информационную часть, формировать на базе данного списка другой список и т. д.
Поэтому для решения поставленной перед нами задачи удаления некоторого элемента из списка, нам нужно найти
по какому-либо признаку этот элемент, что, надеюсь не составит для Вас труда.
Уточним поставленную перед нами задачу: удалить из списка элемент с заданной информационной частью.
Обозначим Head – исходный список, Digit – значение информационной части удаляемого элемента.
При исследовании списка на наличие в нем заданного элемента может встретиться три различных случая.
Рассмотрим их.
Удаление элемента из начала списка
Изобразим удаление графически:
x
Head
Nil
x
Head
Nil
Напишем фрагмент программы:
x := Head;
{Запомним адрес первого элемента списка}
Head := Head^.Next; {Теперь Head указывает на второй элемент списка}
Dispose(x); {Освободим память, занятую переменной x^}
Удаление элемента из середины списка
232
Для этого нужно знать адреса удаляемого элемента и элемента, находящегося в списке перед ним.
Изобразим удаление графически:
Head
dx
x
Nil
Head
dx
x
Nil
x := Head; {Переменная х для хранения адреса удаляемого элемента}
{Найдем адреса нужных элементов списка}
while (x<>Nil) and (x^.Data<>Digit) do
Begin
dx := x;
x := x^.Next
End;
dx^.Next := x^.Next;
Dispose(x);
Удаление элемента из конца списка
Удаление элемента из конца списка производится, когда указатель dx показывает на предпоследний элемент списка,
а х – на последний.
Изобразим удаление графически:
Head
dx
x
Nil
Head
dx
x
Nil
{Найдем предпоследний элемент}
x := Head;
dx :=Head;
233
Nil
while x^.Next<>Nil do
Begin
dx := x;
x := x^.Next;
End;
{Удаляем элемент x^ из списка и освобождаем занимаемую им память}
dx^.Next := Nil;
Dispose(x);
Теперь опишем процедуру удаления элементов из списка в общем случае:
Procedure Del(Gigit : integer; Var u : Ukazatel );
Var
x, dx : UKAZATEL ;
Begin
x := Head;
while x<>Nil do
if x^.Data=Digit
then
Begin
if x=y
then
Begin
Head := Head^.Next;
Dispose(x);
x := Head;
End;
else
Begin
dx^.Next := x^.Next;
Dispose(x);
x := dx^.Next;
End;
End;
else
Begin
dx := x;
x := x^.Next;
End;
End;
Задание. Напишите полный текст программы, решающей рассматриваемую задачу. Протестируйте программу,
дополните комментарием покажите учителю для оценки.
Выберите с учителем задачи для самостоятельного решения.
1. Написать программу, содержащую процедуру, которая удаляет из списка М второй элемент, если такой есть.
2. Написать программу, содержащую процедуру, которая удаляет из списка М N-ый элемент, если такой есть. N задает
пользователь.
3. Написать программу, содержащую процедуру удаления из заданного списка все вхождения элемента с заданным
значением информационной части.
4. Написать программу, содержащую процедуру, которая удаляет из списка М за каждым вхождением элемента Е один
элемент, если такой есть и он отличен от Е.
5. Написать программу, содержащую процедуру, которая удаляет из списка М первый отрицательный элемент, если
такой есть.
6. Написать программу, содержащую процедуру, которая удаляет из списка М все отрицательные элементы.
7. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят хотя бы в один из списков М1 и М2.
234
8. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят одновременно в оба списка М1 и М2.
9. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят в список М1, но не входят в список М2.
10. Познакомившись с текстами предыдущих задач, придумайте свою задачу и решите ее.
Занятие 7. Зачет.
Приготовьте для проверки файлы с решенными задачами и листинги.
Проверьте свои знания, ответив на вопросы:
1. Дайте определение динамической структуре список.
2. Сколько элементов может содержать список? Как заканчивается список?
3. Сколько полей может содержать элемент списка? От чего зависит количество полей? Приведите примеры.
4. Какого типа могут быть поля элементов списка? Приведите примеры.
5. Обязательно ли применять процедуру освобождения памяти, занятой элементом, когда мы избавляемся от этого
элемента в списке? Каким образом это влияет на работу программы?
6. Можно ли ссылку одного элемента направить сразу на два или больше других элемента? Как необходимо поменять
тип указателя, чтобы решить эту проблему?
7. Может ли элемент списка быть такого типа, чтобы содержать несколько полей типа указателя? Если – да, то
приведите пример для чего это может быть нужно.
8. Можно ли последовательно "связать" два списка разного типа и почему?
9. Можно ли одновременно работать с несколькими списками сразу?
10. Как Вы считаете, на что нужно обращать особое внимание при работе со списками?
ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
Занятие I. Динамические структуры данных. Статические и динамические переменные.
Адреса. Указатели и их объявление.
В любой вычислительной системе память относится к таким ресурсам, которых всегда не хватает. Управление памятью
– одна из главных забот программиста, так как для него очень важно создавать программы, эффективно использующие
память, ведь во время выполнения программы память необходима для следующих элементов программ и данных:
•
сама программа пользователя;
• системные программы времени выполнения, которые осуществляют вспомогательные действия при работе
программы пользователя;
•
определяемые пользователем структуры данных и константы;
•
точки возврата для программ;
•
временная память для хранения промежуточных результатов при вычислении выражений;
•
временная память при передаче параметров;
• буферы ввода-вывода, используемые как временные области памяти, в которых хранятся данные между моментом
их реальной физической передачи с внешнего устройства или на него и моментом инициализации в программе операции
ввода или вывода;
•
различные системные данные (информация о статусе устройств ввода-вывода и др.).
Из этого перечня видно, что управление памятью касается широкого класса объектов.
235
До сих пор мы использовали простейший способ распределения памяти – статическое распределение, т. е.
распределение памяти при трансляции программы. То есть когда Вы объявляете переменную
Var
A : Array[1..100] of integer;
Вы даете указание компилятору выделить память размера, соответствующего заданному типу, т.е. 2*100=200 байт. Если
в программе на нужный программный объект мы ссылаемся по имени А[3], то машинный код содержит ссылку на номер
ячейки памяти (адрес байта), начиная с которой размещается этот объект.
Адреса задаются двумя 16-тиразрядными словами (тип word) – сегментом и смещением. Каждое из них способно
адресовать 216=65536 байт (64 Кбайт). Для адресации пространства размером в 1 Мбайт требуется 20 разрядов. Сегменты
адресуют память с точностью до параграфа – фрагмента памяти в 16 байт. Смещение адресует память с точностью до байта,
но впределах сегмента. Реальный (абсолютный) адрес складывается из значения сегмента, сдвинутого на 4 разряда влево
(умноженного на 16), и смещения. Фрагмент программы вычисления абсолютного адреса в реальном режиме:
Var
Segment, Offset : word;
Address : LongInt;
. . .
Address := Segment*16+Offset;
Программа на Паскале получает один сегмент данных, поэтому область памяти, в которой могут быть размещены
статические переменные Вашей программы, ограничена 64 Кбайтами. При попытке исполнить программу, требующую
большего размера памяти, будет выдана ошибка:
Error 49: Data Segment too large{Слишком большой сегмент данных}
При динамическом распределении памяти Вы можете запросить блоки размером до одного сегмента (64 Кбайт) каждый,
причем их можно требовать в пределах основной памяти (640 Кбайт) в реальном режиме и без программных ограничений в
защищенном.
Бывают такие данные, размер которых выясняется только при выполнении программ. Кроме того, иногда мы не знаем,
будет существовать некоторый объект или нет.
Например, в программе для обработки текстов (такие программы называются "текстовыми процессорами") требуется
организовать поиск слов, определенных пользователем. Естественно, что определить заранее длину слова, которое будет
задано, невозможно. Часто программный объект, причем значительного размера, бывает нужен на непродолжительное время.
Использование статических программных объектов в таких случаях очень неэффективно, поскольку программа должна быть
рассчитана на максимальные размеры объектов. Область памяти, в которой могут быть размещены статические переменные,
ограничена, и, рассчитывая на максимальный размер переменных, мы ограничиваем их количество. В Паскале, кроме
статических, предусмотрены динамические объекты. Память под них отводится во время исполнения программы, а когда
программный объект можно удалить, память освобождается.
И статические, и динамические переменные вызываются по их адресам. Без адреса не получить доступ к нужной ячейке
памяти, но, используя статические переменные, непосредственно адрес Вы не указываете, а обращаетесь к переменной по
имени. Компилятор размещает переменные в памяти и подставляет нужные адреса в коды команд.
Адресация динамических переменных происходит через указатели. В Паскале можно определить переменные, которые
имеют тип указатель, их значения определяют адрес объекта. Для работы с динамическими переменными в программе
должны быть предусмотрены:

выделение памяти под динамическую переменную;

присвоение указателю на динамическую переменную адреса выделенной памяти (инициализация указателя);

освобождение памяти после использования динамической переменной.
Программист сам должен резервировать место под переменную, определять значения указателей, освобождать память –
удалять динамические переменные. Для использования динамической переменной где-то в статике должен быть указатель на
нее. Компилятор предусматривает место под указатель, об инициализации указателя должен заботиться программист.
Вместо любой статической переменной можно использовать динамическую, но без реальной необходимости этого
делать не стоит. Переменные простых типов нет смысла размещать в динамической области, поскольку они занимают
меньше места, чем указатель на них. Например, указатель на целое занимает 4 байта, само целое – 2 байта. Кроме того, при
динамическом распределении памяти удлиняется текст программы, снижаются наглядность и быстродействие. Это
объясняется тем, что, во-первых, нужно во время исполнения программы определять значения указателей, а во-вторых,
усложняется доступ к значению переменной.
236
Указатели и их объявление
Для работы с динамическими программными объектами в Паскале предусмотрен ссылочный тип или тип указателей. В
переменной ссылочного типа хранится ссылка на программный объект (адрес объекта). Указатель состоит из сегмента и
смещения. По правилам Паскаля указатели на разные типы данных имеют различные типы, причем эти типы несовместимы,
т.е. указатели на разные типы данных не могут ссылаться на один объект.
Чтобы связать ссылочный тип с определенным типом данных, используется символ ^, помещаемый перед именем типа.
Например, имеется тип массив:
Type
A = Array[1..100] of integer;
Тип указателя на такой объект:
Type
tA = ^A;
Переменные ссылочного типа могут определяться как статические, при этом по общим правилам объявления
переменных возможна запись с явным и неявным определением ссылочного типа.
Type
{Тип массив из 100 целых чисел}
A = Array[1..100] of integer;
{Тип указатель на тип А}
tA = ^A;
Var
B : tA;
{Указатель на тип А}
C : ^A;
{Указатель на тип А}
Для получения данных, соответствующих указателю, символ "^" приводится после имени указателя. Действия с
элементами массива типа А могут быть описаны через действия над указателями В и С.
B^[i] := i;
C^[i] := B^[i];
который указывает В}
{i-му элементу массива, на который указывает В, присвоить значение i}
{i-му элементу массива, на который указывает С, присвоить значение i-го элемента массива, на
После выполнения этого кода i-е элементы массивов, на которые указывают В и С, будут равны.
Указатели могут ссылаться на любой тип данных, кроме файлового.
Разберем простой пример, обратив еще раз внимание на синтаксис:
Var
P : ^integer;
{Указатель на целое}
P^ – переменная целого типа, на которую ссылается Р, она может стоять как в левой, так и в правой части
выражений:
P^ :=16;
x := x+P^;
Первый оператор присваивает целочисленной переменной, на которую ссылается Р, значение 16, второй прибавляет к
значению переменной х значение 16, второй прибавляет к значению переменной х значение 16. Аналогично определяются и
используются указатели на переменные любого типа, в том числе и определенного пользователем.
Обратите внимание, что указатель является обычной статической переменной, а переменная, на которую он указывает –
динамической.
Схематически можно представить себе указатель так:
P : ^Integer;
‡‰¾ÂÒ
адре
с
P^ : Integer;
16
Указательная переменная Р может быть в трех состояниях.
1. Содержать адрес какой-либо переменной, память под которую уже выделена.
237
P
P^
‡‰¾ÂÒ
адрес
2. Содержать специальный пустой адрес Nil.
P
Nil
3. Находиться в неопределенном состоянии.
P
?
?
В неопределенном состоянии указатель бывает в начале работы программы до первого присваивания ему или
конкретного адреса, или пустого адреса Nil, а также после освобождения области памяти на которую он указывает.
Схематически различия между состоянием Nil и неопределенным состоянием можно изобразить так:
P2
P1
Nil
P2
P1
Nil
?
? ?
?
P1<> P2
P1=P2
Использование имени указателя в программе означает обращение к адресу ячейки памяти, на которую он указывает.
Чтобы обратиться к содержимому ячейки, на которую указывает указатель, требуется после его идентификатора поставить
символ ^. Эта операция еще называется разыменованием.
Для представления указателя на строку с завершающим нулем в Паскале имеется предопределенный тип PChar. В
модуле System этот тип описывается следующим образом:
Type
PChar = ^char;
Паскаль поддерживает набор расширенных правил, позволяющих работать со строками с завершающим нулем,
используя тип PChar.
Иногда связи между ссылкой и переменной не существует по смыслу задачи, в этом случае с указателем нельзя связать
никакой объект, а ссылка должна быть пустой. Зарезервированное слово Nil обозначает константу со значением указателя,
который ни на что не указывает. После присвоения
P := Nil;
указатель не будет указывать ни на какой объект. Значение Nil совместимо с любым ссылочным типом.
Операции "=" и "<>" могут использоваться для сравнения операндов типа указатель. Два указателя равны только в том
случае, если они ссылаются на один и тот же объект.
Занятие 2. Присвоение значений указателю. Оператор @ с переменной. Оператор @ с
параметром процедуры, переданным по значению. Оператор @ с параметром процедуры,
переданным по ссылке.
Переменной-указателю можно присвоисть значение другого указателя того же типа. В языке существует универсальный
тип указателя, его имя – pointer. Используя тип pointer как промежуточный, можно присвоить значение одного указателя
другому и при несовпадении их типов.
Для инициализации указателей в Паскале предусмотрены специальные процедуры и функции.
Переменной-указателю можно присвоить значение с помощью процедуры new, операции @ или функции Ptr.
238
Процедура new отводит блок памяти в области для динамических переменных и сохраняет адрес этого блока в
указателе.
Операция @ ориентирует переменную-указатель на область памяти, содержащую уже существующую переменную. Ее
можно применять к статическим переменным, динамическим переменным, процедурам и функциям.
Функция Ptr ориетирует переменную-указатель на определенный адрес в памяти. Тип результата – указатель того же
типа, что и Nil, т.е. он может быть назначен любой переменной-указателю.
@ – это унарный оператор. Тип значения указателя управляется через директуву компилятора $T. Если переключателшь
отключен, то результатом является нетипизированный указатель, если включен, – то тип указателя соответствует типу
объекта. Если оператор @ применяется к процедуре, функции или методу, то результатом всегда будет указатель типа
pointer, независимо от состояния опции $T.
Оператор @ с переменной
Использование @ с обычной переменной (не параметром процедуры) несложно.
Например, можно задать декларацию
Type
A = Array [0..99] of char;
{Тип массива символов}
Var
X : Array [0..49] of integer;
{Массив целых чисел}
{Указатель на массив символов}
pA : ^A;
Объявлены переменные двух разных типов: массива целых из 50 элементов и ссылочного на тип А (массив из 100
символов). Чтобы указатель рА указывал на массив Х, надо присвоить ему адрес Х:
рА := @Х;
{Указатель на массив целых чисел}
Теперь pA^ ссылается на массив целых, но по своей природе он указатель на массив символов, поэтому при обращении
pA^[i] мы получаем содержимое отдельных байтов массива Х в символьной форме.
Пример. Компонентам массива целых присваиваются сдвинутые на 65 значения индекса, печатается массив целых.
Переменной-указателю на символьный массив присваивается адрес массива целых. Снова распечатывается массив, но по
адресам значений. Вместо последовательности чисел будет напечатана последовательность ASCII символов от А до z с
пробелами.
Program ReInterpretation;
{Интерпретация массива целых чисел как массива из символов}
Uses
Crt;
Type
A = Array [0..99] of char;
{Тип A – массив 100 символов}
Var
X : Array [0..49] of integer; {Массив целых чисел}
pA : ^A;
{Указатель на массив символов}
i : integer;
Begin
ClrScr;
for i := 0 to 49 do
begin
X[i] := 65+i
{65 – код буквы А}
write(X[i], ' ');
{Печать чисел}
End;
pA := @X;
{Указателю на А присваивается адрес массива целых чисел}
writeln;
for i := 0 to 99 do
239
{Печать символов}
write(pA^[i],' ');
End.
Попытка исполнить последний оператор до оператора pA := @X привела бы к ошибке, поскольку указатель на массив
был бы не опpеделен. Массив Х имеет значения 65..114, которые не выходят за пределы младшего байта двухбайтовых
элементов типа word. В старших байтах этой переменной – нули. При побайтной печати массива младшие байты выводятся
как буквы алфавита, а старшие – как символ #0, который процедурой write интерпретируется как пробел.
Задание. Наберите программу, откомпилируйте ее и проверьте действие.
Оператор @ с параметром процедуры, переданным по значению
Применение @ к формальному параметру процедуры означает то же, что ссылка на фактический параметр,
находящийся в стеке.
Например, пусть Х – формальный параметр процедуры, а рХ – указатель на него. Если в процедуре выполнено
назначение
рХ := @Х;
то рХ^ указывает на значение Х, которое хранится в стеке.
Пример. Процедура Test присваивает локальному параметру р его адрес и выводит значение адреса в формате сегмент :
смещение . Основная программа обращается к процедуре с фактическим параметром Р и выводит адрес фактического
параметра.
Program FormalParam;
{Определение адреса формального параметра}
Uses
Crt;
Var
P : pointer;
Procedure Test(p: pointer);
Begin
p := @P; {Определение адреса локального параметра}
writeln ('', Seg(p^), ':', Ofs(p^));
End;
Begin
ClrScr;
Test(P);
{Вызов процедуры}
writeln('', Seg(p^), ':', Ofs(p^));
End.
На экран будет выведен результат исполнения программы:
В процедуре
Р=1103:16378
В основной программе Р=0:0
Задание. Наберите программу, откомпилируйте ее и проверьте действие.
Оператор @ с параметром процедуры, переданным по ссылке
Применение оператора @ к формальному переменному параметру процедуры приводит к указанию на действительный
параметр процедуры (указатель берется из стека).
Например, пусть
Х – формальный переменный параметр процедуры;
а – переменная, передаваемая в процедуру как действительный параметр;
рХ – ссылочная переменная.
Если процедура, как в предыдущем примере, выполняет присвоение
pХ := @X;
240
то pХ – указатель на а, а pX^ – ссылка на само значение а.
Задание. Чтобы проверить выше сказанное, модифицируйте в предыдущем примере единственную строчку, передав
указатель в процедуру по ссылке:
Procedure Test(Var p:pointer);
Значение указателя в основной программе изменится и будет равно значению указателя в подпрограмме. Результат:
В процедуре
Р=1119:98
В основной программе Р=1119:98
Задание. Используя одну из созданных Вами программ в теме "Процедуры и функции", модифицируйте ее, применив
знания этого занятия.
Занятие 3. Список. Создание списка путем добавления элементов в конец списка. Просмотр
списка
Определение. Списком называется структура данных, каждый элемент которой посредством указателя связывается со
следующим элементом.
Из определения следует, что каждый элемент списка содержит поле данных (Data) (оно может иметь сложную
структуру) и поле ссылки на следующий элемент (Next). Поле ссылки последнего элемента должно содержать пустой
указатель (Nil).
Схематически это выглядит так:
Head
Data
Next
Data
Next
Data
Next
Data
Next
Nil
Попробуем вместе сформировать небольшой список путем добавления элементов в конец списка.
Задача. Сформировать список, содержащий целые числа 3, 5, 1, 9.
Для этого сначала определим запись типа S с двумя полями. В одном поле будут содержаться некоторые данные (в
нашем случае числа 3, 5 , 1 и 9), а в другом поле будет находится адрес следующего за ним элемента.
Примечание. Нужно понимать, что поле данных вообще говоря может содержать в себе сколько угодно полей; это
зависит от конкретно поставленной задачи.
Type
Ukazatel = ^S;
S = record
Data : integer;
Next : Ukazatel ;
end;
Таким образом, мы описали ссылочный тип, с помощью которого можно создать наш связанный однонаправленный
список.
Заметим, что все элементы списка взаимосвязаны, т. е. где находится следующий элемент, "знает" только предыдущий.
Поэтому самое главное в программе, это не потерять, где находится начало списка. Поэтому на начало списка будем ставить
указатель с именем Head и следить за тем, чтобы на протяжении выполнения программы значение этого указателя не
менялось.
А теперь опишем переменные для решения нашей задачи:
Var
Head,
{указатель на начало списка}
x {вспомогательный указатель для создания очередного элемента списка}
: Ukazatel ;
Создадим первый элемент:
new(x);
{выделим место в памяти для переменной типа S}
x^.Data := 3;
{заполним поле Data первого элемента}
x^.Next := Nil;
{заполним поле Next первого элемента: указатель в Nil}
Head := x;
{поставим на наш первый элемент указатель головы списка}
241
x
Head
x^.Data
3
x^.Next
Nil
Таким образом, к выделенной области памяти можно обратиться через два указателя.
Продолжим формирование списка, для этого нужно добавить элемент в конец списка. Поэтому вспомогательная
переменная указательного типа х будет хранить адрес последнего элемента списка. Сейчас последний элемент списка
совпадает с его началом.
Поэтому можно записать равенства:
Head^.Next = x^.Next;
Head^.Data = x^.Data;
Head = x;
Выделим область памяти для следующего элемента списка.
new(x^.Next);
x
Head
x^.Data
x^.Next
3
Nil
Присвоим переменной х значение адреса выделенной области памяти, иначе, переставим указатель на вновь
выделенную область памяти:
x := x^.Next;
x
Head
x^.Data
x^.Next
3
Определим значение этого элемента списка, иначе, заполним поля:
x^.Data := 5;
x^.Next := Nil;
x
Head
x^.Data
3
5
x^.Next
Nil
Итак, теперь у нас список содержит два элемента. Понятно, чтобы создать третий и четвертый элементы, нужно
проделать те же самые операции.
Задание. Запишите в тетрадь ответы на вопросы:
1. Какие операции требуется выполнить для вставки в список его элемента?
2. Можно ли для построения списка обойтись одной переменной?
3. Сколько элементов может содержать список?
4. Когда прекращать ввод элементов списка?
5. Запишите в тетрадь рассмотренные операторы и дополните их операторами, создающими третий и четвертый
элементы списка (1, 9).
Теперь попробуем подытожить наши рассуждения.Оформим создание списка в виде процедуры, в которой его элементы
вводятся с клавиатуры.
Procedure Init(Var u : Ukazatel);
Var
x : Ukazatel;
Digit : integer;
{Значение информационной части элемента списка}
Begin
writeln('Введите список ');
242
Head := Nil;
{Список пуст}
writeln ('Введите элементы списка. Конец ввода 0');
read (Digit);
if Digit <> 0
then {Формируем и вставляем первый элемент списка}
begin
new(x);
x^.Next := Nil;
x^.Data := Digit;
Head := x
read (Digit);
while Digit<>0 do
begin
new(x^.Next); {Формируем и вставляем элемент в конец списка}
x := x^.Next;
x^.Next := Nil;
x^.Data := Digit;
read(Digit);
end;
writeln;
End;
Рассмотрите формирование списка несколько другим способом.
Procedure Init(Var u : Ukazatel);
Var
x, y : Ukazatel;
Digit : integer;
Begin
writeln('Введите список ');
Head := Nil;
writeln ('Введите элементы списка. Конец ввода 0');
read (Digit);
while Digit<>0 do
begin
new(y);
y^.Next := Nil;
y^.Data := Digit;
if u=Nil
then
u := y
else
x^.Next := y;
x := y;
read(Digit);
end;
writeln;
End;
Задание. Перепишите эту процедуру в тетрадь, дополните ее комментарием, составьте чертеж и приготовьте учителю
подробное объяснение работы данной процедуры.
Просмотр списка
Просмотр элементов списка осуществляется последовательно, начиная с его начала. Указатель р последовательно
ссылается на первый, второй, и т.д. элементы списка до тех пор, пока весь список не будет пройден. При этом с каждым
элементом списка выполняется операция вывода на экран. Начальное значение р – адрес первого элемента списка p^. Если р
указывает на конец списка, то его значение равно Nil, то есть
while p<>Nil do
begin
write(p^.Data, ' ');
p := p^.Next;
end;
Задание. Составьте программу, содержащую процедуру создания списка путем вставки элементов в конец списка и
процедуру просмотра списка и вывода на экран его элементов. Процедуры должны содержать параметр, в который
передается начало списка. Покажите протестированную программу и листинг учителю для оценки.
243
Занятие 4. Создание списка путем вставления элементов в начало.
Задание. Путем добавления элемента в начало списка получить список, изображенный на рисунке:
Head
7
3
5
1
9
Nil
Эту задачу Вы решите сами немного позже, а сейчас рассмотрим как добавить в этот список некоторый элемент,
например 2. То есть получить такой список:
Head
2
7
3
5
1
1
9
Nil
9
Выполним следующие действия:
new(x);
{Создание новой динамической переменной}
Head
7
3
5
Nil
x
x^.Data := 2;
x^.Next := Head;
{Информационное поле созданного элемента}
{Присоединим элементы списка и к созданному элементу}
Head
x
2
7
3
Nil
5
1
9
5
1
9
u := x; {Изменим значение указателя начала списка}
Head
x
2
7
3
Итак, нужный элемент вставлен. Теперь Вы можете сформировать весь данный список полностью.
244
Nil
Задание. Написать программу, создающую произвольный список путем добавления его элементов в начало. Включите
эту процедуру в программу, решающую задачу создания списка путем добавления элементов в конец списка. Добавьте меню.
Протестируйте программу на наличие ошибок, включите в нее комментарий и покажите результат учителю.
Выберите задачу для самостоятельного решения в соответствии с порядковым номером в журнале.
1. Написать программу, содержащую процедуры формирования и просмотра списка и функцию вычисления среднего
арифметического элементов непустого списка.
2. Написать программу, содержащую процедуры формирования и просмотра списка и подпрограмму проверки наличия
в списке заданного числа.
3. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество слов списка, которые начинаются и оканчиваются одной и той же литерой.
4. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество слов списка, которые начинаются той же литерой что и следующее слово.
5. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, подсчитывающую
количество различных значений информационной части уже существующего списка.
6. Написать программу, содержащую процедуры формирования и просмотра списка и функцию, увеличивающую
каждое значение информационной части элемента списка на предыдущее значение элемента списка. Нового списка заводить
нельзя.
7. Написать программу, содержащую процедуры формирования и просмотра списка со строковой информационной
частью. Включите в нее функцию, которая оставляет в информационной части только первое слово находящегося там
предложения.
8. Написать программу, содержащую процедуры формирования и просмотра списка со строковой информационной
частью. Включите в нее функцию, которая оставляет в информационной части только гласные буквы находящегося там
предложения.
9. Написать программу, содержащую процедуры формирования и просмотра списка со информационной частью
являющейся произвольным массивом. Включите в нее функцию, которая удаляет из информационной части отрицательные
числа.
10. Написать программу, содержащую процедуры формирования и просмотра списка со информационной частью
являющейся записью. Включите в нее функцию, которая читает и записывает в текстовый или типизированный файл
выбранную Вами информацию .
Занятие 5. Упорядочивание списка. Вставление элемента в середину списка.
Сформируем список целых чисел упорядоченный по неубыванию, т.е. каждый следующий элемент списка должен быть
больше или равен предыдущему.
Для решения этой задачи рассмотрим основные части алгоритма, который мы будем воплощать в программе.
После ввода очередного числа с клавиатуры определяем его место в списке. Заметим, что при этом элемент может быть
вставлен либо в начало списка, либо в конец его, либо во внутрь. Первый и второй случаи мы уже рассмотрели выше.
Остановимся на третьем случае.
Для того чтобы вставить в список элемент со значением Digit между двумя элементами, нужно найти эти элементы и
запомнить их адреса (первый адрес – в переменной dx, второй – в рх), после чего установить новые связи с переменной, в
которой хранится значение Digit.
Графически это можно представить так:
Head
px
dx
Nil
x
Операторы, выполняющие данную задачу будут следующими:
new(x);
x^.Data := Digit;
px^.Next := x;
x^.Next := dx;
Приведем процедуру InsInto, которая ищет место в списке и вставляет элемент, переданный ей как параметр. В
результате сразу получается упорядоченный список. Адрес первого элемента списка хранится в глобальной переменной
Head.
Procedure InsInto(Digit : integer; Var Head : Ukazatel );
245
Var
dx, px, x : Ukazatel ;
Begin
new(x);
x^.Data := Digit;
x^.Next := Nil;
if Head = Nil
then {Если список пуст, то вставляем первый элемент}
Head := x
else
{Если список не пуст, то просматриваем его до тех пор, пока не отыщется подходящее место для x^ или не закончится
список}
begin
dx := Head;
px := Head;
while (px<>Nil) and (px^.Data<=Digit) do
begin
dx := px;
px :=px^.Next;
end;
if px=Nil
then
{Пройден весь список}
dx^.Next := x
{Элемент добавляется в конец списка}
else
{Пройден не весь список}
begin
x^.Next := px;
if px=Head
then
Head := x {Вставляем в начало списка}
else
dx^.Next := x;
{Вставляем внутрь списка}
end;
end;
End;
Задание. Создайте программу, формирующую упорядоченный список, вставив в нее рассмотренную выше процедуру и
процедуру просмотра и вывода на экран элементов списка. Отладьте программу, добавьте комментарий, покажите учителю
результат для оценки.
Примеры задач, решаемых с помощью списка
Задание. Просмотрите предложенные решения задач и приготовьтесь объяснить алгоритм их решения учителю. Если
необходимо, то наберите программы на компьютере и просмотрите их действие.
Задача 1. Проверить есть ли и сколько раз встречается список М1 в списке М2.
Program BaranovA;
Uses
Crt;
Type
EXS = ^ S;
S = Record
Data : integer;
Next : EXS;
End;
Var
u, x, m1, m2 : EXS;
i, Kol : integer;
Procedure Poisk(Var x1, x2 : EXS);
Var
m3, m4 : EXS;
Begin
Kol := 0;
m3 := m1;
m4 := m2;
while m4 <> Nil do
begin
if m4^.Data = m3^.Data
then
246
begin
m3 := m3^.Next;
m4 := m4^.Next;
if m3 = Nil
then
begin
Kol := Kol+1;
m3 := m1;
end;
end;
else
begin
m3 := m1;
m4 := m4^.Next;
end;
end;
End;
Procedure Init (Var u : EXS);
Var
y : EXS;
Digit : integer;
Begin
writeln('Введите список. Конец ввода – 0');
u := Nil;
read(Digit);
while Digit <> 0 do
begin
new(y);
y^.Next := Nil;
y^.Data := Digit;
if u = Nil
then
u := y
else
x^.Next := y;
x := y;
read(Digit);
end;
writeln;
End;
Procedure Print(X : EXS);
Begin
while X <> Nil do
begin
write(X^.Data : 5);
X := X^.Next;
end;
readln;
writeln;
End;
Begin
ClrScr;
Init(m1);
Init(m2);
writeln('***Список 1***');
Print(m1);
writeln('***Список 2***');
Print(m2);
Poisk(m1, m2);
writeln('Список 1 встречается в списке 2 ', Kol, ' раз(а)');
readln;
End.
Задача 2. Из текстового файла, состоящего из строк, сформировать список, запросить слово и удалить это слово из
списка.
Program ;
Uses
247
Crt;
Type
EXS = ^ Spisok;
Spisok = record
Data : string;
Next : EXS;
end;
Var
Golova_Spiska, Golova_Spiska_Udalen_ : EXS;
F : text;
S, St : string;
Procedure Smotr(x : EXS);
Begin
TextColor(LightRed);
write('Ваш список...');
while x <> Nil do
begin
writeln (x^.Data,' ');
x := x^.Next;
end;
End;
Procedure reading;
Begin
reset (F);
writeln('Ваш файл...');
while no Eof(F) do
begin
readln (F, St);
writeln (St);
end;
close (F);
End;
Procedure CreateFile;
Begin
writeln('Создание файла');
write('Введите имя файла...');
readln(S);
assign (F, S);
rewrite('Вводите текст в файл (окончание ввода - <Enter>');
repeat
readln(St);
writeln (F, St);
until St = '';
write('Файл создан');
close (F);
readln;
End;
Procedure Proverka;
Var
x, y, u : EXS;
i : integer;
Begin
reset (F);
while not Eof (F) do
begin
readln (F, St[i]);
while i < Length (St) do
begin
new (x);
x^.Next := Nil;
if (St[i] <> '') or (St[i] <> St[Length(St)])
then
x^.Data := x^.Data + St[i];
if u = Nil
then
u := x
248
else
y^.Next := x;
y := x;
end;
end;
close (F);
Smotr (u);
End;
Begin
ClrScr;
TextColor (White);
CreateFile;
Proverka;
End.
Выберите задачи для самостоятельного решения.
1. Написать программу, содержащую процедуру, которая меняет местами первый и второй элементы непустого списка.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
2. Написать программу, содержащую процедуру, которая меняет местами первый и пятый элементы непустого списка.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
3. Написать программу, содержащую процедуру, которая меняет местами первый и последний элементы непустого
списка. Если элементы не найдены, то выдать на экран соответствующие сообщение.
4. Написать программу, содержащую процедуру, которая вставляет новый элемент перед каждым вхождением заданного
элемента. Если элементы не найдены, то выдать на экран соответствующие сообщение.
5. Написать программу, содержащую процедуру, которая вставляет новый элемент за каждым вхождением заданного
элемента. Если элементы не найдены, то выдать на экран соответствующие сообщение.
6. Написать программу, содержащую подпрограмму, которая проверяет на равенство списки М1 и М2.
7. Написать программу, содержащую функцию, которая определяет, входит ли список М1 в список М2. Предполагается,
что списки существуют.
8. Написать программу, содержащую подпрограмму, которая копирует в конец непустого списка М его первый элемент.
Если элементы не найдены, то выдать на экран соответствующие сообщение.
9. Написать программу, содержащую подпрограмму, которая копирует в начало непустого списка М его последний
элемент. Если элементы не найдены, то выдать на экран соответствующие сообщение.
10. Написать программу, содержащую процедуру, которая копирует в список М за каждым вхождением заданного
элемента все элемента списка М1.
11. Написать программу, содержащую процедуру, которая объединяет два упорядоченных по неубыванию списка М1 и
М2 в один упорядоченный по неубыванию список, построив новый список М.
12. Написать программу, содержащую процедуру, которая объединяет два упорядоченных по неубыванию списка М1 и
М2 в один упорядоченный по неубыванию список, сменив соответствующим образом ссылки в М1 и М2.
13. Написать программу, содержащую функцию, которая проверяет, упорядочены ли элементы списка по алфавиту.
14. Напишите программу сортировки существующего списка по алфавиту. В программе используйте подпрограммы.
15. Напишите программу, которая создавала бы файл целых чисел, а затем формировала список целых чисел файла.
Создайте в конце списка элемент, содержащий сумму всех чисел файла. В программе используйте подпрограммы.
16. Напишите программу, которая создавала бы файл целых чисел, а затем формировала список целых чисел файла.
Создайте список чисел, являющихся суммой соседних элементов. В программе используйте подпрограммы.
17. Напишите программу, которая создавала бы текстовый файл, а затем формировала список строк файла. Создайте
список обратных строк. В программе используйте подпрограммы.
18. Напишите программу, которая создавала бы текстовый файл, а затем формировала список строк файла. Создайте
отсортированный список строк. В программе используйте подпрограммы.
19. Напишите программу, которая создавала бы файл комбинированного типа, а затем формировала список, используя
какое-либо поле записи. Создайте отсортированный список. В программе используйте подпрограммы.
20. Напишите программу, которая создавала бы файл комбинированного типа, а затем формировала список элементов
файла. Создайте отсортированный по какому-либо полю список. В программе используйте подпрограммы.
Занятие 6. Удаление элемента из списка.
В результате решения задач предыдущих занятий, Вы научились создавать различными способами список,
анализировать его информационную часть, формировать на базе данного списка другой список и т. д.
Поэтому для решения поставленной перед нами задачи удаления некоторого элемента из списка, нам нужно найти по
какому-либо признаку этот элемент, что, надеюсь не составит для Вас труда.
Уточним поставленную перед нами задачу: удалить из списка элемент с заданной информационной частью.
Обозначим Head – исходный список, Digit – значение информационной части удаляемого элемента.
При исследовании списка на наличие в нем заданного элемента может встретиться три различных случая. Рассмотрим
их.
249
Удаление элемента из начала списка
Изобразим удаление графически:
x
Head
Nil
x
Head
Nil
Напишем фрагмент программы:
x := Head;
{Запомним адрес первого элемента списка}
Head := Head^.Next; {Теперь Head указывает на второй элемент списка}
Dispose(x); {Освободим память, занятую переменной x^}
Удаление элемента из середины списка
Для этого нужно знать адреса удаляемого элемента и элемента, находящегося в списке перед ним.
Изобразим удаление графически:
Head
dx
x
Nil
Head
dx
x
Nil
x := Head; {Переменная х для хранения адреса удаляемого элемента}
{Найдем адреса нужных элементов списка}
while (x<>Nil) and (x^.Data<>Digit) do
Begin
dx := x;
x := x^.Next
End;
dx^.Next := x^.Next;
Dispose(x);
Удаление элемента из конца списка
Удаление элемента из конца списка производится, когда указатель dx показывает на предпоследний элемент списка, а х
– на последний.
Изобразим удаление графически:
250
Head
dx
x
Nil
Head
dx
x
Nil
Nil
{Найдем предпоследний элемент}
x := Head;
dx :=Head;
while x^.Next<>Nil do
Begin
dx := x;
x := x^.Next;
End;
{Удаляем элемент x^ из списка и освобождаем занимаемую им память}
dx^.Next := Nil;
Dispose(x);
Теперь опишем процедуру удаления элементов из списка в общем случае:
Procedure Del(Gigit : integer; Var u : Ukazatel );
Var
x, dx : UKAZATEL ;
Begin
x := Head;
while x<>Nil do
if x^.Data=Digit
then
Begin
if x=y
then
Begin
Head := Head^.Next;
Dispose(x);
x := Head;
End;
else
Begin
dx^.Next := x^.Next;
Dispose(x);
x := dx^.Next;
End;
End;
else
Begin
dx := x;
x := x^.Next;
End;
End;
Задание. Напишите полный текст программы, решающей рассматриваемую задачу. Протестируйте программу,
дополните комментарием покажите учителю для оценки.
Выберите с учителем задачи для самостоятельного решения.
1. Написать программу, содержащую процедуру, которая удаляет из списка М второй элемент, если такой есть.
251
2. Написать программу, содержащую процедуру, которая удаляет из списка М N-ый элемент, если такой есть. N задает
пользователь.
3. Написать программу, содержащую процедуру удаления из заданного списка все вхождения элемента с заданным
значением информационной части.
4. Написать программу, содержащую процедуру, которая удаляет из списка М за каждым вхождением элемента Е один
элемент, если такой есть и он отличен от Е.
5. Написать программу, содержащую процедуру, которая удаляет из списка М первый отрицательный элемент, если
такой есть.
6. Написать программу, содержащую процедуру, которая удаляет из списка М все отрицательные элементы.
7. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят хотя бы в один из списков М1 и М2.
8. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят одновременно в оба списка М1 и М2.
9. Написать программу, содержащую процедуру, которая формирует список М, включив в него по одному разу
элементы, которые входят в список М1, но не входят в список М2.
10. Познакомившись с текстами предыдущих задач, придумайте свою задачу и решите ее.
Приготовьте для проверки файлы с решенными задачами и листинги.
Проверьте свои знания, ответив на вопросы:
1. Дайте определение динамической структуре список.
2. Сколько элементов может содержать список? Как заканчивается список?
3. Сколько полей может содержать элемент списка? От чего зависит количество полей? Приведите примеры.
4. Какого типа могут быть поля элементов списка? Приведите примеры.
5. Обязательно ли применять процедуру освобождения памяти, занятой элементом, когда мы избавляемся от этого
элемента в списке? Каким образом это влияет на работу программы?
6. Можно ли ссылку одного элемента направить сразу на два или больше других элемента? Как необходимо поменять
тип указателя, чтобы решить эту проблему?
7. Может ли элемент списка быть такого типа, чтобы содержать несколько полей типа указателя? Если – да, то
приведите пример для чего это может быть нужно.
8. Можно ли последовательно "связать" два списка разного типа и почему?
9. Можно ли одновременно работать с несколькими списками сразу?
10. Как Вы считаете, на что нужно обращать особое внимание при работе со списками?
252
Download