МИНИСТЕРСТВО ОБРАЗОВАНИЯ РФ методическое пособие для учащихся 9-11 классов средних общеобразовательных школ ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ PASCAL Краткие теоретические сведения Примеры программ Задачи для самостоятельного решения Вопросы для защиты лабораторных работ СОДЕРЖАНИЕ ВВЕДЕНИЕ....................................................................................................................................................................................................3 НЕМНОГО О РАБОТЕ В СИСТЕМЕ ТУРБО ПАСКАЛЬ..............................................................................................................4 ПЕРЕМЕННАЯ. ЧИСЛА. ИНСТРУКЦИЯ ПРИСВАИВАНИЯ ...................................................................................................5 СТРУКТУРА ПРОГРАММЫ В ПАСКАЛЕ. ВВОД И ВЫВОД ДАННЫХ. ЛИНЕЙНЫЕ ПРОГРАММЫ...................8 УСЛОВНЫЙ ОПЕРАТОР В ПРОГРАММАХ НА ПАСКАЛЕ .................................................................................................. 12 ОРГАНИЗАЦИЯ ЦИКЛОВ ................................................................................................................................................................... 17 МАССИВЫ ................................................................................................................................................................................................. 25 ОБРАБОТКА ТАБЛИЦ. (ДВУМЕРНЫХ МАССИВОВ) ............................................................................................................. 31 ОПЕРАТОР ВАРИАНТА. (ВЫБОРА)................................................................................................................................................ 36 ПОДПРОГРАММЫ ................................................................................................................................................................................. 39 РЕКУРСИЯ ................................................................................................................................................................................................. 46 ОБРАБОТКА СТРОК В ПАСКАЛЕ.................................................................................................................................................... 51 КОМПЬЮТЕРНАЯ ГРАФИКА ........................................................................................................................................................... 57 ЗАПИСИ. ОБРАБОТКА ЗАПИСЕЙ ................................................................................................................................................... 65 ФАЙЛЫ. РАБОТА С ФАЙЛАМИ В ПАСКАЛЕ............................................................................................................................ 70 ЛИТЕРАТУРА ........................................................................................................................................................................................... 75 2 ВВЕДЕНИЕ Чтобы научиться программированию, надо писать программы, решать конкретные задачи. Изучать приведенные решения. Вводите их в свой компьютер. Не бойтесь экспериментировать – вносите изменения в программы. Чем больше работы вы проделаете самостоятельно, тем больше научитесь. Писать программы сначала лучше на бумаге, а уже затем вносить в компьютер. Задача считается решенной, если программа работает так, как сказано в условии задачи. Задачи сгруппированы по темам и относятся практически ко всем разделам программирования: от объявления переменных и программ с линейной структурой до работы с графикой и файлами. Приведены решения наиболее часто встречающихся, а также интересных и трудных задач. Приведенные примеры можно рассматривать как образцы оформления решения задач. Правильно оформленную программу легче отлаживать, кроме того, она производит хорошее впечатление. Для правильного оформления предполагается использовать: осмысленные имена переменных, констант, функций и процедур; отступы при записи инструкций; комментарии. Цель методических указаний – помочь овладеть приемами программирования. Контрольные вопросы позволяют оценить уровень теоретических и практических умений. 3 НЕМНОГО О РАБОТЕ В СИСТЕМЕ ТУРБО ПАСКАЛЬ Система Турбо Паскаль разработана фирмой Borland для компьютеров IBM PC. Она включает в себя транслятор, редактор, различные сервисные функции для работы с файлами, библиотеки, позволяющие использовать в программе средства ввода-вывода операционной системы MS-DOS, построения изображений. Создание программы. Каталог с библиотеками Турбо Паскаль, как правило, называется ТР, после этих букв указывается версия системы, например 5. В этом каталоге надо найти файл с именем turbo.еxе, подвести к нему курсор и нажать <Enter>. При запуске системы появляется окно редактора текстов программ (этот редактор можно использовать и как просто редактор текстов). Для входа в меню служит клавиша <F10>. Строка меню расположена вверху экрана, передвижение по ней производится клавишами управления курсором. Если экран пуст, то можно сразу набирать текст программы, делая такие же отступы, какие имеются в тексте книги. Эти отступы облегчают чтение текста и поиск ошибок. Если на экране после запуска системы находится ненужная программа, то следует войти в пункт меню File и выполнить команду New. Экран очищается, вверху появляется имя программного файла noname.pas (безымянная программа). Набор каждой строки программы завершается нажатием клавиши <Enter>. По уже имеющемуся тексту можно перемещаться с помощью клавиш управления курсором. В начало строки можно перейти с помощью клавиши <Ноme>, в конец строки — клавишей <End>. Убрать ненужную строку можно нажатием комбинации клавиш <Ctrl> + <Y>, вставить — нажатием <Enter> (курсор при этом должен находиться в конце строки, после которой производится вставка). Если произошел случайный разрыв строки (нажатием клавиши <Enter> в середине строки), то надо подвести курсор к концу верхней строки и нажать <Delete>. Нижняя строка при этом расположится на верхней строке. Нажимая <Delete> еще несколько раз, можно ликвидировать разрыв полностью. Запуск программы. Для выполнения программы надо выйти в меню и в пункте Run выполнить команду Run. Система сначала запускает транслятор, который переводит программу с Паскаля на язык машинных кодов и ищет синтаксические ошибки в программе. Если они найдены, то программа не будет выполняться, произойдет возврат в редактор. Поверх текста программы появляется красное окно с сообщением типа ошибки. После нажатия клавиши <Esc> окно исчезает, курсор устанавливается в строку с ошибкой. Для получения подробной информации об ошибке надо нажать <Ctrl> + <F1>. Когда все ошибки исправлены, программа начинает выполняться. Если в системе уже имеется программа с именем noname.pas, то выдается окно, где об этом сообщается. Чтобы имя осталось без изменений, нажимается <Enter> и появляется еще одно окно, в котором спрашивается, будет ли программа с таким именем записана поверх уже имеющейся. Если пользователь с этим соглашается, то он нажимает <Y> (yes — да). Чтобы изменить имя программы, новое имя надо ввести в первом появившемся окне, стерев 4 noname.pas и записав новое имя. После этого программа начинает выполняться. Программу можно модифицировать и выполнять сколько угодно, раз. Для помещения в окно редактора программы, находящейся на диске, необходимо выполнить команду Load из пункта меню File (или нажать <F3>). При этом появляется окно, в котором или набирается имя файла, или нажимается <Enter>. В последнем случае появляется список файлов с расширением .pas и производится выбор файла. Лабораторная работа №1 ПЕРЕМЕННАЯ. ЧИСЛА. ИНСТРУКЦИЯ ПРИСВАИВАНИЯ Цель работы: научиться записывать инструкции присваивания; особое внимание уделить понятию переменной, очень важного в программировании. Краткие теоретические сведения В настоящее время в компьютерном мире существует множество языков программирования. Программу, выполняющую одни и те же действия, можно записать на разных языках. Но одним из наиболее популярных сегодня языков программирования является язык Паскаль. Он позволяет составлять программы для решения математических задач, обработки текстов, построения изображений на экране дисплея (позволяет использовать практически все возможности персонального компьютера). Создатель Паскаля — Никлаус Вирт. Как каждый язык, Паскаль имеет свой алфавит. В него входят латинские буквы, цифры от 0 до 9, специальные знаки (+, -, круглые, квадратные и фигурные скобки, точка, запятая и др.), а также служебные слова (из английского языка: (begin, end, for, while и др.). При написании программы для переменных величин вводятся обозначения, точно так же, как это делается для обозначения переменных в курсе алгебры. Такое обозначение в языках программирования называют именем величины. Имя в Паскале — слово из букв, цифр и знаков подчеркивания, начинающееся с буквы. В качестве имени нельзя использовать служебные слова. Каждое имя соответствует некоторой ячейке памяти, куда записывается значение переменной величины. Поскольку в ячейку можно записать одно за другим сколько угодно данных, имя также называют переменной или именем переменной. Ячейка — понятие условное, это последовательность разного количества байтов памяти для разных данных. Для целых чисел в Паскале требуется два байта, для действительных — шесть. Любой символ клавиатуры занимает один байт. Поэтому для каждой переменной надо указать ее тип, чтобы транслятор знал, сколько места в памяти она будет занимать. Числа в Паскале различаются как целые и действительные (вещественные). Целое число по внешнему виду такое же, как обычно: знак «+» можно не указывать. Вещественные числа, несмотря на одинаковое представление в памяти компьютера, могут иметь вид с фиксированной и с плавающей точкой. Числа с фиксированной точкой похожи на десятичные, только целая часть от дробной отделяется не запятой, а точкой: -7.23; 897.5. 5 При выполнении действий с числами с фиксированной точкой может получиться результат, целая часть которого содержит больше разрядов, чем объем ячейки памяти. Происходит, как принято говорить, переполнение ячейки памяти. Чтобы этого избежать, используют представление вещественных чисел с плавающей точкой. В этом случае число представляется в виде мантиссы и порядка. Мантисса — это последовательность цифр, изображающих число, а порядок определяет положение точки в этой последовательности. Например, десятичное число 243,7 может быть Представлено в виде: 243,7 = 2,437 • 102, или 243700 • 10-3 , или 0,002437 • 105 и т. д. В этом примере 2437 — мантисса числа, а цифры 2, - 3 или 5 - порядок (нетрудно увидеть, что это степень числа 10, которая меняется в зависимости от различных видов записи числа 243,7). В машинной записи число 243,7 будет выглядеть как 2.4376000000 Е+02, Числа с плавающей точкой имеют громоздкий вид, они выводятся как результат работы программы. Однако их можно заменить на числа с фиксированной точкой. Если программа выдала вещественное число 4.9876543234Е-02, то это тоже самое, что - 0,049876543234, т. е. десятичную точку надо сдвинуть влево на две позиции. Направление сдвига указано после буквы Е в записи числа: вправо, если после Е плюс, и влево, если минус. Дли работы с числами используются шесть операций: «+» — сложение, «-» — вычитание, «/» — деление, «*» — умножение, mod — нахождение остатка от деления и div — деление нацело. Находить остаток от деления и делить нацело можно только целые числа. Из имен, чисел, знаков арифметических действий и математических функций конструируются арифметические выражения. Для указания порядка действий используются только круглые скобки, их может быть несколько, главное, чтобы количество открывающих скобок равнялось количеству закрывающих. Математические функции Паскаля во многом совпадают с общепринятыми: sin(x), cos(x), ln(x). Для возведения аргумента в квадрат используется обозначение sqr(x), для извлечения квадратного корня sqrt(x), а модуль обозначается abs(x). В качестве аргумента каждой функции может быть арифметическое выражение. Пример арифметического выражения: x 1 x2 x/(1+sqr(x)/(5+x*sqr(x))) 5 x3 математическая запись запись на Паскале Оператор присваивания. Алгоритм преобразования данных на Паскале состоит из операторов — укрупненных команд. Каждый оператор преобразуется специальной программой-транслятором в последовательность машинных команд. Основное преобразование данных, выполняемое компьютером, — присваивание переменной нового значения. Общий вид оператора присваивания: 6 имя переменной: = арифметическое выражение; В дальнейшем будет показано, что справа может стоять и выражение другого типа. Знак «:=» читается «присвоить». Точка с запятой в конце записи оператора является обязательной. При выполнении оператора присваивания рассматривается арифметическое выражение, из ячеек оперативной памяти, соответствующих стоящим там именам, вносятся в процессор значения и выполняются указанные действия над данными. Полученный результат записывается в ячейку памяти, имя которой указано слева от знака присваивания. Примеры оператора присваивания: х:= 3.14; {переменной x присвоить значение 3.14} а:= b + с; {из ячеек b и с считываются заранее помещенные туда данные, вычисляется сумма, результат записывается в ячейку а} i:= i + 1; {значение переменной увеличивается на единицу} Для типов переменной слева и арифметического выражения справа от знака присваивания существуют ограничения: 1) если переменная слева вещественного типа, то арифметическое выражение может быть как целого, так и вещественного типа, т. е. содержать либо целые переменные и допустимые для них операции, либо вещественные, либо и те, и другие (тогда выражение преобразуется к вещественному типу); 2) если переменная слева целого типа, то арифметическое выражение только целочисленное. Это означает, что можно, например, вещественной переменной присвоить целое значение. В памяти компьютера оно будет преобразовано к вещественному типу. В фигурных скобках рядом с оператором помещается комментарий его действий. Методические указания по работе и задания № Условие задачи 1 Объявить переменные для вычисления значений функции y=x2. 2 Объявить переменные и записать в виде инструкции формулу для пересчета сопротивления электрической цепи из омов в килоомы. 3 Объявить переменные и записать в виде инструкции формулу для вычисления объема цилиндра. 4 Объявить переменные и записать в виде инструкции формулу для вычисления объема конуса. 5 Объявить переменные и записать в виде инструкции формулу для пересчета веса из фунтов в килограммы (1 фунт = 409,5г.) 6 Объявить переменные и записать в виде инструкции формулу для 7 вычисления треугольника (привести разные способы) 7 Объявить переменные и записать в виде инструкций формулу, для вычисления объёма полого цилиндра. 8 Объявить переменные и записать в виде инструкции формулу для вычисления площади круга. 9 Объявить переменные и записать в виде инструкции формулу для вычисления площади трапеции. 10 Объявить переменные и записать в виде инструкции формулу для вычисления объема параллелепипеда. 11 Объявить переменные и записать в виде инструкции формулу для вычисления площади прямоугольника. 12 Объявить переменные и записать в виде инструкции формулу для вычисления функции y=-2,7x3+0,23x2-1,4. 13 Объявить переменные и записать в виде инструкции формулу для вычисления площади поверхности шара. 14 Объявить переменные и записать в виде инструкции формулу для пересчета расстояния из миль в метры. 15 Объявить переменные и записать в виде инструкции формулу для вычисления стоимости покупки из нескольких тетрадей, карандашей и линейки ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Что входит в состав алфавита Паскаля? 2. Почему Паскаль различает целые и вещественные числа? 3. Что такое арифметическое выражение, из чего оно может состоять? 4. Как работает оператор присваивания? 5. Какие ограничения накладывает Паскаль на типы данных присваивании? 6. Что понимают под понятием переменной в программировании? 7. Что такое транслятор? 8. Запишите на Паскале tg х, х4. при Лабораторная работа №2 СТРУКТУРА ПРОГРАММЫ В ПАСКАЛЕ. ВВОД И ВЫВОД ДАННЫХ. ЛИНЕЙНЫЕ ПРОГРАММЫ Цель работы: усвоить назначения и использование операторов ввода данных и вывода результата, оформления программы на Паскале, освоение 8 программы с линейной структурой, используемых, как правило, для реализации обычных вычислений по формулам. Краткие теоретические сведения Программа на Паскале состоит из двух частей: описания используемых данных и операторов по их преобразованию. Вторая часть также называется программным блоком. Общий вид программы: program (имя программы); label (список меток); const (список постоянных значений); type (описания сложных типов данных); var (описания данных программы); begin (начало программного блока) (алгоритм) end. (конец программы) Имя программы состоит не более чем из 8 знаков, начинается с буквы и содержит буквы, цифры и знаки подчеркивания. Программа начинается со слова program и заканчивается, словом end с точкой. Операторы, разделы и описания разделов заканчиваются точкой с запятой. Описательная часть программы состоит из четырех разделов. Раздел меток label, раздел констант const и раздел типов type. Их использование будет рассмотрено в дальнейшем, по мере необходимости. Основным является раздел переменных var. В нем указываются имена переменных, используемых в программе, и их тип. Для числовых данных применяются основные описатели типов integer (целый) и real (вещественный). Например, в программе используются две целочисленные переменные и одна вещественная. Раздел переменных может иметь вид: var i,j: integer; x: real; Имена переменных одного типа перечисляются через запятую, затем после двоеточия указывается их тип. Описание каждого типа заканчивается точкой с запятой. Когда при переводе на язык машинных кодов транслятор встречает описание переменной, он отводит для этой переменной ячейку памяти и ставит в соответствие имени переменной номер первого байта ячейки. Программный блок содержит операторы, описывающие алгоритм решения задачи. Для сообщения данных компьютеру служат операторы ввода и вывода. Оператор ввода помещает вводимое значение переменной в отведенную для нее ячейку. Оператор ввода: read (список имен); . Оператор read (читать) останавливает работу программы и ждет; пока пользователь наберет на клавиатуре число и нажмет <Enter>. Введенное число помещается в оперативную память, в отведенную ячейку. Если список ввода содержит несколько имен, то для каждого надо ввести свое значение. Числа вводятся или через пробел, или через запятую, или нажатием клавиши <Enter>. Например: read (i, j); требует ввода двух целых чисел. После работы этого оператора курсор располагается за последним числом, но не переводится на новую строку. Для перевода курсора на новую строку экрана дисплея после ввода данных надо использовать оператор readln (список имен); Для вывода результатов работы программы на экран дисплея служит 9 оператор write (список вывода);. Оператор write (писать) выводит данные на экран дисплея. Список вывода — перечисленные через запятую имена результатов или арифметические выражения, являющиеся результатом работы программы. Также в список вывода, для пояснения, входят заключенные в апострофы тексты. Например: write (x=‘‘, x);. Этот оператор напечатает на экране, начиная с той позиции, где находится курсор, текст, заключенный между апострофами, и значение переменной х из оперативной памяти. Значение будет выведено в форме вещественного числа с плавающей точкой. Чтобы число было выведено в форме с фиксированной точкой, надо после имени соответствующей переменной указать два целых числа, отделив каждое двоеточием. Первое из этих чисел показывает, сколько позиций занимает число (включая десятичную точку и знак числа). Второе равно количеству цифр дробной части числа. Например, для печати числа —23.57 как значения переменной x, оператор печати примет вид: write (‘x= ‘, x:6:2);.На экран будет выдано x=-23.57. Перевод курсора на новую строку осуществляется оператором пустого вывода writeln;. Если надо перевести курсор после печати, то применяется writeln (список вывода); После вывода результатов работы программы на экран в Турбо Паскаль система так быстро возвращается в редактор текстов программы, что пользователь не успевает увидеть эти результате. Чтобы задержать изображение, в конце программы следует ставить оператор пустого ввода readln; Например: Пусть требуется найти сумму, произведение и разность двух данных чисел. Для каждого из чисел надо придумать имя переменной и указать ее тип. Затем ввести эти числа в отведенные ячейки и, используя возможность оператора вывода содержать арифметическое выражение, напечатать результаты. program P1; var a,b: real; begin write (‘введите два числа через пробел, затем нажмите <Enter>‘); readln (a, b); write (‘ a + b = ‘, a + b, ‘a*b = ‘, a*b, ‘a - b = ‘, a- b); readln end. Служебные слова Паскаля, выделенные жирным шрифтом, при наборе текста программы на клавиатуре никак не выделяются, их различает транслятор (синоним — компилятор). Поэтому служебные слова нельзя использовать в качестве имен. Первый оператор программного блока выводит на экран подсказку для пользователя — что он должен сделать. Для ввода данных рекомендуется создавать подобные подсказки. При решении задач имена присваиваются не только исходным данным, но и результатам, а также получаемым промежуточным значениям. Поскольку в рассматриваемом примере надо получить три результата, введем для них переменные x, у, z.. В программе этим переменным будут присвоены значения суммы, произведения и разности двух вводимых чисел. program P2; var a, b, x, y, z: real; 10 begin write (‘введите два числа через пробел, затем нажмите <Enter>‘); readln(а, b); x = а + b; y = а - b; z = а - b; write (‘a + b = ‘, x, ‘ а * b = ‘, у, ‘ а - b = ‘, z); readln end. Методические указания и задания к работе № Условие задачи 1 Написать программу вычисления площади параллелограмма (площади поверхности параллелепипеда, площади поверхности цилиндра). 2 Напишите программу вычисления площади треугольника, если известны координаты его вершин (формула Герона). 3 Напишите программу возведения числа в седьмую степень за четыре операции. 4 Написать программу вычисления объема куба (объема цилиндра, объема параллелепипеда). 5 Напишите программу определения времени встречи двух автомобилей, если известно расстояние между двумя пунктами, откуда они вышли навстречу друг другу одновременно, а также их скорости. 6 Написать программу пересчета расстояния из верст в километры (1верста=1066,8м), веса из фунтов в килограммы (1фунт=409,5 г). 7 Написать программу вычисления сопротивления электрической цепи, состоящей из параллельно (последовательно) соединенных сопротивлений. 8 Напишите программу вычисления площади круга, если известна длина окружности. 9 Напишите программу вычисления площади и гипотенузы прямоугольного треугольника, если известны его катеты. 10 Напишите программу вычисления суммы арифметической прогрессии, если известен ее начальный член и разность, а также количество ее членов. 11 Напишите программу вычисления площади боковой поверхности куба. 12 Напишите программу вычисления расстояния между двумя точками плоскости. 13 Напишите программу вычисления среднего арифметического двух чисел. 14 Напишите программу пересчета величины временного интервала, заданного в минутах, в величину, выраженную в часах и минутах. 11 15 Напишите программу вычисления суммы модулей трех вещественных чисел. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Для чего необходимо описывать данные в программе? 2. Как описать переменные одного типа, например вещественного? 3. Какой оператор используется для ввода данных? Как он работает? 4. Куда попадают введенные с клавиатуры числа при работе оператора ввода? 5. Как перевести курсор на новую строку после ввода данных? 6. Как вывести результаты работы программы на экран дисплея? 7. Как сделать, чтобы данные выводились с новой строки? 8. Как увидеть результаты вывода на экране дисплея, если уже сработал write? 9. Можно ли получить результат вычислений без использования оператора присваивания? Лабораторная работа №3 УСЛОВНЫЙ ОПЕРАТОР В ПРОГРАММАХ НА ПАСКАЛЕ Цель работы: приобрести навыки в решении задач с помощью условного оператора, усвоить назначение и правила его применения. Краткие теоретические сведения Очень часто ход решения задачи в практике зависит от выполнения какого-либо условия. Например: Требуется построить алгоритм вычисления значения функции x при x 0, y=|x|. Она задается соотношением: y - x при x 0 При решении этой задачи требуется выполнить следующие: 1) проверить больше или равен нулю x; 2) если x больше или равен 0, то присвоить y значение x (y:= x), если x меньше 0, то присвоить у значение -x (у:=-x). Коротко алгоритм решения этой задачи может быть записан так: если x 0, то у: = x, иначе у: = -x Эти команды называются командами ветвления (условным оператором) Условный оператор может иметь две формы (структуры), представленные на рисунках 1 и 2. На рисунке 1 показана неполная форма 12 условного оператора: действие выполняется только тогда, когда выполняется записанное в ромбе условие. В случае невыполнения условия происходит переход к следующему оператору (выход из структуры). На рисунке 2 изображена полная форма условного оператора: в случае выполнения условия (выход «+» из ромба) выполняется одно действие, в случае невыполнения (выход «—») — другое действие. Каждая структура имеет один вход и один выход. Программу рекомендуется строить из последовательных, логически завершенных блоков, не допуская передачи управления из одного блока в другой. Такая программа содержит меньше ошибок при разработке, легче проверяется на правильность выполнения. Неполный условный оператор имеет вид: IF условие THEN оператор; Полный условный оператор: IF условие THEN оператор_1 ELSE оператор_2; Рис 1. Неполная форма условного оператора Рис 2. Полная форма условного оператора Если перевести на русский язык английские слова IF, THEN и ELSE, то вид условного оператора - ЕСЛИ условие, ТО оператор 1, ИНАЧЕ оператор 2; В различных случаях после слов THEN и ELSE надо выполнить не один оператор, а несколько. Тогда эти операторы заключаются в так называемые операторные скобки, открывающая скобка которых — слово BEGIN, а закрывающая — слово END: begin (операторы) end; Перед словом ELSE точка с запятой не ставится. В операторных скобках рекомендуется каждую пару BEGIN — END записывать в одном столбце: так легче проверить соответствие каждой открывающей скобке закрывающую. Примеры условного оператора: if a < b then у: = х; if х < 0 then х: = -х; {изменение знака переменной х} if a + b < с then begin z: = х; {обмен значениями переменными х и у} х: = у; у: = z end; В качестве выполняемого в условном операторе действия может быть другой условный оператор. Например: 13 if sqr (х) + sqr (у) > 1 then if х > у then z: = 0 else z: = 1; При такой форме записи, использующей сдвиг вправо для каждого внутреннего действия, легко понять, к какому из двух слов IF относится слово ELSE. Если этот оператор записать в одну строку, то ответ будет неоднозначным. Транслятор поступает следующим образом. Встретив сложную конструкцию из вложенных условных операторов, он анализирует ее с конца, приписывая последнее найденное ELSE первому встреченному при просмотре справа налево IF. Пример программы: Пусть для двух целых чисел надо определить, являются они четными или нет. Для проверки четности используем условие: остаток от деления на 2 четного числа равен 0. program P3; var a, b: integer; begin writeln (‘введите два целых числа’): readln(a, b); if a mod 2=0 then writeln (‘a — четное’) else writeln (‘a — нечетное’); if b mod 2=0 then writeln (‘b — четное’) else writeln (‘b — нечетное’) end. Логические выражения. Алгоритм решения квадратного уравнения содержит проверку условия d < 0. Два значения, d и 0, связаны отношением < — меньше. Если условие выполняется, то говорят, что соответствующее выражение истинно, если не выполняется — выражение ложно. Речь идет о логическом выражении. Для построения сложных условий в Паскале имеются логические операции and (и), or (или) и not (не). Обозначив истинное значение через 1 и ложное через 0, построим таблицы истинности для этих операций. X Y X and Y X Y X or Y X not X 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 1 0 1 0 0 1 1 0 0 0 0 0 0 Рассмотрим примеры построения сложных логических выражений. 1. Пусть требуется определить, принадлежит ли точка с координатой х отрезку [а; b]. Если записать это условие двойным неравенством, то читать его надо так: х меньше либо равен b и больше либо равен a (а х b). Отношение «меньше либо равно» в Паскале записывается двумя знаками. Аналогично записывается и «больше либо равно». Однако в 14 Паскале нельзя записывать двойное неравенство. Используя логическую операцию and (и), запишем: (х a) and (х b) Рис. 3 Отношения, между которыми стоит логическая операция, заключаются в круглые скобки. 2. Имеется прямоугольное отверстие со сторонами a и b и кирпич с ребрами х, у, z. Требуется составить условие прохождения кирпича в отверстие (рис. 3). Кирпич пройдет в прямоугольное отверстие, если выполнится сложное условие: (а х) and (b y) or (а у) and (b x) or (а х) and (b z) or (a z) and (b x) or (a y) and (b z) or (a z) and (b y) Для трех граней шесть условий получается потому, что можно каждую грань повернуть на 90° и проверить для каждой грани два случая. 3. Определить принадлежность точки фигуре. Пусть фигура задана ограничивающими ее прямыми (рис.4). Для каждой прямой определим полуплоскость, в которой находится фигура – треугольник АВС. Полуплоскость задается неравенством. Полуплоскость, находящаяся выше оси х определяется неравенством у > 0. Полуплоскость, находящаяся справа от прямой, соединяющей точки (—1,0) и (0,2), задается неравенством у — 2х — 2 < 0. Полуплоскость, находящаяся слева от прямой, соединяющей точки (1,0) и (0,2), задается неравенством у + 1х — 2 < 0. Условие принадлежности точки (х, у) фигуре: (Y > 0) and (Y - 2*X - 2 < 0) and (Y + 2*X - 2 < 0) 4. Приведем пример программы определения существования треугольника со сторонами a, b и с. Условие существования треугольника известно из Рис. 4 геометрии: сумма двух любых сторон должна быть больше третьей. Следовательно, для всех сторон условие «сумма двух больше третьей» должно выполняться. program Р4; var a, b, с: real; begin writeln (‘введите длины трех сторон треугольника ‘); 15 readln(a. b, с); write (‘треугольник со сторонами ‘, а, b, с); if (a + b > с) and (b + с > a) and (a + с > b) then write (‘существует’) else write (‘не существует’); readln end. Методические указания по работе и задания № Условие задачи 1 Проверьте, есть ли среди трех заданных чисел равные (вывести ответ «Да» или «Нет») 2 В компьютер вводятся длины трех отрезков. Компьютер должен ответить на вопрос, существует или нет треугольник с такими сторонами. 3 Даны три действительных числа. Выберите те из них, которые принадлежат отрезку [1;3]. 4 Написать программу решения квадратного уравнения. Программа должна проверять правильность исходных данных. 5 Вводятся значения двух переменных x и y, если значения обоих переменных положительные, то они заменяются значениями квадратного корня из них, иначе оба числа остаются прежними. 6 Вычислите площадь кольца. Программа должна проверять правильность исходных данных. 7 Даны действительные числа а, b и с. Удвойте эти числа, если они являются упорядоченными по возрастанию. 8 Найдите решение уравнения ах + b = 0, если оно существует 16 9 Если данное число х меньше нуля, то z присвойте значение большего из двух чисел х и у, иначе z присвойте значение полусуммы этих чисел. 10 Выясните, попадает ли точка М(x, y) в круг радиусом r с центром в точке (x0,y0). 11 Определить в каком квадранте находится точка с координатами x и y, и отпечатать номер квадранта. 12 Даны три действительных числа. Найдите наибольшее значение из их суммы и произведения. 13 Даны три числа а, b и с. Выясните, верно ли а < b < с. Ответ получите в текстовой форме: верно или неверно. 14 Написать программу, которая вычисляет оптимальный вес пользователя, сравнивает его с реальным и выдает необходимые рекомендации поправиться или похудеть (оптимальный вес вычисляется по формуле: рост (в сантиметрах)100). 15 Написать программу определения стоимости разговора по телефону с учетом скидки 20%, предоставляемой по субботам и воскресеньям (исходные данные длительность разговора - целое число минут, номер дня недели). ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Как транслятор анализирует вложенные условные операторы? 2. Какие формы условного оператора вы знаете? Чем они отличаются? 3. Как работает неполный условный оператор? 4. Зачем при отладке программы нужно тестировать все ветви алгоритма? 5. Как проверить, является ли целое число нечетным? 6. Как выполняются логические операции и, или, не? Лабораторная работа №4 ОРГАНИЗАЦИЯ ЦИКЛОВ Цель работы: приобрести навыки в составлении циклических программ, изучить назначение и правила использования операторов цикла. Краткие теоретические сведения 17 В своей практической деятельности человек постоянно сталкивается с задачами, при решении которых требуется многократно повторять одни и те же действия, для решения таких задач используется команды повторения (цикла). Например. Пусть требуется определить остаток от деления числа М на число N (М и N — произвольные натуральные числа). Самый простой способ решения этой задачи заключается в следующем: проверяем, не меньше ли М, чем N (если М < N, то М и есть остаток от деления М на N); если М N, то уменьшаем значение М на значение N (т.е. вычитаем из М число N и дальнейшие действия осуществляем с результатом этой операции, который для удобства мы снова обозначим М); снова проверяем, не стало ли М меньше N, если не стало, то еще раз уменьшаем значение М на величину значения N и т. д. Эти две операции (сравнения и вычитания) повторяются до тех пор, пока очередное значение М не станет меньше значения N. Значение М в этот момент и будет остатком от деления заданных вначале чисел. Как видно, в этом примере несколько раз повторяется одна и та же последовательность действий. Компьютер может заданное число раз выполнить одни и те же действия с разными данными. Повторяющиеся действия в программировании называются циклом. Если изобразить цикл в виде блок-схемы, то получатся две разные структуры (рис. 5). Цикл не может выполняться вечно, в этом случае нарушается свойство алгоритма решить задачу за конечное число шагов. Цикл заканчивается по какому-либо условию. Проверка этого условия может производиться в начале каждого повторяющегося шага, в этом случае цикл называется пока. При проверке условия в конце каждого шага цикл называется до. Разновидностью цикла до является цикл пересчет. Рис. 5. Циклические структуры В цикле пока сначала проверяется условие, и если оно выполняется, т. е. логическое выражение истинно, то выполняется оператор и снова проверяется условие. Записанное в цикле пока условие является условием продолжения цикла. Как только оно перестанет выполняться, цикл завершится. На рисунке 5 выход из ромба «+» (или да) означает выполнение условия цикла, «—» (или нет) — невыполнение. Цикл пока не выполнится ни разу, если условие при входе в структуру оказалось ложным. Как правило, цикл пока содержит условие повторения, а цикл до — условие окончания работы цикла. Обе структуры имеют один вход и один выход. Однако цикл до всегда выполняется хотя бы один раз, потому что условие проверяется после выполнения действия. Это затрудняет проверку правильности программы, поэтому лучше использовать цикл пока. Оператор в цикле может быть простым или составным, заключенным в операторные скобки. В этом 18 случае в цикле могут повторяться несколько операторов, а не один. Повторяющиеся в цикле операторы называются телом цикла. Циклы можно организовывать, используя различные средства Паскаля. Оператор безусловного перехода. Этот оператор позволяет перейти без проверки условия либо на один из предыдущих операторов, либо на один из последующих, т. е. изменить порядок выполнения команд. Общий вид оператора: goto n; где п — целое число, не более чем из четырех цифр, называемое меткой. Метка появляется в программе три раза: 1) в описательной части в разделе Label; 2) в операторе goto; 3) перед оператором, на который осуществляется безусловный переход, в этом случае метка от оператора отделяется двоеточием. Организация циклов с помощью операторов условного и безусловного переходов. Пусть требуется вычислить наибольший общий делитель двух натуральных чисел А и В. Воспользуемся алгоритмом Евклида: будем уменьшать каждый раз большее из чисел на величину меньшего до тех пор, пока оба числа не станут равны. Исходные данные Первый шаг Второй шаг Третий шаг А =25 В= 15 А= 10 В- 15 А =10 В=5 А=5 В=5 НОД (А, В) =5 program P5; label 1,2; var a, b: integer; begin write (‘введите два натуральных числа’); readln(a, b); 1: if a = b then goto 2; if a > b then a: = a - b else b: = b - a; goto 1; 2: write (‘НОД = ‘, a); readln; end. Оператор цикла пока. Циклический процесс можно организовать без использования специальных операторов. Но удобнее с операторами цикла пока, который имеет вид: while условие do оператор; и выполняется следующим образом: оператор (тело цикла) повторяется до тех пор, пока выполняется условие (истинно логическое выражение). Оператор может быть простым или составным, заключенным в операторные скобки begin ... end. Для алгоритма Евклида программа примет вид: program P6; var a, b: integer; begin write (‘введите два натуральных числа’); 19 readln (а, b): while a<>b do if a>b then a: = a - b else b: = b - a; write (‘НОД = ‘, a); readln; end. Оператор цикла до. Проверка условия в цикле до осуществляется после выполнения оператора. Если условие в цикле пока является условием продолжения повторений, то условие в цикле до — условием выхода из цикла, его завершением. Поэтому для одной и той же задачи эти условия противоположны. Общий вид оператора: repeat оператор until условие; Между словами repeat (повторить) и until (до тех пор пока) можно записать любое количество операторов без использования операторных скобок. Перед словом until не ставится точка с запятой. Программа нахождения наибольшего общего делителя примет вид: program P7; var a, b: integer; begin write (‘введите два натуральных числа’); readln(a, b); repeat if a > b then a: = a - b; if b > a then b: = b - a until a = b; write (‘НОД = ‘,a); readln; end. Операторы циклов пересчет. При выполнении программ нахождения наибольшего общего делителя число повторений различно для разных данных. Когда известно число повторений, удобно использовать цикл пересчет. В Паскале имеется два оператора для организации циклов пересчет: прямой и обратный. Прямой пересчет идет от известного меньшего числа до известного большего, на каждом шаге прибавляется единица (например, от 120 до 140: 121, 122, 123, .... 139, 140). Оператор прямого пересчета: for i: = n1 to n2 do оператор; читается как «для i начиная с n1 до n2 выполнить оператор». Переменная i называется переменной цикла, она при прямом пересчете всегда меняется от меньшего значения до большего. При i = n1 цикл выполняется первый раз. Затем к значению переменной i добавляется единица и осуществляется проверка, не превысило ли полученное значение величину n2. Если i+1 n2, то оператор выполняется, если нет, то происходит выход из цикла и выполнение следующего по порядку оператора программы. Поскольку оператор цикла for сам изменяет значение переменной цикла, ее нельзя менять другими способами, например присваиванием ей какого-либо значения в теле цикла (она не должна появиться слева от знака «:= »). Оператор в цикле может быть простым или составным, заключенным в операторные скобки. Оператор пересчет работает как цикл до, поэтому надо 20 быть внимательным, оператор в теле цикла выполнится всегда хотя бы один раз. Рассмотрим примеры использования операторов цикла. 1. Пусть надо вычислить аn. Известно, что для получения целой степени п числа его надо умножить само на себя п раз. Это произведение при выполнении программы будет храниться в ячейке с именем р. Каждый раз, при очередном выполнении цикла, из этой ячейки будет считываться предыдущий результат, домножаться на основание степени а и снова записываться в ячейку р. Основной оператор в теле цикла повторяется п раз и имеет вид: р: = р * а; При первом выполнении цикла в ячейке р должно находиться число, не влияющее на умножение, т. е. до цикла туда надо записать единицу. Программа имеет вид: Выполнение программы а=2 п=5 I P 1 2 3 4 5 1 2 4 8 16 32 program P8; var a, p: real; i, n: integer; begin write (‘введите a — основание степени, а = ‘); readln (a); write (‘введите целое n — показатель степени, n = ‘); readln(n); p:= 1; for i: = 1 to n do p: = p * a; write (‘p = ‘, p); readln end. Перед текстом программы представлен протокол ее выполнения при возведении числа 2 в пятую степень. Таблица заполнена вручную, процесс ее заполнения называется отладкой программы. Отладка — это проверка всех этапов работы программы. Для сложных задач сначала составляется контрольный пример (тест) и программа выполняется человеком, который выполняет каждый оператор так, как его выполняет компьютер. Затем программу выполняет компьютер и сверяются все промежуточные, полученные при счете данные и конечные результаты. Только после полного совпадения программа выполняется с реальными данными. Для понимания работы программы, выполнения отдельных операторов полезно заполнять подобные протоколы для всех учебных задач. 21 2. Вычисление р = n! (n факториал). По определению п!= 1 * 2 * 3 * ... * n. Используя предыдущую программу, вычислим р как произведение чисел от 1 до n, т. е. р каждый раз умножается не на одно и то же число, а на значение переменной цикла. program P9; var p, i, n: integer; begin write (‘введите целое n = ‘); readln(n); p= 1; for i: = 1 to n do p: = p* i; write (n,’! = ‘,p); readln end. 3. Составление таблицы значений функции у = sin x. Пусть требуется составить таблицу значений функции на отрезке [0;3.14] с шагом 0,1. Чтобы не определять количество повторений вычислений, можно воспользоваться циклом пока. Используя вывод вещественных чисел с фиксированной точкой, определим, что количество цифр после запятой в значении функции будет равно 5. Тогда все число, учитывая область значений синуса, займет семь позиций (числа положительные, значит, добавится позиция для десятичной точки и целой части числа). Программа имеет вид: program P10; var x, у: real; begin x: = 0; writeln (‘x’ : 10,’sin x’ : 10); while x< =3.14 do begin y: = sin(x); writeln (x : 10,’ ‘,y : 7 : 5); x: = x+ 0.1 end; readln end. При каждом выполнении цикла будет сначала проверяться условие (x 3.14), затем вычисляться значение функции, печататься аргумент х (для него отведено десять позиций, из них одна — для цифры дробной части) и, через три пробела, — значение функции. Для следующего шага цикла вычисляется новое значение аргумента (х увеличится на 0,1). Цикл пока позволяет изменять переменную цикла как угодно, увеличивая ее или уменьшая на любое число. 4. Суммирование чисел. При суммировании, как и при умножении нескольких чисел, необходимо накапливать результат в некоторой ячейке памяти, каждый раз считывая из этой ячейки предыдущее значение суммы и 22 увеличивая его на очередное слагаемое. Пусть известно, что будет складываться n чисел. В этом случае надо n раз выполнить действие s: = s + а; здесь a — очередное число, вводимое с клавиатуры. Для первого выполнения этого оператора присваивания надо из ячейки с именем s взять такое число, которое не повлияло бы на результат сложения. Следовательно, прежде чем начать выполнять цикл, надо поместить в эту ячейку (или, что то же самое, присвоить переменной s) число нуль. Программа имеет вид: program Р11; var a, s: real; i, n: integer; begin write (‘введите количество слагаемых n = ‘); readln(n); s: = 0; for i: = 1 to n do begin write (i,’- oe число - ‘); readln(a); s: = s + a end; write (‘сумма s = ‘,s); readln end. Если количество чисел неизвестно, то можно задать числоограничитель, например нуль. В таком случае используется цикл while или repeat. s:=0; s:=0; readln(а); repeat while а <> 0 do readln(a); begin s: = s + a; s: = s + a readln(a) until a = 0; end; Оператор цикла обратный пересчет работает аналогично оператору цикла прямого пересчета, только переменная цикла не возрастает с каждым шагом на единицу, а на единицу убывает. Оператор имеет вид: for i: = n2 downto nl do оператор; Для этого оператора должно также выполняться п2 > nl. При использовании в программе операторов цикла необходимо соблюдать следующие правила: — внутри цикла может находиться другой цикл, но необходимо, чтобы циклы имели разные переменные и внутренний цикл полностью находился в теле внешнего цикла; — нельзя передавать управление в тело цикла, минуя заголовок (это значит, что метка и оператор goto с этой меткой должны находиться в теле цикла); — если требуется обойти группу операторов в теле цикла и продолжить цикл, т. е. выполнить его следующий шаг, то надо передать управление на замыкающий цикл end; — можно досрочно выйти из цикла, или используя оператор goto, или изменив параметр условия в операторах while и repeat так, чтобы цикл 23 больше не выполнялся. Методические указания по работе и задания № Условие задачи 1 Для различных вводимых с клавиатуры целых чисел найдите сумму положительных нечетных. 2 Подсчитать число цифр целого положительного числа. 3 Одноклеточная амеба делится каждые 3 часа на 2 клетки. Определить сколько амеб будет через 3, 6,9,12,…,24 часа. 4 В интервале [2;n] найти натуральное число с максимальной суммой делителей. 5 Составить программу, которая печатает таблицу умножения и сложения натуральных чисел в десятичной системе счисления. 6 Начав тренировку спортсмен в первый день пробежал 10км. Каждый день он увеличивал дневную норму на 10% нормы предыдущего дня. Какой суммарный путь пробежит спортсмен за 7 дней. 7 Написать программу, которая выводит таблицу y=2,4х2+5х –3 в диапазоне от –2 до 2 с шагом 0,5. 8 Написать программу, которая выводит таблицу степеней двойки ( до 10). 9 Написать программу, выводящую на экран «электронные часы», которые работают в течение, например, трех минут или до тех пор, пока пользователь не нажмет любую клавишу. 10 Написать программу приближенного вычисления интеграла функции f(x)=5x2- x + 2 методом прямоугольника (методом трапеций). 11 Дано положительное число А. Найдите среди чисел 1, 1 + 1/2, 1 + 1/2 + 1/3, ... первое, большее А. 12 Вводя числа с клавиатуры без ограничения их количества (конец ввода — число нуль), найдите сумму положительных и произведение отрицательных чисел. 13 Составить алгоритм решения задачи: сколько можно купить ваз, салфеток и цветов, платя за вазу 10р., за салфетку-5р., а за цветок – 0,5р., если на 100р. надо купить 100 предметов. 14 Напишите программы вычисления сумм: значений функции а) сорока слагаемых вида п — i, где i = 1, 2, 3, .... 40, a n — данное число; б) п слагаемых вида х + i, где х —- данное число, а i меняется от 1 до п; в) ста слагаемых, имеющих вид дроби (i + 1) / (i + 2); 24 г) п слагаемых вида (i + 1)2, где i = 1, 2, .... n; д) кубов n первых натуральных чисел; е) n слагаемых sin х + sin2 х + sin3 х + ... + sinn х; ж) п слагаемых sin х + sin х2 + sin х3 + ... +- sin хn; 15 Напишите программы вычисления произведений: а) a * (a + 1) * (a + 2) * ... * (a + n - 1); б) a * (a - n) * (a – 2n) * ...* (a - n2); в) (x - 1) (x - 2) (х - 3) ... (x - п); г) 2 * 4 * 6 * ... * (2n); д) (1 + sin 0.1) (1 + sin 0.2) ... (1 + sin 10); е) n сомножителей вида (x+i)2; ж) всех чисел от 1 до 100 кратных 3, но не кратных 6. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Перечислите возможные способы организации цикла с заданным числом повторений. 2. Сколько раз выполнится оператор цикла repeat, если условие после слова until истинно при входе в цикл? 3. Объясните, какая разница между условиями, записанными после слов while и repeat для одной и той же задачи. 4.Что такое итерационный процесс? Его отличие от цикла с заданным числом повторений. 5. В чем преимущества использования операторов цикла в программах? 6. Рассказать правила организации цикла. 7. Каково условие выхода из цикла при вычислении суммы бесконечного ряда? Лабораторная работа №5 МАССИВЫ Цель работы: приобрести навыки решения задач с использованием одномерных массивов, усвоить операторы используемые при работе с массивами: ввода и вывода одномерных массивов, оператора описания. Краткие теоретические сведения. В рассмотренных ранее примерах программ производилась обработка одиночных данных — значений простых переменных. При решении практических задач данные объединяются в различные структуры, наиболее простыми из которых являются массивы. Массив — именованный набор с фиксированным количеством однотипных данных. В массивы объединены результаты экспериментов, списки фамилий, различные сложные структуры данных. Так, список из классного журнала 10 «А» является массивом. В массиве могут быть одинаковые данные, поэтому 25 элементы массива различаются по своим порядковым номерам. Если каждый элемент имеет один порядковый номер, то такой массив называется одномерным, если два — то это таблица из строк и столбцов. Для таблиц первый номер элемента показывает строку, а второй — столбец, на пересечении которых находится элемент. Все строки таблицы имеют одинаковую длину. Одномерный массив может быть числовой последовательностью с известным количеством членов. Так же, как и в последовательности, в массиве можно указать элемент с конкретным номером, например a5, или записать общий вид элемента, используя в качестве индекса переменную и указывая диапазон ее изменения: ai, i = 1, 2, ..., n. Задачи на обработку массивов могут иметь различную формулировку. Например, начинаться со слов «Дано п чисел...», а далее говорится, что требуется сделать с этими числами. Чтобы решить такую задачу на компьютере с использованием языка программирования Паскаль, необходимо выполнить следующее: 1) определить, какие числа даны: целые или вещественные (если об этом конкретно не сказано, то лучше считать их вещественными); 2) назвать весь массив одним именем, которое будет использоваться для каждого элемента, только к нему добавится номер этого элемента (индекс); 3) описать массив в разделе переменных var, тем самым отведя место в памяти для массива; 4) ввести данные в память. В описании массива имеется специальное слово array (массив), после которого в квадратных скобках через две точки указывается диапазон изменения номеров элементов, затем слово of (из) и пишется тип данных массива. Встретив описание массива, транслятор отводит для него столько последовательных ячеек, сколько указано в квадратных скобках, и такого формата, каков тип данных массива. Эту память в программе можно использовать целиком или частично, вычисляя значения элементов массива или вводя их с клавиатуры (либо с диска). Чаще всего номера элементов меняются от 1 до заданного числа n. Поместив значение п в разделе констант (const), в описании можно указать в качестве переменной n последнее значение (верхнюю границу) номера элемента массива. Пример описания: const n = 10; var a: array [1 .. n ] of real; Это описание означает, что для массива а будет отведено десять ячеек оперативной памяти по шесть байтов каждая. Имена ячеек: а1, а2, ... , a10. В Паскале эти имена будут записаны следующим образом: а[1], ... , a[10]. В описании после имени массива а ставится двоеточие, за которым указывается тип данного — массив. Если в программе несколько массивов одного размера и типа, то, как и для простых переменных, их имена можно перечислить через запятую, а потом, после двоеточия, указать описание массива. Для ввода данных в память необходимо организовать цикл. Поскольку число повторений ввода данных известно, удобно использовать цикл пересчет. Ввод описанного массива a может иметь вид: for i: = 1 to n do 26 read (a[ i ]); Вводимые значения набираются на клавиатуре через пробел и нажимается <Enter>. Можно ввод прокомментировать и вводить каждое данное на отдельной строке экрана:for i: = 1 to n do begin write (‘a[‘, i, ‘] = ‘); readln (a [ i ]) end; При обработке массивов решения многих задач основываются на следующих, более простых, задачах: вычисление суммы (произведения) элементов массива; нахождение наибольшего (наименьшего) элемента; упорядочение элементов по возрастанию или убыванию. Рассмотрим эти базовые задачи. 1. Вычисление суммы элементов массива. Вычисление суммы элементов массива ничем не отличается, в принципе, от суммирования значений простых переменных (программа Р11). Решение задачи состоит из трех основных этапов: 1) ввод данных; 2) вычисление суммы; 3) печать результатов. program Р12; const n = 7; var a: array [ 1 .. n ] of real; S : real; i: integer; begin write (‘вводите элементы массива — ‘, n, ‘ вещественных чисел через пробел’); for i: = 1 to n do read (a [ i ]); S : = 0; for i: = 1 to n do S : = S+a [i]; writeln; write (‘ сумма элементов массива S = ‘, S) end. Выполнение программы вычисления суммы элементов массива представлено в таблице: I 1 Исходные данные: 3, -2, 9, 7, -1, 6, 1 2 3 4 5 6 A[i] 3 -2 9 7 -1 6 1 S 0 1 10 17 16 22 23 7 2. Нахождение наибольшего элемента массива. В предыдущем примере производились вычисления, переменная S меняла свои значения в процессе решения задачи. Однако большинство задач, решаемых с помощью компьютера, являются невычислительными. К ним относится задача поиска наибольшего элемента в массиве. Трудность при разработке алгоритма решения заключается в том, что надо записать в виде команд компьютеру привычные для человека действия: выделение большего 27 из последовательности чисел. Чтобы лучше представить себе, как последовательно просматривать и сравнивать между собой числа, записанные в памяти, вообразим, что каждое число написано на отдельной карточке и карточки сложены стопкой. В таком случае мы первое число запомним сразу как наибольшее и перевернем карточку. Теперь в нашем распоряжении два числа: одно видим, другое — помним. Сравнивая их между собой, запомним большее, т. е. если первое было больше, то запоминать новое не придется и надо смотреть следующую карточку. Если второе больше первого, то первое в дальнейшем помнить нет смысла и мы запомним второе. Таким образом, на каждом этапе сравнения мы будем помнить большее из просмотренных чисел и в конце решим поставленную задачу. Записав приведенные рассуждения в виде операторов, получим программу нахождения наибольшего значения. Промежуточные значения и ответ содержит переменная max. program Р13; const n = 7; var a: array [ 1 .. n ] of integer; max, i: integer; begin for i: = 1 to n do begin write (‘a[‘, i, ‘] = ‘); readln (a [ i ]); end; max: = a [1 ]; for i: = 2 to n do if max < a [ i ] then max: = a [ i ]; write (‘наибольший элемент массива max = ‘, max) end. 3. Упорядочение массива по возрастанию. Упорядочения массивов по какому-либо признаку называются также сортировками. Существуют различные методы сортировок, различающиеся, в основном, по скорости получения результата. Рассмотрим один из них — «метод пузырька». Пусть имеется последовательность чисел a1, а2, ..., an, которую необходимо упорядочить по возрастанию. Зафиксируем первый элемент и будем последовательно сравнивать его со стоящими справа. Если какой-то из элементов справа окажется меньше первого, то мы поменяем местами этот элемент с первым и продолжим сравнение уже нового элемента, стоящего на первом месте, с оставшимися справа числами. Если снова выявится элемент, меньший зафиксированного, то повторим перестановку. В результате первого просмотра последовательности на первом месте окажется наименьший из всех элементов, т. е. он, как более «легкий», как бы всплывает наверх (отсюда и название метода — «метод пузырька»). Теперь зафиксируем второй элемент и повторим просмотр, выполняя при необходимости перестановки элементов, и т. д. Уяснив идею решения, остановимся на двух вопросах: каким образом фиксировать элементы и как осуществить перестановку двух элементов? Чтобы при переборе элементов, стоящих справа от проверяемого, не менялся индекс последнего, индексы фиксируемого и стоящих правее него элементов должны быть различными: i и j. Индекс i изменяется от 1 до п — 1, индекс j всегда на 1 больше i и пробегает 28 все значения от i + 1 до n. Для каждого значения i индекс j должен последовательно принять все допустимые значения, следовательно, конструкция программы, отражающая полный перебор всех элементов и их упорядочение по возрастанию, представляет собой двойной цикл. При перестановке двух элементов используется третья переменная. Перестановка местами (обмен значениями в памяти) двух переменных а и b выглядит следующим образом: 1) с: = а; 2) a: = b; 3) b: = с. Программа сортировки методом пузырька имеет вид: program Р14; const n = 7; var a : array [ 1.. n ] of real; i, j: integer; c: real; begin for i: = 1 to n do begin write (‘a [‘, i, ‘] = ‘); readln (a [ i ]) end; for i: = 1 to n - 1 do for j: = i + 1 to n do if a [ i ] > a [ j ] then begin c: = a [ i ]; a[i]:= a[j]; a [ j ]: = c end; writeln (‘упорядоченный по возрастанию массив ‘); for i:= 1 to n do write (a [ i ]); end. 4. Поиск элемента в массиве. Одна из важных невычислительных задач — поиск данного значения среди элементов массива, Такой поиск называется также поиском по ключу. На практике поиск осуществляется в упорядоченном массиве, причем имеются различные алгоритмы поиска. В данном примере осуществим поиск путем сплошного перебора. Если элемент найден, то напечатаем его номер, если нет, то выдадим соответствующее сообщение. Существенным является то, какой из одинаковых элементов массива, равных данному, нас интересует: первый встретившийся при поиске или последний. В этом примере будем искать первый. Поиск осуществляется в цикле, и как только элемент найден, надо выйти из цикла. Для досрочного выхода из цикла for используем оператор goto. Если досрочный выход не произойдет, то значит, элемент, равный данному, в массиве отсутствует. В таком случае выдача сообщения об отсутствии элемента происходит сразу после цикла поиска. Следовательно, чтобы обойти печать номера элемента, надо использовать еще один оператор goto и еще одну метку в программе. Программа поиска данного элемента в массиве: program Р15; label 1,2; const n = 7; 29 var a : array [1 .. n ] of real; x : real; i : integer; begin writeln (‘введите элементы массивов’); for i: = 1 to n do read (a [ i ]); writeln; write (‘введите число для поиска в массиве, х = ‘); readln (х); for i: = 1 to n do if a [ i ] = x then goto 1; writeln (‘такого числа в массиве нет’); goto 2; 1: write (‘номер элемента массива, равного данному ‘, i); 2: end. Если искать не первый по порядку равный ключу элемент, а последний, то надо использовать цикл обратного пересчета: for i: = n downto 1 do. Методические указания по работе и задания № Условие задачи 1 Написать программу, которая проверяет, находится ли в массиве введенное с клавиатуры число и сколько раз. 2 Подсчитать количество ненулевых элементов, введенного с клавиатуры массива. 3 В заданной последовательности целых чисел определите количество и сумму элементов, кратных 10. 4 Написать программу, которая определяет количество учеников в классе, чей рост превышает средний. 5 Найдите сумму квадратов неотрицательных элементов и количество положительных чисел в заданном целочисленном одномерном массиве. 6 Вычислите среднее арифметическое наибольшего и наименьшего из п чисел. 7 Найдите полупроизведение всех положительных элементов массива 8 Составить программу, которая вычисляет среднюю (за неделю) температуру воздуха. 9 Дано n чисел. Найдите сумму чисел, больших заданного числа а. 10 Проверить, представляют ли элементы введенные с клавиатуры массива возрастающую последовательность. 11 Дан целочисленный массив с количеством элементов n. Напечатать те его элементы, индексы которых являются степенями двойки. 30 12 Заполнить случайными числами из диапазона [0;1] вещественный линейный массив из N чисел. Найти максимальное значение и его индекс. 13 Пригодность детали оценивается по размеру В, который должен соответствовать интервалу (А+, А-). Определить имеются ли в партии из N деталей бракованные. Если да, то подсчитать их количество, иначе выдать отрицательный результат. 14 При поступлении в вуз абитуриенты, получившие «двойки» на первом экзамене, ко второму не допускаются. В массиве А[n] записаны оценки экзаменующихся, полученные на первом экзамене. Подсчитать, сколько человек не допущено ко второму экзамену. 15 Дан массив чисел. Найти, сколько в нем пар одинаковых соседних элементов. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Чем отличается массив от файла? 2. Для чего необходимо описание массива? 3.Что надо сделать, чтобы начать решать на компьютере задачу, формулировка которой начинается со слов: «Дано п чисел...»? 4. Может ли массив содержать разнородные данные? 5. Что надо изменить в программе Р13, чтобы осуществлялся поиск не наибольшего, а наименьшего элемента массива? 6. Какие изменения в программу Р13 надо внести, чтобы одновременно со значением наибольшего числа определялся его порядковый номер? 7. Объясните работу двойного цикла в программе Р14. Лабораторная работа №6. ОБРАБОТКА ТАБЛИЦ. (ДВУМЕРНЫХ МАССИВОВ) Цель работы: приобрести навыки в решении задач с использованием двумерного массива. Краткие теоретические сведения Двумерный массив (или прямоугольная таблица) В из n строк и т столбцов в общем виде выглядит следующим образом: b11 b12 … b1m b21 b22 … b2m . .. . .. ... . .. bn1 bn2 … bnm На Паскале имена элементов массива записываются так же, с двумя номерами (индексами): b (1,1), b (1, 2), .... b (1, т), b (2, 1), b (2, 2), ..., b (2, т), .... b (n, т). В памяти компьютера элементы двумерного массива расположены один за другим: после элементов первой строки следуют элементы второй строки и т. д. Если число строк таблицы равно числу столбцов, то такая 31 таблица называется квадратной. Главная диагональ квадратной таблицы проходит из левого верхнего угла в правый нижний. Рассмотрим примеры. 1. Вычисление суммы элементов главной диагонали квадратной таблицы. Для решения задачи надо выполнить следующие шаги: 1) ввести таблицу в память; 2) найти сумму элементов главной диагонали; 3) напечатать результат. Описание таблицы, как и описание одномерного массива, используется для резервирования памяти. В описании указываются диапазоны для двух номеров: строк и столбцов. const n = 3; var b: array [ 1..n, 1..n ] of real; i, j: integer; При обработке массивов в разделе переменных программы появляются имена индексов элементов: для одномерного массива — одной, для двумерного — двух целочисленных переменных. При вычислении суммы элементов диагонали следует обратить внимание на имена суммируемых элементов: оба индекса имеют одинаковые значение, т. е. в общем виде имя элемента диагонали — b[ i, i ]. Это означает, что можно рассматривать диагональ, как одномерный массив, и использовать один цикл для вычислений. program Р16; const n =3; var b: array [ 1 .. n, 1 .. n ] of real; i, j: integer; S: real; begin writeln (‘введите значения элементов таблицы по строкам’); writeln (‘в конце каждой строки нажимайте <Enter> ‘); for i: = 1 to n do begin for j: = 1 to n do read (b[i,j]); writeln end; S: = 0; for i: = 1 to n do S: = S+ b [i, i ]; write (‘ сумма элементов диагонали таблицы S = ‘ , S) end. 2. Нахождение наибольших элементов каждой строки таблицы. Каждую строку таблицы можно рассматривать, как одномерный массив, и использовать идею нахождения наибольшего значения в программе Р13. Найденные значения будем помещать в одномерный массив. В программе Р17 для каждой строки таблицы переменная а [ i ] играет такую же роль, как переменная mах в программе Р13. Для каждой строки (ее задает переменная i) элемент a [ i ] получает значение первого элемента строки. Затем внутренний цикл по переменной j позволяет просмотреть все элементы данной строки и, если среди них встретится элемент, значение которого больше, чем запомненное в а [ i ], то оно присваивается a [ i ]. Для распечатки результатов работы программы — массива а — используется цикл. Имеющийся в программе комментарий, заключенный в фигурные скобки, позволяет при чтении программы выделить основную ее часть. 32 Пример Р17 — нахождение наибольших элементов строк: Массив результатов А [1] 6 1 а [2] 5 2 а [3] Данная таблица 5 6 4 12 2 -3 1 15 0 program Р17; const n = 3; var b: array [ 1 .. n, 1 .. n ] of integer; i, j: integer; a: array [1 .. n ] of integer; begin writeln (‘введите значения элементов таблицы по строкам’); writeln (‘в конце каждой строки нажимайте <Enter> ‘); for i: = 1 to n do begin for j: = 1 to n do read (b [ i, j ]); writeln end; {построение массива наибольших значений элементов строк таблицы} for i: = 1 to n do begin a[i]:= b[i,1 ]; for j: = 2 to n do if a[i]<b[i,j] then a [i]: = b[i,j]; end; writeln (‘наибольшие числа строк таблицы:’); for i: = 1 to n do writeln (a [ i ]) end. 3. Нахождение сумм элементов столбцов таблицы. При обработке таблиц можно осуществлять операции как над строками, так и над столбцами. Для нахождения сумм элементов столбцов можно использовать алгоритм примера Р12. Чтобы лучше понимать работу программы, введем переменную S для вычисления суммы, а затем для каждого столбца запишем полученный результат в массив a, т. е. присвоим его переменной а [j ], где j — текущий номер столбцов таблицы. Пример Р18 — суммирование по столбцам: 5 4 2 Данная таблица 6 12 -3 Массив результатов 1 15 0 а [1] а [2] а [3] 33 11 15 16 program Р18; const n = 3; var b: array [ 1 .. n, 1 .. n ] of integer; S, i, j: integer; a: array [1 .. n ] of integer; begin writeln (‘вводите значения элементов таблицы по строкам’); writeln (‘в конце каждой строки нажимайте <Enter>‘): for i: = 1 to n do begin for j: = 1 to n do read (b [ i, j ]); writeln; end; {построение массива сумм элементов столбцов таблицы} for j: = 1 to n do begin S: = 0; for i: = 1 to n do S: = S+ b [i,j]; a [j ]: = s end; writeln (‘суммы элементов столбцов таблицы:’); for i: = 1 to n do write (a [ i ]) end. 4. Перестановка строк таблицы. В прямоугольной таблице В из n строк и m столбцов требуется поменять местами две строки. При решении этой задачи можно воспользоваться алгоритмом обмена значениями двух переменных из программы сортировки (пример Р14). Для этого достаточно организовать цикл по переменной столбца и, используя промежуточную переменную, менять местами каждую пару элементов, стоящих в одном столбце. При заданных номерах строк К и L решение выглядит так: program Р19; const n = 3; m = 4; var b: array [ 1 .. n, 1 .. m ] of real; c: real; i, j, K, L: integer; begin write (‘введите номера меняемых местами таблицы’); readln (К, L); {ввод таблицы} for i: = 1 to n do begin writeln (i, ‘-я строка таблицы’); for j: = 1 to m do read (b [ i, j ]); 34 строк end; {перестановка строк} for j: = 1 to m do begin c:= b[K,j]; b [ K, j ]: = b [ L, j ]; b [ L, j ]: = с end; {печать результатов} writeln; writeln (‘таблица с переставленными строками:’) for i: = 1 to n do begin for j: = 1 to m do write (b [ i, j ]); writeln end end. Методические указания по работе и задания № Условие задачи 1 Найдите произведения элементов строк прямоугольной таблицы. 2 Найдите наибольший элемент квадратной таблицы. 3 Замените все отрицательные числа их модулями. 4 Найдите наим. элемент квадратной таблицы и замените его нулем. 5 В квадратной таблице, не содержащей отр. элементов, найдите корень квадратный из произведения диагональных элементов. 6 В целочисленной прямоугольной таблице увеличьте на 0,5 все отрицательные элементы. 7 В целочисленной прямоугольной таблице расставить строки таким образом, чтобы элементы в первом столбце были упорядочены по убыванию. 8 В квадратной таблице найдите наибольший элемент диагонали. 9 В заданном массиве замените нулем наибольший элемент 10 Поменяйте местами 1-ую и последнюю строки прям-ой таблицы. 11 Составить программу подсчета числа различных элементов двумерного массива. 12 В прямоугольной таблице замените все элементы их квадратами 35 13 Квадратичную матрицу, состоящую из натуральных чисел повернуть на 90 градусов по часовой стрелке и вывести результат на экран. 14 Написать программу, которая вычисляет сумму диагональных элементов квадратичной матрицы. 15 Написать программу, которая проверяет, является ли введенная матрица магическим квадратом (сумма элементов которой в каждой строке, в каждом столбе и по каждой диагонали одинакова). Лабораторная работа №7 ОПЕРАТОР ВАРИАНТА. (ВЫБОРА) Цель работы: отработать практические навыки работы с оператором выбора (варианта). Краткие теоретические сведения Условный оператор позволяет осуществить ветвление программы только по двум направлениям, одно из которых соответствует выполнению проверяемого условия, а другое — невыполнению этого же условия. Если для переменной необходимо осуществить ряд действий, зависящих от других условий, то надо записывать либо вложенные условные операторы, либо несколько таких операторов подряд. Для такой ситуации удобно использовать оператор варианта. Он соответствует структуре, изображенной на рисунке 6. Данная структура называется также переключателем и выполняется следующим образом. Вход в структуру содержит вычисление или ранее полученное значение переменной (индекса варианта). Это значение может совпасть с меткой, стоящей перед оператором на одной из ветвей переключателя. В таком случае выполняется оператор, помеченный этой меткой, и происходит выход из структуры. Оператор бывает простым или составным, ограниченным операторными скобками begin ... end;. Если значение индекса варианта не совпало ни с одной из меток, то выполняется оператор с номером п + 1 из строки else. Если оператор варианта содержит строку else, то это — полная форма оператора, если такой строки нет, то используется сокращенная форма оператора варианта. Метки оператора варианта могут быть константами любого типа. Их тип должен совпадать с переменной индекса варианта. Возможно, чтобы индекс варианта был как именем переменной, так и выражением соответствующего типа. 36 Рис. 6. Структура оператора варианта На языке Паскаль оператор варианта имеет вид: case индекс варианта of метка1: оператор 1; метка2: оператор 2; ... метка n: оператор n; else оператор n + 1 end; Пример программы, содержащей оператор варианта. Одной из распространенных задач раздела физики «Молекулярно-кинетическая теория» является задача, связанная с расчетом числа молекул в единице объема в теле заданной массы и в теле известного объема. Для такой задачи можно построить программу-решатель. Дано: молярная масса вещества М, плотность данного вещества Р, масса R или объем данного тела V. Требуется найти число молекул К: 1) в единице массы вещества; 2) в теле с заданной массой; 3) в единице объема вещества; 4) в теле с заданным объемом. Для решения задачи воспользуемся формулой: К= (NA/M)R, где NA = 6,022 * 10 23 г/моль — число Авогадро. На основании этой формулы получаем расчетные формулы для программы: 1) К = N A/ М; 2) К= N AR/M; 3) К= NA Р V/ М; 4) К= NA Р/ М. Программа имеет вид: program Р20; const NA = 6.022 E20; var N: integer; М, R, Р, V, К: real; begin writeln (‘зная постоянную Авогадро, плотность Р данного вещества’); writeln (‘и его молярную массу М, можно найти число молекул в’); writeln (‘1. в единице массы вещества’); writeln (‘2. в теле массой R’); writeln (‘3. в единице объема’); writeln (‘4. в теле объемом V’); write (‘введите номер решаемой задачи’); readln (N); write (‘введите исходные данные: М = ‘); readln (М); case N of 1: К: = NA/M; 2: begin write (‘R = ‘); readln (R); K: = NA -R/M; end; 3: begin 37 write (‘плотность вещества Р = ‘); readln (Р); write (‘V= ‘); readln (V); K: = NA *P-V/M; end; 4: begin write (‘плотность вещества Р = ‘); readln (Р); К: = NA "P/V end; end; write (‘число молекул К = ‘, К’) end. Методические указания по работе и задания № Условие задачи 1 Написать программу, которая запрашивает у пользователя номер месяца и выводит соответствующее название времени года (если недопустимое число то « ошибка ввода данных»). 2 Написать программу, которая запрашивает у пользователя номер дня недели и выводит одно из сообщений: «Рабочий день», «Суббота», «Воскресенье». 3 Написать программу, которая после введения с клавиатуры числа в диапазоне от 1 до 999, обозначающего денежную единицу, дописывает слово «рубль» в правильной форме.(12 рублей, 21 рубль …) 4 Написать программу, которая вычисляет дату следующего дня. 5 Найти наибольшее из двух действительных чисел, используя оператор выбора. 6 Написать программу, определяющее животное, соответствующее введенному году по китайскому гороскопу. 7 Преобразуйте символ, если он является строчной русской буквой, в заглавную букву. Предполагается использование альтернативной кодировки ASCII. 8 Написать программу, которая после введения с клавиатуры числа в диапазоне от 1 до 99, обозначающего денежную единицу, дописывает слово «копейка» в правильной форме (5 копеек, 41 копейка …). 9 Написать программу, которая после введения с клавиатуры числа в диапазоне от 1 до 99, обозначающего возраст человека, дописывает слово «год», «года», «лет» соответственно во фразу «Мне … лет» ( 5 лет, 2 года, 41год …). 38 10 Написать программу, определяющее по заданному году и номеру месяца количество дней в этом месяце. 11 Написать программу, которая читает натуральное число в десятичном представлении (до 10000), а на выходе выдает это же число на естественном языке (7 семь, 204 двести четыре, 12 двенадцать). 12 Написать программу, позволяющую получить словесное описание школьных оценок (1-плохо, 2-неудовлетворительно, 3-удовлетворительно, 4-хорошо, 5отлично). 13 Написать программу, которая для любого натурального числа печатает количество цифр в записи этого числа. 14 Даны два действительных положительных числа. Составить программу, которая по введенной операции выполняла бы то или иное действие. 15 Написать программу, которая по данному натуральному числу от 1 до 12 (номеру месяца) выдает все приходящиеся на этот месяц праздники (например число1, то: 1января-Новый год, 7 января - Рождество). Лабораторная работа №8 ПОДПРОГРАММЫ Цель работы: приобрести навыки в решении задач с использованием процедур, функций, подпрограмм. Краткие теоретические сведения При разработке программы иногда появляются повторяемые группы действий или возникает необходимость расчленить программу на функциональные модули, сделать ее структуру иерархической. Для этого во всех языках программирования существуют средства организации подпрограмм. Для решения сложной задачи рекомендуется сначала алгоритм, а затем и программу разрабатывать «сверху вниз», от более общего плана к детальному. В таком виде главная программа соответствует укрупненному плану решения задачи, а ее команды — вызову соответствующей подзадачи, реализованной в виде подпрограммы. Идя по такому пути создания программы, можно отдельные мелкие функции реализовывать сначала в виде небольших подпрограмм, проверять их на контрольных примерах и, только убедившись в правильности работы, включать в состав основной программы. Это удобнее проделывать, имея в распоряжении язык, позволяющий полностью выделить подпрограмму из текста основной программы в виде отдельного модуля. Использование подпрограмм дает возможность разрабатывать программу по частям, поручать реализацию больших проектов группам разработчиков. В состав групп входят специалисты данной науки 39 или производства, из области которой решается задача, разрабатывающие алгоритм и структурирующие данные, а также программисты, объединяющие алгоритм и данные в программе для компьютера. В Паскале подпрограмма является частью основной программы, ее описание располагается между разделом var главной программы и ее программным блоком (первым begin). Подпрограмм может быть несколько, их описания располагаются в произвольном порядке одно за другим. Описание подпрограммы можно сравнить с записываемой в математике формулой «в общем виде», в которую при расчетах подставляются конкретные значения. Поскольку далеко не каждую задачу удается свести к некоторой формуле, но всегда можно записать алгоритм ее решения, подпрограмма — это та же инструкция по решению некоторой задачи. Как и формула, подпрограмма используется для различных данных, передаваемых из главной программы или других подпрограмм. Подпрограмма — это специальным образом оформленный алгоритм, который может многократно использоваться при решении более общей задачи. В Паскале различают два вида подпрограмм: процедуры и функции. Основное различие между ними заключается в том, что процедура получает в результате своей работы любое количество данных, а функция — только одно значение. Подпрограммы имеют структуру, аналогичную главной программе. Они содержат заголовок со специальным словом — признаком подпрограммы, имя и, при необходимости, списки передаваемых на обработку и получаемых из подпрограммы данных. Затем могут располагаться все имеющиеся в главной программе разделы описаний: меток, констант, типов и переменных. В этих разделах описываются данные, используемые только внутри подпрограммы и являющиеся промежуточными при ее выполнении. Такие данные называются локальными. В подпрограмме могут участвовать переменные, описанные в главной программе. Эти данные называются глобальными, их значения и подпрограмма, и главная программа берут из общей памяти. При работе с подпрограммой всегда выделяется два этапа: описание подпрограммы, т. е. запись алгоритма решения задачи в специальной форме, и вызов подпрограммы — передача ей данных на обработку из вызываемой программы, которая, в свою очередь, может быть подпрограммой, и получение обратно результатов. Рассмотрим способы организации подпрограмм в Паскале. Процедура — подпрограмма, имеющая любое количество входных и выходных данных. Процедура может быть описана без параметров и с параметрами. Параметры — это данные из заголовка процедуры, как передаваемые ей на обработку, так и получаемые в виде результатов. Таким образом, с помощью параметров происходит обмен информацией между процедурой и вызывающей ее программой. Процедуры без параметров. Описание процедуры имеет вид: procedure имя; {описание локальных переменных} 40 begin {операторы} end; Процедура без параметров может реализовывать любой алгоритм. Все переменные, над которыми производят действия операторы процедуры, определяются в вызывающей программе, им присваиваются необходимые для выполнения процедуры значения. Рассмотрим пример вычисления наименьшего общего кратного двух натуральных чисел НОК (X, Y), которое можно вычислить, используя наибольший общий делитель этих чисел, по формуле: HOK(X,Y) = Х*У/НОД(Х,У). При составлении программы оформим как процедуру без параметров программу Р7 — вычисление НОД по алгоритму Евклида. Результат работы процедуры будет заносится в ячейку с именем М, переменная М описана как глобальный параметр и используется и главной программой, и процедурой. В программе будем вычислять НОК нескольких чисел, занеся их в массив С. Этот массив формируется в разделе констант главной программы. Если данные определяются в разделе констант, то они не требуют дополнительного описания в разделе переменных (var). Переменная Х сначала содержит значение первого числа, а затем ей присваивается результат — НОК двух первых чисел. Переменная Y имеет своим значением второе число из пары, для которой вычисляется наименьшее общее кратное. Таким образом, при каждом шаге цикла вычисляется НОК двух чисел, первое из которых Х содержит результат предыдущего шага. Вызов процедуры НОД вычисления наибольшего общего делителя осуществляется только по имени: NOD; Рассмотрим пример выполнения программы вычисления НОК нескольких чисел. Х := НОК (X, Y) Y:=C[i] М := НОД (X, Y) 36 54 18 108 72 36 216 18 18 216 15 3 1080 Текст программы имеет вид: program Р21; const c: array [1 .. 5] of integer = (36, 54, 72, 18, 15); var x, y, i, m: integer; procedure NOD; {заголовок процедуры} var a, b: integer; {описание локальных переменных} begin a: = x; b: = у; {сохранение исходных данных} while а <> b do if a > b then a: = a — b else b: = b — a; m: = а; {результат работы процедуры присваивается глобальной переменной} end; {конец процедуры} begin {начало главной программы} 41 x: = с[1 ]; for i: = 2 to 5 do begin y:= c[i]; NOD; {вызов процедуры без параметров} x: = x * у div m {div — деление нацело для целочисленных данных} end; write (‘ НОК = ‘, x) end. {конец главной программы} Процедуры с параметрами. Для удобства передачи данных в процедуру и получения из нее результата используются формальные и фактические параметры. Формальные — условные обозначения в описании процедуры — описываются в ее заголовке, фактические — с которыми требуется выполнить процедуру — перечисляются при вызове процедуры, формальные и фактические параметры должны соответствовать по количеству, типу и порядку следования. Формальные параметры описываются только в заголовке процедуры и больше нигде. Их описание похоже на описание данных в разделе переменных и может также содержать слово var. Слово var в заголовке процедуры ставится перед теми параметрами, имена которых соответствуют выходным данным. Фактические параметры, соответствующие формальным, перед которыми стоит слово var, могут быть только именами переменных. Перед именами формальных переменных, являющимися входными данными процедуры, слово var указывать не обязательно. Если перед формальным параметром в заголовке процедуры нет слова var, то ему может соответствовать формальный параметр, имеющий вид выражения соответствующего типа. Если для входных данных процедуры при описании формальных параметров указано слово var, то им также соответствуют фактические параметры — имена переменных. Например, процедура NOD с параметрами может иметь заголовок: procedure NOD (a, b: integer; var k: integer); Вызов этой процедуры: NOD (x, у, m); или: NOD (36, 54, m); Переменные в заголовке процедуры — формальные параметры, заменяемые при выполнении процедуры на конкретные значения переменных х и у или числа 36 и 54. В заголовке процедуры NOD описаны формальные параметры: a и b — входные данные, для которых находится наибольший общий делитель; k — результат работы процедуры. При вызове процедуры переменная а примет значение x, а переменная b — значение у. Результат работы процедуры при вызове попадет в ячейку с именем т, которой соответствует формальный параметр k. Программа при использовании процедуры с параметрами примет вид: program Р22; const с: array [1 ..5] of integer = (36,54,72,18,15); var x, у, i, m: integer; procedure NOD (a, b: integer; var k :integer); {заголовок процедуры} begin while a <> b do if a > b then a: = a - b 42 else b: = b - a; k: = а {значение переменной k— результат работы процедуры} end; {конец процедуры} begin {начало главной программы} х:= с[1]; for i: = 2 to 5 do begin y:= c[i]; NOD (x, y, m); {вызов процедуры с фактическими х: = х * у div m параметрами} end; write (‘ НОК = ‘, х) end. {конец главной программы} Например. Найдем с помощью процедуры среднее арифметическое, наибольший и наименьший элементы массива. program Р23; const n = 10; type R = array [ 1 ..n ] of real; var Y: R; A, B, C: real; i: integer; procedure Stat (X : R; var S, min, max: real); begin S: = 0; min: = x [1]; max: = x [1]; for i: = 1 to n do begin S: = S+x[i]; if x [ i ] < min then min: = x [ i ]; if x [ i ] > max then max: = x [ i ] end; S: = S/n end; begin {главная программа} for i: = 1 to n do read (Y [ i ]); Stat (Y, А, В, С); {вызов процедуры} writeln; write (‘среднее = ‘, А, ‘наименьшее = ‘, В, ‘наибольшее = ‘,C); end. В программе Р23 появился новый раздел описаний — раздел типов данных type. В этом разделе можно описать новый тип данных через уже известные типы, которые могут быть так же ранее описаны в данном разделе. Тип данных R — это массивы из n вещественных чисел, R — имя типа. В дальнейшем этот тип позволяет сократить описания, он используется в главной программе при описании исходного массива Y и в заголовке процедуры при описании формального параметра — массива X. Главная программа состоит из трех основных этапов: 1) ввода данных — массива Y; 2) вызова процедуры Stat с фактическими параметрами — массивом Y и получаемыми результатами, попадающими соответственно в 43 ячейки А (среднее значение), В (наименьшее) и С (наибольшее); 3) печати результатов работы программы. Подпрограммы-функции. Подпрограмма, имеющая единственный результат, может быть оформлена, как функция. Описание функции имеет вид: function имя_функции (описание входных данных): тип_результата; {описания локальных переменных} begin {операторы} имя_функции: = результат; end; После описания формальных параметров, которые являются аргументами функции, в заголовке указывается тип результата, т. е. тип самой функции. Это описание относится к имени функции, которому необходимо присвоить значение результата работы подпрограммы. Как и процедура, функция может содержать все четыре раздела описаний локальных переменных. Имя функции нельзя использовать для промежуточных вычислений. Функция вызывается с помощью указателя. Указатель — это имя функции, после которого в круглых скобках перечислены фактические параметры — аргументы функции. Указатель имеет вид: имя_функции (список фактических параметров) Указатель может появиться в выражении соответствующего типа, в условиях операторов if, while и repeat после слова until, а также в операторе печати write. Примерами являются встроенные арифметические функции, такие, как sin(x): write (sin(x)); Рассмотрим третий вариант программы вычисления наименьшего общего кратного. Поскольку наибольший общий делитель двух натуральных чисел — единственное число, то вычисляющую его подпрограмму можно оформить, как функцию. Программа имеет вид: program Р24; const с: array [1 .. 5] of integer = (36,54,72,18,15); var x, у, i: integer; function NOD (a, b: integer): integer; {заголовок функции} begin while a < > b do if a > b then a: = a - b else b: = b - a; NOD: = а {результат работы функции присваивается ее имени} end; {конец описания функции} begin {начало главной программы} x: = с [ 1 ]; for i: = 2 to 5 do begin y: = с [ i ]; x: = x * у div NOD (x, у) {вызов функции} 44 end; write (‘ HOK = ‘.x) end. {конец главной программы} Методические указания по работе и задания № Условие задачи 1 Написать функцию, которая возвращает максимальное из двух целых чисел, полученных в качестве аргумента. 2 Написать процедуру, которая выводит на экран строку, состоящую из звездочек. Длина строки (количество звездочек) является параметром функции. 3 Написать функцию, которая вычисляет значение аb. 4 Написать функцию вычисления факториала. 5 Написать функцию, которая сравнивает два целых числа и возвращает результат сравнения в виде одного из знаков: >,<,=. 6 Написать процедуру ввода элементов матрицы. 7 Написать процедуру ввода и вывода элементов матрицы. 8 Написать функцию, которая находит сумму цифр целого числа. 9 Написать функцию, которая находит цифровой корень целого числа. 10 Вычислить площадь правильного шестиугольника со стороной а, используя подпрограмму вычисления площади треугольника. 11 Составить программу разложения данного натурального числа на простые множители.(200= 23+52) 12 Дано четное число n>2. Проверить для него гипотезу Гольдбаха: каждое четное n представляется в виде суммы простых чисел. 13 Из заданного числа вычесть сумму его цифр. Из результата вновь вычесть сумму его цифр и т.д. Через сколько таких действий получится нуль. 14 Дано простое число. Составить функцию, которая будет находить следующее за ним простое число. 15 Дан прямоугольник со сторонами A и B, где А, В- натуральные числа. Начнем отсекать от него квадраты. Сколько квадратов можно отсечь, если каждый раз отсекается самый большой квадрат. 45 ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Что такое подпрограмма и для чего она используется? 2. Объясните назначение локальных и глобальных переменных. 3. Как происходит обмен данными с процедурой без параметров? 4. Что такое формальные и фактические параметры? 5. К чему относится описание типа в конце заголовка подпрограммыфункции? 6. Чем отличается вызов функции от вызова процедуры? 7. Как задать значения элементов массива без использования оператора ввода? Лабораторная работа №9 РЕКУРСИЯ Цель работы: научиться рекурсивных функций и процедур. решать задачи с использованием Краткие теоретические сведения. Если поставить два зеркала напротив друг друга и между ними поместить предмет, то получится бесконечное множество изображении, причем каждое из них содержит свое собственное. Любое из этих изображений можно рассматривать как рекурсивный объект, который частично состоит или определяется с помощью самого себя. Рекурсивные объекты обладают несколькими свойствами: — простотой построения; — несхожестью конечного результата с начальными данными; — внутренним самоподобием. В математике встречаются рекурсивные определения, позволяющие описать объекты через самих себя. К таким определениям относится, например, определение натурального числа: 1) единица есть натуральное число; 2) число, следующее за натуральным (т. е. больше его на единицу), есть натуральное число. Определение, которое задает некоторый объект в терминах более простого случая этого же объекта, называется рекурсивным определением. Мощность рекурсивного определения заключается в том, что оно позволяет с помощью конечного высказывания определить бесконечное множество объектов. Как и цикл, рекурсивное определение содержит повторения, но каждый раз при этом используются новые данные, т. е. повторения не являются явными. Рекурсия — это способ описания функций или процессов через самих себя. Процесс может быть описан некоторым алгоритмом, называемым в данном случае рекурсивным. В нем выделяется два этапа выполнения: 1) «погружение» алгоритма в себя, т. е. применение определения «в обратную сторону», пока не будет найдено начальное определение, не являющееся рекурсивным; 2) последовательное построение от начального определения до определения с введенным в алгоритм значением. Примеры рекурсивных алгоритмов, часто оформляемых в виде 46 процедур и функций. 1. Наиболее распространенным рекурсивным определением является определение факториала (нерекурсивное вычисление факториала приведено в примере Р9): (a) 1! = 1, (b) n > 1, n: = n*(n - 1)! На основе этого определения можно записать программу вычисления факториала, использующую рекурсивную функцию. program Р25; var n, у: integer; function F (x: integer): integer; {описание рекурсивной функции} begin if x=1 then F: = 1 {вызов для начального определения} else F: = х * F (х - 1) {вызов для предыдущего определения} end; {конец описания функции} begin {начало главной программы} readln (n); Y: = F (n); {вызов функции в главной программе} write (n, ‘! = ‘, Y) end. {конец главной программы} Выполним программу Р25 для n = 4. Рекурсивная функция будет работать следующим образом (при вызове функции значение n присваивается переменной х). Сначала осуществляется «погружение», работает оператор ветви else условного оператора: 1-й шаг: х = 4, х-1 = 3, выполняется промежуточное вычисление 4! = 4 * З! 2-й шаг: х = 3, х-1 = 2, выполняется промежуточное вычисление З! = 3 * 2! 3-й шаг: х = 2, х-1 = 1, выполняется промежуточное вычисление 2! = 2 * 1! 4-й шаг (последний): 1! = 1 по начальному определению, работает оператор F: = 1 ветви then условного оператора. Следующий этап выполнения рекурсивного алгоритма — построение «прямого» определения, от начального до получения результата с исходными для алгоритма данными (числом 4). При этом осуществляется подстановка предыдущих вычислений (более поздних шагов) в более ранние: 5-й шаг: 2! = 2 * 1 = 2 6-й шаг: З! = 3 * 2 = 6 7-й шаг: 4! = 4 * 6 = 24 — получен результат, он возвращается в главную программу и присваивается переменной Y. 2. Вычисление степени с натуральным показателем можно определить рекурсивно: (a) x 0 = 1 (b) k > 0: xk = x* xk - 1 Этому определению соответствует рекурсивная функция power (k, x). Программа имеет вид: program Р26; var у: real; n: Integer; function power (k: integer; x: real): real; {описание рекурсивной функции} 47 begin if k=0 then power: = 1 {начальное определение} else power: = x * power (k - 1, x) {рекурсивное определение} end; {конец описания функции} begin {начало главной программы} write (‘ основание степени х = ‘); readln (у); write (‘показатель степени k = ‘); readln (n); write (‘х в степени k’, power(n, у)) {вызов функции и печать результата} end. {конец главной программы} 3. Вычисление чисел Фибоначчи. Итальянский математик Фибоначчи придумал последовательность натуральных чисел: 1, 1, 2, 3, 5, 8, 13, ... . Первые два члена последовательности равны единице, а каждый, начиная с третьего, равен сумме двух предыдущих. Для чисел Фибоначчи верно соотношение: Fk = Fk + Fk-2 Рекурсивная функция получения значения n-го числа Фибоначчи имеет вид: function Fib (n: integer): integer; begin if k<3 then Fib: = 1 else Fib: = Fib (n - 1) + Fib (n - 2) end; Для чисел Фибоначчи используется следующее рекурсивное определение: (a)n= 1, n=2: fib(n) = 1 (b) n > 2: fib (n) = fib (n - 2) + fib (n - 1) Для того чтобы определить fib (6), применяя данное рекурсивное определение, надо вычислить: fib (6) = fib(4) + fib(5) = fib(2) + fib(3) + fib (5) = 1 + fib(3) + fib(5) = = 1 + fib(l) + fib(2) + fib(5) = 1 + 1 + 1 + fib(5) = 3 + fib(3) + fib(4) = = 3 + fib(l) + fib (2) + fib(4) = 3 + 1 + 1 + fib(4) = 5 + fib(2) + fib(3) = = 5 + 1 + fib(l) + fib(2) = = 6+1+1=8 Количество действий в данных вычислениях с использованием рекурсивного определения чисел Фибоначчи резко возрастает, потому что это определение ссылается само на себя дважды. При вычислении факториала количество действий при выполнении программы с рекурсивной функцией и примера Е9 одинаково. 4. Рекурсивные алгоритмы могут быть оформлены и в виде процедур. Примером такой процедуры является решение задачи о Ханойских башнях. Эта задача связана с легендой о том, что в одном из восточных храмов находится бронзовая плита с тремя алмазными стержнями. На один из них при сотворении мира нанизали 64 диска из чистого золота так, как показано на рисунке 7. Жрецы должны переносить диски с одного стержня на другой, следуя следующим законам: 48 1) диски можно перемещать только по одному; 2) нельзя класть больший диск на меньший. Согласно легенде, когда все диски будут перенесены с одного стержня на другой, наступит конец света. Решение этой задачи реализовано в виде рекурсивного алгоритма, который представляет собой инструкцию по перемещению дисков. Сформулируем задачу, присвоив имена стержням (А, В, С) и номера дискам (от 1 до n). Надо перенести диски со стержня А на стержень С, используя В как вспомогательный и Рис. 7. Ханойские башни следуя приведенным выше правилам переноса дисков. Алгоритм на естественном языке имеет вид: 1) если n = 0, остановиться; 2) переместить верхние п - 1 дисков со стержня А на стержень В, используя стержень С как вспомогательный; 3) переместить оставшийся диск со стержня А на стержень С; 4) переместить п - 1 дисков со стержня В на стержень С, используя стержень А как вспомогательный. В процедуре появляется новый тип данных — char, значение этого типа — один символ, заключенный в апострофы. program Р27; var k: integer; procedure Hanoy (n: integer; One, Two, Three: char); begin if n > 0 then begin Hanoy (n - 1, One, Three, Two); write (‘ переместить диск’, n, ‘со стержня ‘, One, ‘на стержень ‘, Two); Hanoy (n - 1, Two, One, Three) end; end; begin write (‘введите количество дисков’); readln (k): Hanoy (k,’А’,’В’,’С’) end. Результат работы программы для n = 3 — это инструкция из 7 пунктов (п = 4 — инструкция из 15 пунктов): переместить диск 1 со стержня А на стержень С переместить диск 2 со стержня А на стержень В 49 переместить диск 1 со стержня С на стержень В переместить диск 3 со стержня А на стержень С переместить диск 1 со стержня В на стержень А переместить диск 2 со стержня В на стержень С переместить диск 1 со стержня А на стержень С Методические указания по работе и задания № Условие задачи 1 Написать функцию, которая находит цифровой корень целого числа. 2 Найти сумму цифр заданного натурального числа. 3 Найти количество цифр в заданном натуральном числе. 4 Составить программу вычисления суммы четных факториалов. четное, n10) 5 Описать рекурсивную логическую функцию Simm(S,I,J), проверяющую, является ли симметричной часть строки S, начинающаяся i-м и заканчивающаяся j-м ее элементом. 6 Составить программу вычисления суммы нечетных факториалов. четное, n10) 7 Составить программу сортировки массива целых чисел. 8 Составить программу вычисления НОД двух натуральных чисел. 9 Составить программу нахождения числа, которое образуется из данного натурального числа при записи его цифр в обратном порядке.(173371) 10 Составить программу перевода данного натурального числа в р-ичную систему счисления( 2р9) 11 Дан прямоугольник со сторонами A и B, где А,В- натуральные числа. Начнем отсекать от него квадраты. Сколько квадратов можно отсечь, если каждый раз отсекается самый большой квадрат. 12 Поиска значений в упорядоченном списке. 13 Найти сумму 1/1+1/2+1/3+1/4+…+1/n,основываясь на рекурсии.(сумма k слагаемых равна сумме (k-1) слагаемых плюс k-е слагаемое). 14 Напишите главную программу для вычисления n-го числа Фибоначчи. Почему использовать рекурсивный алгоритм вычисления n-го числа Фибоначчи невыгодно? 15 Определите рекурсивно умножение как сложение и деление как вычитание и 50 (n- (n- оформите алгоритмы в виде рекурсивных функций с вызовом из главных программ. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Что такое рекурсивный объект и каковы его свойства? 2. Приведите примеры рекурсивного определения в математике. 3. Что такое рекурсия? 4. Как выполняется рекурсивный алгоритм? 5. Поясните выполнения рекурсивной функции вычисления степени с натуральным показателем. Лабораторная работа №10 ОБРАБОТКА СТРОК В ПАСКАЛЕ Цель работы: приобрести навыки в решении задач, обрабатывающих символьные данные и усвоить функции обработки символьных данных. Краткие теоретические сведения. В памяти компьютера могут храниться числа и символы. Любой символ занимает один байт памяти. Для данного, соответствующего одиночному символу, используется описатель char. Символы могут объединяться в массивы. Каждому элементу массива, как и числовому данному, соответствует порядковый номер, а имя элемента состоит из имени всего массива и его собственного номера. В тексте программы не всегда можно определить, какой массив обрабатывается: числовой или символьный, это можно понять только по описанию массива. Значение символьного данного — любой символ клавиатуры компьютера, ограниченный апострофами. Например: ‘А’, ‘?’, ‘5’ — значения символьных величин. Примеры описаний: var a: array [ 1.. 50 ] of char; x, y: char; Массив а может состоять из 50 символов, ему отводится при трансляции программы 50 байтов памяти. Элементы массива: a[1], а[2], ..., а[50]. Переменные х и у — простые, их значения — одиночные символы. Для ввода символьного массива необходимо использовать цикл: for i: = 1 to n do read (a[ i ]); При вводе такого массива достаточно набрать строку из п символов и в конце нажать <Enter>. Можно объявить в описании таблицу символов и для ее ввода использовать двойной цикл: const n = 10; m = 15; var b: array [ 1..n, 1:m ] of char; i, j: integer; begin for i: = 1 to n do begin 51 for j: = 1 to m do read (b [ i,j ]); writeln end; end. В примере используется b — таблица из 10 строк по 15 символов каждая. При ее вводе необходимо набирать строки по 15 символов и нажимать <Enter>. Неудобство такого ввода заключается в том, что все строки должны содержать по 15 символов, т. е. если набираются слова, то в них не может быть более чем 15 букв, а в коротких словах надо добавлять пробелы. При обработке символьных массивов используются такие же алгоритмы, как и для числовых. Например, требуется слово, заданное как массив символов, записать в обратном порядке, т. е. справа налево. При разработке алгоритма можно использовать такую постановку задачи: данный числовой массив переписать так, чтобы последний элемент встал на первое место, предпоследний на второе и т. д., а первый — на последнее. Другими словами, необходимо из массива а1, а2, ..., аn, получить аn, аn-1, ..., а1 ,который будет находиться в массиве b (рис.8). На рисунке 8 в рамке обведена формула пересчета индекса: когда у массива а номера перечисляются в прямом порядке, т. е. текущий индекс элемента массива изменяется от 1 до n, у элементов массива b индексы должны меняться от n до 1. Рис. 8. Перемещение элементов из массива а в массив b и пересчет индексов Такое изменение и обеспечивает данная формула, она приведена для индексов массива b. Программа Р32 производит перемещение элементов в обратном порядке, для символьных данных она называется программой обращения слова: program Р28; const n = 15; var a, b: array [ 1.. n ] of char; i: integer; begin for i: = 1 to n do begin read (a [ i ]); b [n-i+1]:= a[i] end; for i: = 1 to n do write (b [ i ]) end. Несколько подряд записанных символов образуют строку. Строка — это ограниченная апострофами последовательность любых символов. Длина строки, обрабатываемой в Паскале, не должна превышать 255 52 символов (апострофы не считаются). Это связано с тем, что в конце строки, в дополнительном байте, хранится ее длина — количество символов, а наибольшее целое число, которое может быть записано в байте, — 255. Если требуется обработать текст, длина которого большее 255 знаков, то надо использовать массив строк. Описание строки имеет вид: var х: string [ 20 ]; Строка х должна быть не более чем из 20 символов. Если она меньше, то будет занимать в памяти столько байтов, сколько знаков она содержит (плюс 1 байт — длина). Поэтому при вводе строк нет необходимости дополнять их до указанной в описании длины. Для обработки строк используются специальные операции и собранные в специальную библиотеку подпрограммы. Операции позволяют работать со строками, как с цельными объектами, а подпрограммы, в основном, — с отдельными символами или частями строк. Операции над строками — это объединение, сравнение и присваивание. Объединение строк. Эта операция позволяет объединить две строки в одну, присоединив начало второй строки к концу первой. Объединение обозначается знаком «+». Например: var x, у, 2: string [ 10 ]; begin: x: = ‘тепло’; у: = ‘ход’; z: = х + у; write (z) end. Переменным х и у присваиваются значения строк, а переменной z результат объединения этих строк в одну: ‘теплоход’. При печати строки будет выдано содержимое области памяти, называемой z. Очевидно, что операция объединения строк некоммутативная, т. е. для нее а+b < > b+а, поэтому при использовании объединения необходимо предусматривать, с какой стороны к данной строке присоединяется другая: слева или справа. Как и для арифметических операций, для данной операции со строками существует нейтральный элемент, не влияющий на ее результат. Это — строка нулевой длины (пустая строка), обозначаемая двумя рядом стоящими апострофами ("). Такую строку можно присоединить к любой строке слева или справа и строка не изменится. Сравнение строк. Для строк используются такие же операции отношения, как и для чисел, но они имеют несколько другой смысл. Если строки сравнивать на «равно» (=), то выполнение равенства означает посимвольное совпадение строк. Соответственно «не равно» (<>) означает несовпадение хотя бы в одном знаке. Остальные отношения (<, , , >) относятся к длинам строк, т. е. сравниваются не символы строк, а их количества. Если записать: ‘а’ < ‘b’ + ‘с’, то сначала выполнится объединение строк (эта операция имеет более 53 высокий приоритет), а затем сравнение длин. В данном случае условие удовлетворяется, так как строка из одного символа меньше (по длине), чем строка из двух символов. Присваивание. Оператор присваивания для строковых данных имеет вид: Имя_строковой _переменной: = строковое выражение; Имя строковой переменной может быть простое или с индексом (элементом массива строк). Если в результате выполнения всех операций строкового выражения получается строка, длина которой превышает длину в описании переменной, стоящей слева от знака присваивания, то такая строка укорачивается справа до допустимой длины. var x: string [ 6 ]; begin х: = ‘мим’ + ‘озабоченный’; write (x) end. В результате работы этой программы будет напечатано слово «мимоза». Поэтому допустимая длина x - 6 символов, значение выражения справа от присваивания «мимозабоченный» сократится до «мимоза», остальные символы будут отброшены. Длина строки. Функция длины строки выдает количество символов строки: length (строковое_выражение) Например: program Р29; var х, у: string [ 20 ]; k, I, n: integer; begin writeln (‘введите две строки’); readln(x); readln(y); k: = length (x); I: = length (y); n: = length (x + y); writeln (‘длина первой строки’: 25, ‘длина второй строки’: 25); writeln (k: 25, I: 25); writeln (x + у, ‘длина строки’, n) end. В программе Р29 используется вывод с форматированием результата. Первый раз формат (: 25) указан после строки, выводимой на экран (‘длина первой строки’). Это означает, что для данной строки отводится 25 позиций экрана, а поскольку выводимый текст короче (20 символов), он дополнится вначале пробелами, т. е. окажется правоустановленным в отведенном ему поле. Аналогично расположатся в предназначенном для них месте экрана целые числа — длины строк. Таким образом, результат работы программы будет иметь вид: длина первой строки длина второй строки 7 10 С помощью форматирования можно располагать выводимые данные в столбцах, строить на экране дисплея таблицы. Копирование строки или ее части. Функция копирования называется также «вырезкой». Она позволяет скопировать одну область памяти в другую. Для копирования необходимо указать строковое выражение, из значения которого выделяется часть, а также начальный номер символа и количество 54 символов копируемой части: copy (строковое выражение, начальный номер символа, количество символов) Например, результатом работы функции copy (‘информатика’, 3, 5) будет слово ‘форма’. Применим данную функцию для разработки второй версии программы обращения слова. Будем обрабатывать слово, выделяя из него буквы и присоединяя к результату слева. Переменной у, содержащей результат, сначала присваивается значение пустой строки. Переменная цикла изменяет свои значения от 1 (первого символа слова) до длины вводимой строки (номера последнего символа слова). program Р30; var x, у: string [10 ]; i: integer; begin write (‘введите слово’); readln(x); y: = "; {присваивание результату начального значения —пустого слова} for i: = 1 to length (x) do у: = copy (x, i, 1) + у; {присоединение копируемой буквы слева} writeln; write (у) end. Поиск подстроки в строке. Функция поиска определяет, с какой позиции (номера символа) одна строка (подстрока) содержится в другой (данной строке). Если такое вхождение подстроки в строку имеет место, то результат работы функции — номер символа в исходной строке, с которого начинается подстрока. Если вхождения нет, то результат — нуль. Аргументы функции могут быть строковыми выражениями. роs (подстрока, исходная строка) Вставка в строку. В одну строку можно вставить другую строку, указав номер символа, начиная с которого осуществляется вставка. Входные данные процедуры — вставляемая строка, исходная строка и целочисленное выражение, задающее позицию вставки. Строки также могут быть заданы строковыми выражениями. Результат работы процедуры помещается в исходную строку, строка при этом «расширяется». Если длина вставки совместно с длиной исходной строки превышает допустимую длину исходной строки, то вставка укорачивается справа до допустимой длины. insert (вставляемая строка, исходная строка, целочисленное выражение); Удаление части строки. Часть строки можно удалить, строка при этом «сжимается». Для удаления необходимо указать строку (в виде строкового выражения), начальный номер удаляемой части строки, количество удаляемых символов. Процедура удаления вызывается следующим образом: delete (строка, начальный номер, количество символов); Рассмотрим пример замены буквы в слове. Сделаем из слова «форма» 55 слово «фирма». program Р31; var x: string [10]; begin x: = ‘форма’; insert (‘и’, x, 2); {вставка буквы «и», получилось слово «фиорма»} delete (x, 3, 1); {удаление третьей буквы — буквы «о»} write (x) end. Методические указания по работе и задания № Условие задачи 1 Удалить из строки заданное слово. 2 Дана строка символов до точки. Подсчитать сколько слов содержит данная строка. 3 Дана строка символов до точки. Определить длину самого длинного и самого короткого слова в ней. 4 Дана строка символов до точки. Определить, сколько слов начинается и кончается одной и той же буквой. 5 Определить сколько строке. 6 Определить является ли введенная строка правильным выражением (рассматривать только круглые скобки) 7 Вывести на экран задом наперед данную строку символов. 8 Определить, является ли заданное слово симметричным. 9 Подсчитать количество слов в строке заканчивающейся точкой. 10 Определите, является ли данное слово палиндромом («перевертышем», например, «казак», «потоп», «кок» и т. д.). 11 Дана строка с несколькими запятыми. Получите слово между первой и второй запятыми. Решите задачу с применением массива символов и строки символов. 12 Из данной символьной строки выбрать все цифры и сформировать другую строку из этих цифр, сохранив их последовательность. 13 Дана строка содержащая произвольный текст. Выяснить чего в нем больше: русских букв или цифр. 56 слов содержит хотя бы одну букву «а» в заданной скобочным 14 Составьте программу циклической перестановки букв слова Х.. 15 Составить программу, которая выбирает и печатает сначала все гласные буквы слова, затем все согласные буквы. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Чем отличается символьный тип данных от строковых? 2.Перечислите специальные функции для обработки символьных данных. Лабораторная работа №11 КОМПЬЮТЕРНАЯ ГРАФИКА Цель работы: приобрести навыки использования графического режима, закрепить знание графических операторов, научиться строить графики и диаграммы. Краткие теоретические сведения. Для построения изображения на экране дисплея используется специальная библиотека подпрограмм, называемая Graph. В нее входят графические процедуры и функции для выдачи различных по форме фигур и линий, а также средства организации графического режима. Эти средства предназначены для анализа возможностей используемого дисплея — разбиения поля экрана на различное число мелких квадратиков, каждый из которых считается отдельной точкой изображения и называется пикселем. Для дисплея типа VGA число точек может быть 640 * 480, а количество используемых цветов — 16. Однако более сложные, не рассматриваемые здесь средства Паскаля позволяют увеличить количество цветов до 256. Цвет, как и координаты экранной точки, задается целым числом. Начало координат экрана находится в левом верхнем углу (точка 0,0), ось Ох направлена вправо, Оу — вниз (рис.9). Рис. 9. Система координат экрана дисплея Эту особенность направленности оси Оу следует учитывать при построении изображений, особенно графиков функций и диаграмм. Для построенной Рис. 10. Установление соответствия между точками отрезка [а, b] и осью Ох экрана дисплея 57 на рисунке 9 окружности необходимо отмечать координаты центра и радиус, для прямоугольника — координаты противоположных вершин (например, А и D). Координаты точки А (180, 160) заданы на рисунке. Каждое изображение можно также построить по точкам, указав для каждой точки ее координаты и цвет. При построении изображений используются так называемые графические примитивы — базовые конструкции и их модификации. К графическим примитивам относятся: точка, отрезок, дуга. Точка. Для выдачи точки на экран используется вызов процедуры PutPixel (x, у, номер_цвета); где x, у — координаты точки. С помощью этого оператора можно построить график функции. Построение графика функции. Чтобы построить график, необходимо сначала задать отрезок области определения, на котором функция существует, и отобразить этот отрезок на ось Ох экрана дисплея. Точке х отрезка [а, b] из области определения функции должна соответствовать точка х экрана дисплея, а точке у = f(x) — значению функции — точка у1 экрана (рис. 10). Таким образом происходит масштабирование графика, что дает возможность отображать на экран любой отрезок области определения. Здесь, безусловно, надо учитывать разрешающую возможность экрана, чтобы масштаб позволил увидеть качественное поведение функции. Точки на экране, в отличие от точек геометрической прямой, имеют дискретные значения. Точки оси Ох нумеруются от 0 до 640, т. е. х1 = 0, 1,2,3, ...,640. Из пропорции (х — а) / (b — а) = (х1 — 0) / (640 — 0) получим расчетную формулу вычисления аргумента функции, соответствующего заданной точке экрана: х = а + х1 * (b - а) / xmax где хтax = 640, если дисплей типа VGA. Для найденного значения аргумента вычисляется значение функции: y=f(x) Теперь необходимо умножить полученное значение функции на коэффициент масштабирования, показывающий, сколько пикселов (физических точек экрана) содержится в выбранной единице масштаба: k = xmax / (b - а) Получаем значение у — координату для выдачи рассчитанной точки графика функции на экран: у1 = у * xmax / (b - а) Теперь следует учесть особенность расположения оси Оу на экране и перевернуть график, предполагающий традиционное положение осей координат, а так- же добавить смещение, чтобы график располагался по центру экрана: у1 = уmax / 2 - у1 С координатами х1 и у1 точка выводится на экран. Поскольку реальные координаты графика функции, по которым она вычисляется, вещественные числа, а координаты точек экрана — целые, то результат, полученный при использовании в программе формулы для вычисления у1, необходимо округлить до ближайшего целого числа. Округление производит функция trunc. аргумент которой — выражение вещественного типа: у1: = trunc (у * xmax / (b - а)). Программа построения графических изображений должна начинаться с оператора подключения библиотеки графических процедур и специальной библиотеки, позволяющей использовать функции операционной системы (библиотеки Crt). Этот оператор располагается сразу за заголовком 58 программы и имеет вид: uses Graph, Crt; Сама программа состоит из описаний процедур построения изображений, описания функции, для которой строится график, и описания специальной процедуры установки графического режима. Главная программа при этом содержит операторы вызова этих процедур и оператор задержки изображения на экране (после построения последней точки изображение исчезает): repeat until keypressed; {выполнять пустой цикл до нажатия любой клавиши} Программа построения графика функции у = sin (х) на отрезке [—, ]: program Р33; uses Graph, Crt; procedure Init; {установка графического режима} var gr, gm: Integer; begin gr: = 0; {автоматическое распознавание типа дисплея} InitGraph (gr, gm, ‘ ‘); {файл egavga.bgi находится в одном каталоге с turbo.ехе} if GraphResult <> grOk then Halt (1); {обработка результата установки} end; function f (х: real): real; {вычисление функции f (х)} begin f: = sin (х) end; procedure grafic; var xmax, ymax, х1, у1: integer; х, y, a, Ь: real; begin xmax: = 640; ymax: = 480; a: = - 3.14; b: = 3.14; for х1: = 0 to xmax do begin х: = a + х1 * (b - a) / xmax; y: = f (х); {вызов подпрограммы-функции} у1: = trunc (y * xmax / (b - a)); у1: = ymax div 2 - у1; PutPixel (х1, у1, 2); {выдача точки зеленым цветом} end end; begin {главная программа} Init; {вызов процедуры установки графического режима} Grafic; {вызов процедуры построения графика функции} repeat until keypressed end. 0 15 15 Рис. 11. 15 0 15 0 15 15 15 0 0 При построении сложных рисунков, выдаваемых по точкам, можно использовать прием мозаики: нарисовать рисунок по клеточкам и 59 заполнить таблицу целых чисел, при этом каждое число соответствует номеру цвета определенной клеточки, а координаты клеточки соответствуют индексам элементов таблицы (рис. 11). Задание цвета. Некоторые графические операторы, такие, как построение точки, включают в себя параметр цвета, но во многих других используется текущий цвет, определенный последним оператором задания цвета: SetColor (цвет); На рисунке 12 приведена таблица цветов, где каждый цвет может быть задан как номером, так и словом (на английском). Отрезок. Для построения отрезка необходимо указать координаты его концов. Отрезок строится текущим цветом. Оператор построения отрезка: Line(x1,y1,x2,y2); При построении изображения компьютер как бы рисует лучом. Луч останавливается в последней точке изображения, координаты которой черный 0 красный 4 серый-т 8 красный-с 12 синий 1 малиновый 5 голубой 9 малиновый-с 13 зеленый 2 коричневый 6 зеленый-с 10 желтый 14 Бирюзовый 3 серый-с 7 Бирюзовый-с 11 Белый 15 Рис. 12. Номера цветов (с-- светлый, т — темный) запоминаются. Можно построить отрезок, указав либо смещение от этой точки по осям х и у, либо координаты конца отрезка (начало там, где остановился луч). Смещение задается в виде целого числа, причем положительное означает увеличение последней координаты на величину смещения, отрицательное — соответственное уменьшение координаты. Смещение удобно использовать для построения изображения в относительных координатах, когда достаточно указать координаты первой точки, а остальные будут пересчитаны. Таким образом можно перемещать картинку по экрану. Оператор построения отрезка с указанием смещения: LineRel (dx, dy); Оператор построения отрезка с указанием последней его точки: LineTo (x, у); Последний оператор удобен для построения графика функции, которая либо резко возрастает, либо резко убывает. В этом случае изображение, построенное по точкам, терпит разрыв, так как для двух соседних аргументов два значения функции находятся далеко друг от друга. Первую точку графика надо выдать оператором Put Pixel, а остальные, вычисляемые и строящиеся в цикле, — оператором LineTo. Луч, строящий изображения, может перемещаться без следа. Это позволяют делать операторы, аналогичные двум последним: 60 Рис. 13. Столбчатая диаграмма успеваемости учащегося по четвертям MoveRel (dx, dy); MoveTo (x, у); Прямоугольник строится подобно отрезку: необходимо указать координаты концов любой диагонали. Прямоугольник может быть построен в виде контура или в виде закрашенной фигуры. Для контурного изображения - оператор Rectangle (x1, у1, х2, у2); для закрашенного Ваг(х1,у1,х2,у2); Построение столбчатой диаграммы. На рисунке 13 представлена столбчатая (линейная) диаграмма падения успеваемости некоторого учащегося по четвертям учебного года. В первой четверти успеваемость составила 75%, во второй — 50%, в третьей — 25%. Построим такую диаграмму с помощью программы, расположив самый высокий столбец в центральной части экрана (его длина — 480 : 3 = 160 пикселов) и рассчитав остальные пропорционально их значениям относительно этого размера. По ширине вся диаграмма занимает также 1/3 часть, т. е. первоначальное значение координаты х равно 210 пикселов, ширина столбцов по 35 и расстояние между ними также 35 пикселов. Для расчета высоты второго столбца составим пропорцию 75 : 50 = 160 : х. Отсюда х = 106 (с округлением до целого). Высота третьего столбца 53 пиксела. Поскольку нижние основания прямоугольников находятся на одно! уровне, для которого у = 320, расчет вторых координат (п оси у) производится вычитанием из 320 высоты соответствующего столбца. Размещение текста на изображении производится с по мощью оператора: OutTextXY (х, у, ‘текст’); где х, у — координаты, начиная с которых будет выдан текст. Программа построения столбчатой диаграммы имеет такую же структуру, как и программа РЗЗ. program Р34; uses Graph, Crt; procedure Init; {установка графического режима} var gr, gm: integer; begin gr: = 0; {автоматическое распознавание типа дисплея} InitGraph (gr, gm, ‘ ‘); {файл egavga.bgi находится в одном каталоге с turbo.ехе} if GraphResult <> grOk then Halt(1); {обработка результата установки} end; procedure Diagram 1; var х, у, х1, y1, x2, y2: integer; begin SetColor (14); Bar (210,160, 245, 320); SetColor (10); Bar (210 + 2*35, 320 -106, 210 + 3-35, 320); SetColor (2); Bar (210 + 4*35, 320 - 53, 210 + 5-35, 320); OutTextXY(210, 320 + 30, ‘Успеваемость по четвертям’); end; begin Init; Diagram 1; repeat until keypressed 61 end. Построение дуги. Для построения дуги. необходимо указать центр соответствующей окружности (х и у), начальный и конечный углы дуги и радиус. Углы отсчитываются против часовой стрелки, их значение указывается в градусах (от 0 до 359). Отсчет угла производится от направленного вправо по горизонтали радиуса. Оператор построения дуги имеет вид: Arc (х, у, начальный_угол, конечный_угол, радиус); Для закрашенного сектора используется следующий оператор с такими же параметрами: PieSlice (х, у, начальный_угол, конечный_угол, радиус); Если указать значения углов соответственно 0 и 359, то получится окружность или закрашенный текущим цветом круг. Окружность можно также изобразить оператором: Circle (х, у, г); Рассмотрим пример построения «рога изобилия», состоящего из окружностей. Центры окружностей перемещаются по окружности, представляющей собой траекторию точки, одна координата которой задается косинусом, а другая — синусом одного и того же угла x1/k. При k = 20 получается замкнутый круг, k = 10 — два круга, k = 30 — полукруг. program Р35; uses Graph, Crt; procedure Init; {установка графического режима} var gr, gm: integer; begin gr: = 0; {автоматическое распознавание типа дисплея} InitGraph (gr, gm, ‘ ‘); {файл egavga.bgi находится в одном каталоге с turbo.ехе} if GraphResult <> grOk then Halt(1); {обработка результата установки} end; procedure Rog; var xmax, ymax, х1, y1, х, у, r: integer; begin xmax: = 640; ymax: = 480; for x1: = 1 to 125 do begin x: = trunc (xmax / 2 + ymax / 2 * cos (x1/20)); y: = trunc (ymax / 2 + xmax / 4 * sin (x1/20)); r: = trunc (ymax / 4 - x1); Circle (x, y, r) end end; begin Init; Rog; repeat until keypressed end Построение круговой диаграммы Диаграммы такого типа представляют собой круги, разделенные н. секторы разной 62 Рис. 14. Круговая диаграмма успеваемости площади (рис. 14) Площадь каждого сектора соответствует некоторой части, как правило, в процентном отношении, а за единицу (целое) принимается площадь всего круга. Вместо площади сектора можно рассчитать длину дуги. Построим круговую диаграмму изменения успеваемости, соответствующую линейной диаграмме на рисунке 13. Программа имеет вид: program Р38; uses Graph, Crt; procedure Init; {установка графического режима} var gr, gm: integer; begin gr: == 0; {автоматическое распознавание типа дисплея} InitGraph (gr, gm, ‘ ‘); {файл egavga.bgi находится в одном каталоге с turbo.exe} if GraphResult <> grOk then Halt(1); {обработка результата установки} end; procedure Diagram2; var xmax, ymax, x1, y1, x, y, r: integer; begin xmax: = 640; ymax: = 480; x: = 320; у: = 240; r: = 200; {координаты центра и радиус диаграммы} x1: = trunc (75 * 36 / 15); {расчет длины первой дуги} SetColor (14); PieSlice (x, у, 0, x1, r); y1: = trunc (50’36/ 15) +x1; SetColor (10); PieSlice (x, у, x1+1, y1, r); {вторая дуга + + первая} SetColor (2); PieSlice (x, y, y1 +1, 359, r); {замыкание круга} end; begin Init; Diagram2; repeat until keypressed end. Методические указания по работе и задания № 1 2 3 4 5 6 Условие задачи разноцветных окружностей, Построить семейство радиусы которых увеличиваются. Написать программу, которая выводит на экран оцифрованную координатную сетку. Написать программу, которая выводит на экран изображение шахматной доски. Написать программу, которая рисует окружность движущуюся по экрану. Написать программу, которая выводит на экран изображение часов, имеющих секундную и минутную стрелки. Написать программу, которая выводит на экран круговую диаграмму, отображающую товарооборот (в процентах) книжного магазина (книги, журналы, открытки и канцтовары) и поместив необходимый текст в диаграмму. 63 7 8 9 10 11 12 13 14 15 Постройте концентрические окружности, закрасив каждую новым цветом. Используя идею детской игры «мозаика», построить изображение разноцветной бабочки, сохранив предварительно в виде таблицы целых чисел (значений цветов) и выдав затем эту таблицу по точкам на экран, применяя двойной цикл. Написать программу, которая выводит на экран изображение работающего светофора. Рекомендуемый вид светофора и алгоритм его работы приведены ниже. С помощью программы построения графика функции постройте графики logx, tgx, cosx на различных участках областей определения этих функций. Построить график функции cos x и при построения графика функции добавьте выдачу на экран координатных осей и отметку на них единицы измерения. Написать программу, которая выводит на экран точечный график функции y=0,5x2+4x-3. Диапазон изменения аргумента – от –15 до 5, шаг аргумента – 0,1. График вывести на фоне координатных осей, точка пересечения которых должна находится в центре экрана. Постройте елочку из п треугольников, определив ее предварительно рекурсивно и использовав в программе рекурсивную графическую процедуру. Написать программу, которая выводит на экран гистограмму успеваемости учеников класса, например по итогам контрольной работы. Дополнить изображение так, чтобы на изображении были все подписи. Напишите программу построения изображения произвольного рисунка, используя для проекта бумагу в клеточку (по теме транспорт, по теме моя любимая игрушка…). ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Как расположены оси координат на экране дисплея? 2. Что такое графические примитивы? 3. Как закрасить один пиксел экрана? 4. Как отобразить отрезок [a,b] на всю ширину экрана? 5. Сколько пикселов будет содержать единица измерения на отображаемом на экране отрезке [а, b]? 6. Как расположить график на экране с учетом направленности оси Оу в противоположную от традиционного направления сторону? 7. Какого типа данные соответствуют экранным координатам? 8. В какой библиотеке Паскаля содержатся графические подпрограммы и как подключить эту библиотеку при выполнении программы? ения? 9. Как задержать изображение на экране после полного его постро- 10. Как задать цвет для построения линий, прямоугольников и дуг? 11. Какой оператор позволяет построить отрезок, используя только одну пару координат? 12. Как переместить рисующий луч по экрану так, чтобы не было следа? 13. Как построить график функции, которая резко возрастает или убывает? 14. Как построить изображение, которое можно перемещать по экрану, 64 задавая координаты только первой его точки? 15. Какие операторы позволяют построить контурный и закрашенный прямоугольники? 16. Как построить линейную диаграмму? 17. Как подписать рисунок? 18. Как построить дугу окружности? Как с помощью оператора построения дуги построить окружность? 19. Как изобразить закрашенный сектор? 20. Для чего используется функция trunc? 21. Что такое круговая диаграмма? Лабораторная работа № 12 ЗАПИСИ. ОБРАБОТКА ЗАПИСЕЙ Цель работы: научиться работать с записями; записывать инструкции присваивания; особое внимание уделить понятию переменной поля записи, очень важного в программировании. Краткие теоретические сведения. Запись – это последовательность байтов на носителе, ограниченная с двух сторон специальными признаками. Такое определение дает представление о записи как о единице обмена между внешней и оперативной памятью компьютера. Однако сама запись бывает сложной структурой, содержащей разные данные. Запись может, например, соответствовать строке ведомости заработной платы, в которой указаны фамилия и несколько чисел, или строке классного журнала, где также содержатся фамилия и оценки. Таким образом, запись понимается как сложная конструкция. Поэтому в Паскале и других программных системах слово «запись» имеет двойной смысл: это и сложная структура, и единица данных на носителе (например, диске). Запись — совокупность разнородных данных, описываемых и обрабатываемых как единое целое. Данные, из которых состоит запись, называются ее полями. Поля могут быть простыми данными или составными, например массивами или записями. С помощью записей удобно описывать свойства объектов, хранить их совместно. Из записей состоят базы данных, включающие описание нескольких объектов. Описание записи состоит из ключевого слова record, после которого указываются имена полей и тип каждого поля. Тип поля отделяется от имени двоеточием. Описание записи заканчивается словом end и точкой с запятой. Записи описываются в разделе типов данных type, В этом разделе указывается имя класса объектов (имя типа) и описание этого класса. Для каждого объекта класса имеется свое имя в разделе переменных var с описанием данного типа. Это имя используется в дальнейшем в программе. Пример. Объект — физическое тело с измерениями а, b, с (длина, ширина и высота). Описание может иметь вид а), когда для каждого 65 поля указан тип данного, или б), когда подряд идущие однотипные поля описаны совместно: б) type z = record a) type z = record a: integer; c: integer b: integer; c: integer end; a, b, end; var x: z; var x: z; Пример. Объект — товар, характеризуется названием и ценой: type tovar = record sign: string [ 20]; price: real end; Пример. Объект — дата рождения: день, месяц, год. День можно указать как диапазон значении, такой тип данных называется интервальным. Этот тип используется для целочисленных и символьных данных в описаниях, а также как метка оператора варианта. Интервальным типом задаются значения констант в разделе const. type date_of_birth = record day: 1 ..31; month: string [10]; year: integer end; var date: date_of_birth; Записи могут объединяться в массивы. Массив записей описывается в разделе type или var. Раздел переменных при объекте товар может иметь вид: var x: array [ 1.. 100 ] of tovar; y: tovar; x — массив записей, к каждому элементу которого используется обычное обращение, например х[ i ]; у — простая переменная. Для обращения к полю записи применяется сложное имя, состоящее из двух имен, разделенных точкой. Первое из них — имя переменной типа «запись» из раздела var, второе — имя поля этой записи из раздела type. Так, для товаров имена полей в программе имеют вид: у. sign, у. price, x [ 1 ]. sign, x [ i ]. price Содержание сведений 66 Ф. И. 0. Должность Дата рождения Зарплата Имя поля записи Тип данных поля name position date salary String [20] string [10] date_of_birth real Пример. Пусть требуется описать сведения о работнике предприятия: фамилию, должность, дату рождения и зарплату. Для каждого поля записи необходимо сначала придумать имя, затем определить, какой тип наиболее удобен для обработки этих данных. Описываемые сведения включают в себя структуру типа структуру типа «запись» (в виде поля даты рождения), которую также требуется уточнить и описать в разделе типов раньше, чем запись о работнике. В описании данной записи используется тип «день рождения» (date_oi_birth) из примера 3. Общее описание записи имеет вид: type date_of_birth = record day: 1 ..31; month: string [10]; year: integer end; worker = record name : string [ 20 ]; position: string [ 10 ]; date : date_of_birth; salary : real end; var x: array [ 1. .7] of worker; w: worker; Поле записи date содержит запись из трех полей. При формировании имени поля этой внутренней записи необходимо использовать тройное имя: имя переменной раздела var, имя поля записи worker и имя поля записи date_of_birth. Например, для переменной w обращение к месяцу рождения работника в программе будет иметь вид: w.date.month В программе ввод и вывод записи производится по полям, но можно присвоить одной записи значение другой, при этом происходит копирование области памяти: х [ 1 ]: = w; Оператор присоединения. Для обработки записи используется оператор with, который позволяет указать один раз имя записи из раздела переменных, а затем во всей области действия оператора указывать только имена полей этой записи из раздела type. После слова with можно написать несколько имен полей из раздела переменных. Оператор присоединения имеет вид: with список имен записей do оператор; Оператор бывает простым или составным, ограниченным операторными скобками. Список имен записей может состоять из одного имени. Пример. Дан массив записей, содержащий сведения о работниках 67 предприятия (пример предыдущий). Напечатать: 1) список бухгалтеров; 2) список работников от 30 до 50 лет; 3) среднюю заработную плату по предприятию. Для записей этой задачи определяются их структура, имена и типы полей. Затем определяется имя массива записей, который используется в программе, и вспомогательные переменные, а также имена результатов. Программа program Р37; const n =10; type date_of_birth = record day: 1 .. 31; month:string [ 10 ]; year: integer end; worker = record name : string [ 20 ]; position: string [ 10 ]; date : date_of_birth; salary : real end; var x: array [ 1..n] of worker; w: worker; i, j, g integer; S: real; p: string [ 10 ]; begin {формирование массива записей} for i: = 1 to n do with x [ i ] do begin writeln (‘сведения о’, i, ‘работнике’); writeln (‘фамилия, инициалы’); readln(name); writeln (‘должность’); readln(position); writeln (‘число, месяц и год рождения’); readln(date.day, date.month, date.year); writeln (‘зарплата’); readln(salary); end; {решение задачи 1) — печатание списка бухгалтеров} p: = ‘бухгалтер’; j: = 0; {счетчик строк списка — количество бухгалтеров} for i: = 1 to n do with x [ i ] do if p = position then begin j:=j+1; 68 writeln (j, ‘.’, name); {после номера в списке печатается точка и фамилия} end; {решение подзадачи 2) — список работников от 30 до 50 лет} writeln (‘список работников от 30 до 50 лет’); j: = 0; write (‘введите текущий год в виде четырехзначного числа’); readln(g); for i: = 1 to n do with x [ i ] do if (g — date.year < 50) and (g — date.year > 30) then begin j:= j+1; writeln (j, ‘.’, name) end; {решение задачи 3) — вычисление средней зарплаты} S: = 0; for i: = 1 to n do S: = S + x[ i ].salary; write (‘средняя зарплата = ‘, S / n: 10: 2) end. № 1 2 3 4 5 6 7 8 9 10 Методические указания по работе и задания Условие задачи Опишите, используя структуру записи, сведения о книгах домашней библиотеке (автор, название, год издания, количество страниц). Составить программу, определяющую: авторов, название книг которых начинается на букву А. Опишите, используя структуру записи, таблицу соревнований (название команды, количество набранных очков). Составьте программу, выводящую на экран упорядоченный список команд (в зависимости от занятого места). Составьте программу, осуществляющую приведение подобных членов многочлена с использованием структуры данных «запись» Опишите, используя структуру записи, книги (автор, название, год издания). Составить программу вывода на экран упорядоченного списка книг (по фамилии автора) Опишите, используя структуру записи, таблицу соревнований (фамилия участника, количество набранных очков). Составьте программу, выводящую на экран упорядоченный список фамилий (в зависимости от занятого места). Опишите, используя структуру записи, экзаменационную ведомость в которой проставлены оценки за четыре экзамена. Составить программу выводящую на экран количество студентов несдавших экзамены, сдавших на 5, сдавших на 4 и5. Опишите, используя структуру записи, книги (автор, название, год издания, номер шкафа). Составить программу вывода на экран упорядоченного списка книг (по фамилии автора в каждом шкафу) Запись содержит информацию о дневной температуре (число, месяц, температура). Составить программу вычисляющую среднемесячную температуру. Опишите используя структуру записи, сведения о товаре ( наименование, цена, количество). Составить программу определяющую самый дорогой и самый дешевый товар. Опишите объект «работник предприятия», используя запись 69 11 12 13 14 15 Опишите используя структуру записи, сведения о товаре ( наименование, цена, количество). Составить программу определяющую на какую сумму имеется товар. Опишите, используя структуру записи, сведения о книгах домашней библиотеке (автор, название, год издания, количество страниц). Составить программу, определяющую: авторов, название книг изданных после 1995г. Опишите, используя структуру записи, данные о владельце автомобиля (фамилия, марка автомобиля, гос. номер, цвет). Составьте программу, осуществляющую поиск владельца автомобиля «Жигули» белого цвета с фиксированным гос. номером. Опишите объект «ученик 11 класса», используя запись Создайте базу данных для своего класса и с ее помощью получите сведения о самом старшем ученике в классе; б) о самом младшем ученике; в) об оценках каждого ученика по изучаемым в классе предметам; г) об отличниках; д) о самом отстающем ученике; е) о среднем балле каждого ученика по оценкам последней четверти; ж) о средней успеваемости класса по всем предметам; з) о тех, кто пропускает уроки чаще, чем раз в неделю. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Как в информатике понимается слово «запись»? 2. Как обратиться в программе к полю записи? 3. Что необходимо сделать, чтобы описать в программе объект, характеристики которого — разнотипные данные? 4. Что необходимо сделать, чтобы описать в программе объект, характеристики которого — однотипные данные? 5. Объясните, что означают имена: х[ 2 ].position, x[ 5 ].date.month, w.name. 6. Для чего используется оператор with? Лабораторная работа №13 ФАЙЛЫ. РАБОТА С ФАЙЛАМИ В ПАСКАЛЕ Цель работы: научиться читать данные из файла, выводить данные в файл, приобрести навыки работы со стандартными процедурами и функциями для всех файлов. Краткие теоретические сведения. С понятием файла пользователь компьютера сталкивается постоянно. Язык программирования Паскаль позволяет работать с компонентами файла — записями, с полями записей. Файл в Паскале состоит из однотипных данных. С данными файла можно производить две операции: запись или чтение. В Паскале осуществляется обработка последовательных файлов, в которых данные записываются или считываются одно за другим. Запись можно прочесть, минуя предыдущие, если известен ее порядковый номер в файле. Чтобы выполнять действия с данными файла, файл надо открыть для соот- 70 ветствующей операции. Этапы, которые необходимы для каждой операции при работе с файлом: Операция записи. Запись в файл означает помещение в него новых данных. Файл размещается на носителе, как правило, на магнитном диске. Данное для занесения в файл формируется в оперативной памяти как значение некоторой переменной. Операцией записи в файл это данное копируется из оперативной памяти во внешнюю. Форма представления данного, его тип и структура должны быть одинаковы и для записей файла, и для переменной, из которой это данное копируется. 1. Описание файла. Описание файла может быть в разделе типов или в разделе переменных. Пусть файл f состоит из целых чисел. Его описание имеет вид: var f: file of integer; a: integer; где a — компонента файла данного того же типа, что и записи файла. Тип данных файла указывается после слова of в описании, это может быть числовой или символьный тип, массив или запись. Сложный тип записи файла необходимо предварительно описать в разделе type. 2. Установление соответствия между логическим и физическим именами файла. Логическое имя — имя переменной из раздела var, под которым файл присутствует в программе. Физическое имя — имя из каталога оглавления диска. Оператор установления соответствия между именами файлов: assign (логическое имя файла, физическое имя); например: assign (f, ‘F.DAT’); Физическое имя заключено в апострофы, оно появится в том же оглавлении, где находится файл turbo.exe. 3. Открытие файла для операции запись это действие выполняется оператором: rewrite (f); Для занесения в файл данных при его открытии на диске появляются две специальные записи: начало файла, содержащее физическое имя, и признак конца файла. Каждое открытие файла для записи означает создание файла. Если для операции запись открыть файл с уже имеющимися данными, то все данные файла пропадут. Поэтому открывать для записи можно только файлы с новыми именами (физическими). При занесении в файл данные будут размещаться между именем и признаком конца файла, причем каждое новое данное окажется перед признаком конца файла. Файл может содержать произвольное количество данных. Ограничение размера файла никак в программе не оговаривается. В оперативной памяти достаточно одной области, совпадающей по формату с записями файла, а на диске определяется размер файла свободным пространством на момент его создания. Запись данных в файл производит оператор: write (f, a); Пример. Пусть требуется создать файл из 10 целых чисел. Программа имеет вид: program Р38; var f: file of integer; a, i: integer; begin 71 assign (f, ‘F.DAT’); rewrite (f); writeln (‘введите 10 целых чисел, после каждого нажимайте <Enter> ‘); for i: = 1 to 10 do begin readln(a); write (f, a) end end. Если создать файл и никаких больше действий не производить, то возможности просмотреть данные файлы вне программы, практически нет. Поэтому большинство задач обработки файлов начинаются словами: «Дан файл». Очевидно, как и для других задач с подобным началом, файл необходимо сначала создать, т. е. выполнить описанные четыре этапа. Чтобы работать с данными файла, их надо прежде всего прочесть, открыть файл для чтения. Операция чтения. Для чтения данных из файла его следует описать, установить соответствие между логическим и физическим именем, а затем открыть для чтения и считывать данные. Первые два шага — описание и установление соответствия имен — такие же, как и для операции записи. Если с файлом совершаются различные операции, то перед выполнением следующей его надо закрыть оператором: close (f); Открытие файла для чтения производится оператором: reset (f); Читать данные из файла позволяет оператор: read (f, a); После создания файла и нескольких преобразований может быть неизвестно количество его записей. Поэтому при чтении данных из файла удобно использовать специальную функцию, контролирующую признак конца файла. Эта функция принимает значение истина, если встречен признак конца файла, и ложь, если прочитана другая запись. При открытии файла для чтения уже считывается первая его запись, содержащая имя файла, поэтому можно поставить контроль признака конца файла, даже не считав ни одной записи оператором read (f,a); Функция обработка признака конца файла: eof (f) Поскольку количество записей в файле неизвестно, использовать при чтении данных файла цикл-пересчет нельзя. Поэтому применяется цикл-пока. Его заголовок while not eof (f) do надо понимать так: пока не встретился признак конца файла, выполнять цикл. Пример. Дан файл целых чисел. Посчитать положительных, отрицательных и нулевых элементов файла. program Р39; const k= 15; var f: file of integer; a, i, n, p, z: integer; begin 72 количество assign (f, ‘F.DAT’); rewrite (f); {создание файла} writeln (‘введите’, k, ‘целых чисел, после каждого нажимайте <Enter>‘); for i: = 1 to k do begin readln(a); write (f, a) end; close (f); {закрытие файла для операции записи} {решение задачи — подсчет различных элементов} n: = 0; p: = 0; z: = 0; {n-отрицательные, р-положительные, z -нули} reset (f); while not eof (f) do begin read (f, a); if a = 0 then z: = z + 1; if a < 0 then n: = n + 1; if a > 0 then p: = p + 1 end; write (‘ n = ‘, n, ‘ z = ‘, z, ‘ p = ‘, p) end. Пример. Пусть требуется расширить данный файл, добавив в него новые данные. Как известно, файл с данными нельзя открывать для записи, поэтому для решения подобных задач необходимо использовать вспомогательный файл. Решение задачи расширения файла складывается из следующих этапов: 1) открыть данный файл f для чтения, а вспомогательный g — для записи; 2) читать данное из исходного файла f и записывать его тут же в файл g; 3) после окончания переписывания данных закрыть файл f; 4) вводить новые данные с клавиатуры и записывать их в файл g, добавляя к уже имеющимся там данным файла f; 5) закрыть файл g; 6) открыть файл f для записи, а файл g — для чтения; 7) читать данные из файла g и записывать их в файл f. Таким образом, в файле f к старым данным добавятся новые. Если необходимо вставить новые данные в середину файла, то надо во втором пункте решения контролировать считываемые данные и, дойдя до места вставки, приостановить чтение, записать требуемые данные в файл g, а затем дописать туда оставшиеся из исходного файла (пункты 3 и 4), далее выполнить пункты 5, 6, 7. program Р40; var f, g: file of integer; a: integer; begin assign (f, ‘F.DAT’); 73 assign (g, ‘G.DAT’); . {перезапись данных из исходного файла во вспомогательный} reset (f); rewrite (g); while not eof (f) do begin read (f, a); write (g, a); end; close (f); {добавление данных во вспомогательный файл} readln(a); while а <> 0 do {признак окончания ввода новых данных - нуль} begin write (g, a); readln (a) end; close (g); reset (g); rewrite (f); {перезапись данных назад в исходный файл} while not eof (g) do begin read (g, a); write (f, a); end end. Методические указания по работе и задания № Условие задачи 1 Вывести на экран содержимое файла a:\ num.txt. 2 Дан файл, элементами которого являются целые числа. Вычислить среднее арифметическое чисел, находящихся в файле. 3 Требуется создать файл целых чисел, в котором значение каждой i-й компоненты равно i2 и квадраты всех чисел не превосходят n. 4 Имеется два отсортированных файла целых чисел. Осуществить слияние файлов в отсортированный третий файл. 5 Для целочисленного файла найдите наибольший элемент данных. 6 Пусть внешний файл состоит из записей, содержащих фамилии владельцев и номера их телефонов. Необходимо по фамилии знакомого отыскать его телефон. 7 Написать программу, копирующую файл. 8 Составить программу подсчета количества элементов файла вещественных чисел, меньших среднего арифметического всех элементов этого файла. 74 9 Написать программу, меняющую местами первый и последний элементы файла. 10 Вывести текстовый файл на экран и подсчитать количество строк в данном текстовом файле. 11 Создать файл вещественных чисел и вычислите сумму компонент этого файла. 12 Считать файл, удвоив каждый его элемент через пробел. 13 Прочитать текстовый файл и найти сумму цифр, встречающихся в нем. 14 Для файла целых чисел перепишите положительные в один дополнительный файл, а отрицательные — в другой. 15 Прочитать текстовый файл и вывести его задом наперед. ВОПРОСЫ К ЗАЩИТЕ ЛАБОРАТОРНОЙ РАБОТЫ 1. Какие операции можно производить с данными файла? 2. Почему второй параметр а операторов write (f, а) и read (f, a) должен быть такого же типа, что и данные файла? 3. Что такое физическое имя файла, чем оно отличается от логического имени? 4. Как открыть файл для записи? 5. Что будет, если ранее созданный файл с данными открыть для записи? 6. Чем ограничено количество данных в файле? 7. Чем отличается файл от массива? 8. Как прочесть данные из файла, не зная количества этих данных? 9. Как добавить данные в имеющийся файл? 10. Какой файл, созданный программой, можно просмотреть при помощи текстового редактора? ЛИТЕРАТУРА 1. 2. 3. 4. 5. 6. Е. А. Зуев. Turbo Pasсal. Практическое программирование. – М.: «ПРИОР», 1997.336с. Емелина Е.И. Основы программирования на языке Паскаль.- М.: Финансы и статистика, 1997.-208с.: ил. Н. Культин. Turbo Pasсal 7.0. –СПб.: БХВ – Санкт-Петербург,1998.336с., ил. Гусева А.И. Учимся программировать Pasсal 7.0. Задачи и методы их решения. – М.: «Диалог-МИФИ», 1998. 272с. Рудаков П.И., Федотов М.А. Основы языка Pascal.-М.: Радио и связь, Горячая линия.- Телеком,1999,208с.:ил. Информатика Задачник – практикум в 2т. / Под ред. И.Г. Семакина, Е.К. Хеннера: - М.: Лаборатория базовых знаний,2000г. –304с.:ил. 75 76