Выводы по проделанной работе. Привести выводы по результатам выполненной лабораторной работы. Выводы – это краткое отражение наиболее значимых результатов выполненной работы. Для лабораторных работ допускаются выводы, совпадающие с основными положениями, приведенными в пункте «Цель работы». 1.12. Контрольные вопросы 1) Каков порядок создания программы в ИСР Turbo Pascal? 2) Какие основные функции выполняет ИСР Turbo Pascal? 3) Какие операции позволяет выполнять текстовый редактор Turbo Pascal при подготовке программы? 4) Как запустить программу, разработанную в ИСР Turbo Pascal? 5) Как сохранить программу под другим именем? 6) Как открыть новое окно редактирования? 7) Какими способами можно выйти из среды? 8) Как вызвать контекстную помощь? 9) Какова структура Pascal-программы? 10) Какие операторы используются для ввода и вывода значений переменных? 11) Какие действия выполняют операторы Write и Writeln? 12) Какие действия выполняют операторы Read и Readln? 13) Каким образом можно объявить переменную в языке Pascal? Лабораторная работа №2. Разработка программы с разветвленной структурой 2.1. Цель работы Приобретение навыков разработки программ разветвленной структуры на языке Pascal с использованием операторов условного перехода IF, выбора CASE и безусловного перехода GOTO. Получение навыков использования встроенного отладчика. 2.2. Задание на лабораторную работу 1. Освоить основные функции встроенного отладчика интегрированной среды Turbo Pascal (п. 2.5). 2. Разработать программу с разветвленной структурой в соответствии с предложенным вариантом. Ввод данных, вычисления и вывод результатов организовать в диалоговом режиме с использованием оператора CASE (п. 2.7). 2.3. Требования к программе Программа должна выполнять следующие действия: – вывод номера варианта и сообщения о назначении программы; – вывод фамилии и инициалов автора программы; – вывод меню; – ввод данных; – вычисления и вывод результатов. Результаты работы выводятся в отформатированном виде (с указанием количества знаков после десятичной точки). 2.4. Порядок выполнения работы 1. Получить вариант задания (п. 2.8). 2. Изучить основные функции отладчика Turbo Pascal (п. 2.5). 3. Подготовить текст программы и выполнить ее отладку с использованием интегрированной среды Turbo Pascal (п. 2.5, 2.6, 2.7). 4. Во время отладки использовать не менее двух контрольных точек останова (п. 2.5). Проверить работу программы при различных значениях исходных данных. 5. Ответить на контрольные вопросы (п. 2.10). 6. Оформить отчёт (п. 1.11). 2.5. Отладка программы с использованием встроенного отладчика Turbo Pascal Очень часто при разработке программ возникает ситуация, при которой программа компилируется и запускается без ошибок, но в дальнейшем она выдает совершенно другой результат, нежели от нее ожидал программист. Это свидетельствует о том, что программист допустил логическую ошибку. Примеры логических ошибок: – вместо Readln(N) написано Writeln(N); – вместо R := A * B написано A := R * B; – пропущен оператор или выражение; – и т.д. Перечень всех возможных логических ошибок, которые может совершить программист, является бесконечным. Ошибка может быть допущена где угодно! В большинстве случаев для исправления подобных ошибок достаточно просмотреть код программы и найти строку, в которой содержится ошибка. В тех ситуациях, когда программист подобным способом не может исправить допущенную ошибку, выручает отладчик. В состав интегрированной среды Turbo Pascal входит встроенный отладчик (debugger), обеспечивающий следующие возможности: – построчная отладка (трассировка) текста программы с возможностью просмотра и изменения значения любой переменной (или выражения); – автоматическое приостановление работы программы (с возможностью просмотра значений переменных или выражений) при достижении точки останова (breakpoint), либо строки, на которой установлен курсор; – наблюдение за переменными и выражениями, включенными в список «Watches»; – доступ к регистрам микропроцессора; – просмотр цепочки вызова подпрограмм (call stack). Для начального изучения основ работы с отладчиком выполните следующие шаги: 1) Набрать простую программу, например: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: | program DebugTest; var A, B, R: Integer; begin Write('Введите A, B: '); Readln(A, B); R := A + B; R := R * A; Writeln('Результат: ', R); end. | В данной программе объявлены 3 целочисленные переменные A, B, R. Вначале программа печатает на экране подсказку «Введите А, В: », затем от пользователя требуется ввести 2 числа, которые будут записаны соответственно в переменные A и B. Далее программа складывает оба этих числа, и полученный результат присваивает в переменную R. В следующей строке (№8) содержится оператор R := R * A, при этом сначала переменная R умножается на переменную A, после этого результат умножения присваивается опять в ту же самую переменную R. Таким образом, переменная R используется в данном примере несколько раз. В программировании повторное использование одних и тех же переменных встречается очень часто. 2) Для запуска программы под отладчиком следует щелкнуть клавишу F7 (меню Run \ Trace Into) или F8 (меню Run \ Step over). При отладке данного примера различия между F7 и F8 отсутствуют, однако если программа содержит процедуры или функции (см. лабораторную работу №5), созданные программистом, то F7 позволит попасть внутрь процедуры для ее отладки. В дальнейшем изложении будет упоминаться только клавиша F7. В результате нажатия клавиши F7 строка №4 (begin) окажется выделенной зеленым цветом, что свидетельствует об успешном запуске сеанса отладки. 3) Щелкнуть клавишу F7 еще раз – будет выделена строка №5 (Write…). Это означает, что при очередном нажатии F7 будет выполнен оператор, расположенный на выделенной строке. 4) Щелкнуть F7. В результате оператор Write будет выполнен, а дальнейшее управление перейдет к строке №6 (Readln). 5) Щелкнуть F7. Произойдет переключение в режим текстового ввода и программа будет ожидать от пользователя ввода двух чисел через пробел. После нажатия Enter в переменные A и B будут записаны числовые значения, которые ввел пользователь, а дальнейшее управление перейдет к строке №7 (R := A + B). 6) На данном этапе с помощью отладчика можно проверить, действительно ли переменные A и B содержат значения, введенные пользователем. Для этого следует установить курсор под переменной A, затем выбрать меню Debug \ Evaluate/modify (определить значение / изменить) или щелкнуть Ctrl+F4. Откроется окно «Evaluate and modify», в котором указано текущее значение переменной A (рисунок 2.1)  Рисунок 2.1 – Окно «Evaluate and modify» В поле Expression можно указать имя переменной, но при необходимости можно ввести целое математическое выражение, например: (A * B) / (A + B). После нажатия кнопки «Evaluate» заданное выражение будет вычислено, а результат появится в строке «Result». При необходимости (в отладочных целях) в данном окне можно изменить значение указанной переменной. Для этого в строке «New value» следует ввести новое значение и нажать Modify. 7) Щелкнуть F7. В результате выражение в строке №7 будет вычислено, а результат записан в переменную R. Для просмотра вычисленного значения переменной R следует установить на нее курсор и нажать Ctrl+F4. 8) В некоторых случаях отладка упрощается, если программист всегда видит на экране значение заданного выражения (без необходимости постоянного нажатия Ctrl+F4). Для этого следует установить курсор на переменную R, щелкнуть меню Debug \ Add watch (Ctrl+F7) и нажать ОК. В результате в нижней части окна Turbo Pascal появится окно «Watches», в котором присутствует наименование переменной и ее значение, вычисленное автоматически (рисунок 2.2). При необходимости в список «Watches» можно добавить произвольное количество переменных или выражений.  Рисунок 2.2 – Окно «Watches» 9) Нажать F7 и убедиться в том, что значения заданных переменных в окне «Watch» обновляются автоматически. 10) Прервать отладку программы можно в любой момент с помощью меню Run \ Program Reset (Ctrl+F2). 11) Очень часто к трассировке программы требуется приступить не с момента ее запуска, а только при достижении определенной строки, подозреваемой в наличии ошибки. Для этого на заданную строку следует поместить точку останова. Разместите курсор на строке №8 (R := R * A), щелкните по ней правой кнопкой мыши и выберите пункт Toggle Breakpoint или нажмите Ctrl+F8. В результате строка будет выделена красным цветом, что свидетельствует о наличии точки останова (повторное нажатие Ctrl+F8 позволяет снять точку останова). 12) Запустить программу с помощью меню Run \ Run (Ctrl+F9), ввести два числовых значения через пробел и нажать Enter. В результате управление перейдет к строке, на которую установлена точка останова (теперь она будет окрашена зеленым цветом), а Turbo Pascal перейдет в режим отладки программы, в котором доступны все ранее описанные действия. 13) При необходимости к отлаживаемой программе можно добавить несколько точек останова (например, при отладке программы с разветвляющейся структурой, переход в ту или иную ветвь которой может произойти при выполнении или невыполнении некоторого условия). Для просмотра списка всех точек останова следует выбрать меню Debug \ Breakpoints. С помощью данного окна можно изменить (Edit) параметры точек останова (критерии срабатывания точки останова, например количество проходов через нее или выполнение заданного условия), быстро перейти к строке исходного кода (View), удалить выбранную точку останова (Delete), либо удалить все точки останова (Clear all). 14) Если в программе планируется использование всего одной точки останова, то в качестве более простой альтернативы можно использовать команду выполнения программы до выделенной строки. Для этого установите курсор на строке №9 (Write) и выберите меню Run \ Go to cursor (F4). В результате Turbo Pascal перейдет в режим отладки, в котором можно совершать все действия, упомянутые ранее. 2.6. Справочная информация по операторам ветвления языка Pascal 2.6.1. Оператор IF При разработке любой программы необходим механизм, позволяющий выполнить тот или иной участок программного кода, основываясь на некотором условии. Для реализации такого рода алгоритмов в Pascal предусмотрен оператор ветвления IF. Основная форма вызова данного оператора: if <условие> then <оператор>; <остальные операторы программы> Принцип действия данного оператора следующий: осуществляется проверка заданного условия. В том случае, если условие выполняется (дает результат «ИСТИНА», т.е. «TRUE»), то осуществляется переход к оператору, расположенному справа от THEN. После окончания работы этого оператора управление переходит к остальным операторам программы, которые расположены после символа «;». Если же условие не выполняется, то оператор, расположенный справа от THEN, пропускается и управление сразу переходит к остальным операторам. Очень часто, в случае выполнения заданного условия, требуется выполнить не один, а сразу несколько операторов. В этом случае эти несколько операторов следует разместить внутри операторных скобок BEGIN..END. Внимание! В программе может находиться несколько участков кода, размещенных внутри BEGIN..END, причем эти участки могут быть вложенными. Самый внешний BEGIN..END определяет начало и окончание программы, а остальные BEGIN..END выполняют роль операторных скобок. Следует учитывать, что если некоторый набор операторов, состоящий из нескольких строк, находится внутри операторных скобок BEGIN..END, то всю конструкцию (с точки зрения оператора IF) следует рассматривать как «составной оператор»: if A = B then Begin <оператор 1>; <оператор 2>; ... <оператор N> end; Условие – это любое выражение, результатом которого является логическое (Boolean) значение: True или False (Да или Нет). При составлении условия можно использовать операторы сравнения: «=» – равно | «<>» – не равно | «>» – больше | «<» – меньше | «>=» – больше или равно | «<=» – меньше или равно | Операция (A = B) вернет True в том случае, если переменные A и B равны между собой; в противном случае вернет False; Операция (A <> B) вернет True только в том случае, если переменные A и B не равны между собой. Операция (A > B) вернет True в том случае, если переменная A имеет значение большее, чем значение переменной B. Операция (A >= B) вернет True в том случае, если переменная A равна переменной B, либо имеет значение большее, чем у переменной B. Кроме того, операции сравнения, возвращающие значения True или False можно комбинировать между собой с использованием логических операций: «and» – логическое И | «or» – логическое ИЛИ | «not» – логическое НЕ | «xor» – исключающее ИЛИ | Выражение ((A < -1) or (A > 1)) вернет True, если значение переменной A меньше -1 или больше 1, т.е. оно не лежит в диапазоне [-1 ÷ 1]. Выражение ((A = B) and (A > C * C)) вернет True, если переменные A и B равны между собой и в то же время значение переменной A превышает значение переменной C, взятое в квадрате. Если не будет выполнено хотя бы одно из условий, то выражение вернет False. Операция «not» инвертирует результат логического выражения, указанного справа, т.е. (not True) вернет False, а (not False) вернет True. Выражение (not (A = B)) вернет True в том случае, если A не равно B. Операция «xor» вернет True в том случае, одно из выражений дает True, а другое False. Например, выражение ((100 > 50) xor (29 = 30)) вернет True, поскольку одно из сравнений (100 > 50) дает True, а другое (29 = 30) – False. Внимание! Программа на языке Pascal всегда должна иметь наименование, указанное после ключевого слова PROGRAM, секцию VAR с объявленными переменными и внешние операторные скобки BEGIN..END, в которых должны располагаться все необходимые операторы. Для краткости изложения материала эти ключевые слова в некоторых дальнейших примерах пропущены! Также пропущен код, осуществляющий присвоение значения некоторым переменным. Ниже представлен один из таких примеров. В нем осуществляется ввод числа A; если введенное число отрицательное, то его значение заменяется на ноль. Readln(A); {ввод числа A} if A < 0 then A := 0; {заменяем на 0, если число отрицательное} Writeln('A: ', A); {выводим на экран значение переменной A} В примере ниже осуществляется проверка делителя на 0. При равенстве нулю выдается сообщение об ошибке и происходит выход из программы. program Delenie; Var Delimoe, Delitel, Res: Real; Begin Delimoe := 100; Readln(Delitel); {ввод значения делителя} if Delitel = 0 then {проверка на равенство нулю} begin {начало составного оператора} Writeln('Ошибка: на ноль делить нельзя!'); Exit; {досрочный выход из программы} end; {составной оператор закончился} Res := Delimoe / Delitel; {осуществляем деление} Writeln('Результат: ', Res); {вывод результата на экран} end. Очень часто возникает необходимость отреагировать не только на выполнение условия, но и на его невыполнение. Для этого к конструкции IF..THEN добавляется ключевое слово ELSE, определяющее начало альтернативной ветви выполнения программного кода. В этом случае конструкция IF..THEN выглядит следующим образом: if <условие> then <оператор1> else <оператор2>; | if <условие> then begin <группа операторов 1>; end else begin <группа операторов 2>; end; | Следует отметить, что перед ключевым словом ELSE не должна стоять точка с запятой. На рисунке 2.3 приведен пример схемы разветвляющегося алгоритма для двух форм оператора IF..THEN: с ключевым словом ELSE и без него. Рисунок 2.3 – Схема алгоритма с оператором if…then с else (слева) и без else (справа) В представленном ниже примере осуществляется поиск наибольшего значения среди X и Y и сохранение найденного значения в переменную Max: if X > Y then Max := X else Max := Y; Write('Максимум: ', Max); | if X >= Y then begin Max := X; Write('X больше или равен Y'); end else begin Max := Y; Write('Y больше X'); end; Write('Максимум: ', Max); | Кроме того, оператор IF..THEN может быть вложенным, причем уровень вложенности не ограничивается, например: if X < -3 then Y := X + 1 else if (X > 3) and (X < 10) then Y := X * X else if X >= 10 then Begin Y := Sqrt(X); Writeln('Y: ', Y); End Else Y := Y * Y; Следует отметить, что подобные конструкции на практике могут быть весьма громоздкими. Для улучшения читабельности кода рекомендуется чаще пользоваться операторными скобками BEGIN..END с необходимым выравниванием. Важно помнить, что ключевое слово ELSE относится только к одному, ближайшему оператору IF..THEN, расположенному выше по коду. 2.6.2. Константы Перед тем, как познакомиться с оператором CASE, необходимо дать определение понятию «константа». Константой в языке Pascal является некоторое значение (например, числовое), заданное непосредственно в тексте программы (т.е. пользователь вашей программы его не вводит). Например, в операторе «A := 100» переменной A присваивается явно заданное значение «100», т.е. константа. В языке Pascal различают два вида констант: именованные и неименованные. Для того чтобы константа была именованной, ее необходимо указать в секции CONST в разделе описаний программы: сначала указывается имя константы, затем символ «=», далее указывается необходимое значение, например: program ConstExample; Const MinLimit = 1; {Минимальный лимит} MaxLimit = 100; {Максимальный лимит} Pi = 3.14; {Число Пи} ....... Begin A := MaxLimit; {Это более осмысленно, чем A := 100} if B < MinLimit then... ....... end; После того, как константа объявлена, ее имя можно использовать в программе вместо числового значения, например «A := MaxLimit». В некоторых случаях это позволяет улучшить читабельность программы, а также упростить ее дальнейшую разработку. Значение именованной константы невозможно изменить при выполнении программы (в отличие от переменной). В данной лабораторной работе рекомендуется использовать константы для обозначения постоянных параметров, которые не требуется вводить пользователю вашей программы. Например, стоимость 1 кВт/час является величиной постоянной, поэтому вы можете ее объявить с помощью именованной константы: Const KiloWattCost = 3.45; {Стоимость 1 кВт/час } 2.6.3. Оператор выбора CASE В том случае, если задана некоторая переменная порядкового типа (целочисленная, логическая или символьная) и на каждое возможное ее значение программа должна отреагировать индивидуально, рекомендуется использовать оператор выбора CASE. Логика работы оператора CASE аналогична логике IF..THEN, однако, использование оператора CASE в некоторых случаях позволяет значительно улучшить читабельность кода. Оператор CASE имеет следующий формат: case <переменная или выражение порядкового типа> of <константа или список констант 1> : <оператор 1>; <константа или список констант 2> : <оператор 2>; ····························· <константа или список констант n> : <оператор N>; Else <альтернативная ветвь: оператор или группа операторов> end; Логика работы оператора CASE следующая: сначала программа определяет значение переменной или выражения порядкового типа (например, целочисленное). Далее отыскивается константа, совпадающая с указанным значением, после чего выполняется оператор, расположенный после символа «:». Если программе не удалось найти константу, совпадающую с заданным значением, то выполняется оператор из альтернативной ветви, расположенной после ключевого слова ELSE. Ключевое слово ELSE не является обязательным (его следует указывать, когда в этом возникает необходимость). В приведенном ниже примере пользователь вводит степень числа N от 1 до 3. Программа возводит переменную X в степень N. Отдельно обрабатывается случай, когда N равен нулю. Во всех остальных случаях устанавливается значение 0. Write('Введите значение n: '); Readln(n); {ожидаем, когда пользователь введет n} case n of 0: {демонстрация использования операторных скобок begin...end} Begin Writeln('Сообщение: любое число в степени 0 равно единице!'); Y := 1; end; 1: Y := X; 2: Y := X * X; 3: Y := X * X * X; else {альтернативная ветвь кода} {здесь дополнительный begin...end не требуется} Writeln('Вы ввели недопустимое число!'); Y := 0; end; {конец оператора case} Writeln('Результат: ', Y); {вывод результата на экран} Кроме одиночных констант могут быть заданы списки и/или диапазоны значений. Например: case n of 0, 2..4 : Y := A * B; {оператор будет выполнен для n: 0, 2, 3, 4} 1, 5 : Y := A / B; 6 : Y := (A + B) * (A - B); end; Следует отметить, что при использовании оператора CASE действует ряд ограничений: – значения констант не должны дублироваться; это ограничение действует также при использовании диапазонов; – тип констант должен соответствовать типу заданной переменной; если переменная целочисленная, то и все константы должны быть целыми; – заданная переменная должна иметь порядковый тип (например, Integer, Byte, Char, Boolean); она не может быть объявлена как Real (дробный тип) или string (строка). 2.6.4. Оператор GOTO Оператор безусловного перехода GOTO (англ.: перейти к) позволяет прервать выполнение текущего участка кода и перейти к другому участку, если он отмечен меткой безусловного перехода. Метка безусловного перехода объявляется в разделе LABEL и должна соответствовать требованиям, предъявляемым к идентификаторам (в порядке исключения допускается вместо наименования метки использовать целочисленные значения). После объявления метки в разделе LABEL ее можно указать в любом месте (но только один раз) в тексте программы. Для того чтобы перейти на заданную метку, следует вызвать оператор GOTO <имя_метки>, причем количество операторов перехода на одну и ту же метку в программе не ограничено: ····························· goto M1; {переходит вниз на метку M1} <операторы>; M1: <операторы>; ····························· goto M1; {переходит вверх на метку M1} | ····························· label M1; var X, Y: Real; begin Readln(X); ····························· goto M1; ····························· M1: Y := X * 2 – 3 / X; Writeln('Y=', Y); ····························· end. | Следует отметить, что в современном программировании использование оператора GOTO не приветствуется, поскольку злоупотребление данным оператора приводит к сильному «запутыванию» кода. Для избежания использования оператора GOTO следует применять другие методы, например циклы и подпрограммы (см. следующие лабораторные работы). 2.7. Пример программы с разветвленной структурой Составить программу вычисления функции:  program Lab2; Label M1, M2; {объявление меток} Var n: Integer; X, Y: Real; Flag: Boolean; {Признак выполнения пункта N1} Begin Writeln('Программа вычисления функции. Автор: Иванов И.И.'); { Вывод на экран меню } Writeln('Введите цифру для выполнения действия:'); Writeln('1 - Ввод данных'); Writeln('2 - Вычисление функции и вывод результатов'); Writeln('3 - Завершение работы программы'); Flag := False; { Первоначальная инициализация флага } M1: Write('Введите номер пункта меню: '); Readln(n); { Ввод номера пункта меню} case n of 1: { Ввод данных } Begin M2: Write('Введите значение аргумента X: '); Readln(X); { Проверка допустимости значения аргумента } if X = 0 then Begin Writeln('X не может быть равным 0 по условию'); goto M2; { переход к M2 для повторного ввода данных } end; Flag := True; {Пункт №1 выполнен, установка флага в True} end; 2: { Вычисление значения функции } Begin if not Flagthen{Если пункт №1 не выполнен} Writeln ('Данные не введены, выполните пункт №1'); Else begin {пункт №1 был выполнен} { Операторы вычисления и вывода значения функции } if X > 0 then {если Х положительный} Y := 1 / X else{иначе Х < 0} Y := X * X; Writeln('При X = ', X:7:2, ' Y = ', Y:7:2); end; end; 3: Exit; { Выход из программы } end; { end case } goto M1; { переход в режим выбора пункта меню } end. { Конец программы} Данный пример требует пояснения. Программа начинается с объявления меток безусловного перехода (M1, M2) и объявления переменных, в том числе логической однобайтной переменной Flag: Boolean. Как ранее было сказано, логическая переменная может иметь всего два значения: True или False. В начале работы программы переменной Flag присваивается значение False. Это необходимо, поскольку если не выполнить этого присвоения, то в начале работы программы значение переменной Flag не определено, т.е. она случайным образом может быть равна False или True. Следует обратить внимание, что для пункта №2 оператора CASE осуществляется проверка переменной Flag (if not Flag then …), а поскольку осуществляется обращение к переменной в режиме чтения, то значение переменной обязательно должно быть присвоено заранее. В приведенном примере проверка (if not Flag then …) будет препятствовать выполнению операторов вычисления до тех пор, пока пользователь в пункте №1 не введет допустимое значение аргумента X (Flag в этом случае будет выставлен в True). Обратите внимание на выравнивание операторов в приведенных примерах! Очень легко поддается пониманию программа, в которой все операторы выровнены надлежащим образом. Представьте, что в предыдущем примере не было произведено выравнивание операторов, например: case n of 1:........ 2: Begin if not Flagthen Writeln ('Данные не введены, выполните пункт №1'); Else Begin if X > 0 then Y := 1 / X Else Y := X * X; Writeln('При X = ', X:7:2, ' Y = ', Y:7:2); end; end; 3: Exit; end; В таком виде разобраться с данным примером практически невозможно. Выравнивание должно быть выполнено таким образом, чтобы вложенные группы операторов имели отступ вправо относительно внешних операторов (рекомендуется 2 пробела). Помните, что каждый BEGIN должен иметь завершающий END, причем их следует располагать на одной вертикальной линии. Все, что находится внутри операторных скобок BEGIN..END, должно смещаться вправо. 2.8. Варианты заданий 1) Вычислить объем параллелепипеда со сторонами A, B, C и определить, является ли данное геометрическое тело кубом. 2) Вычислить площадь треугольника со сторонами А, В, С. Перед вычислением площади проверить условие существования треугольника с заданными сторонами. 3) Вычислить площадь треугольника со сторонами A, B, C. Определить, является ли треугольник равнобедренным. 4) Вычислить площадь прямоугольника со сторонами A и B и определить, является ли данная фигура квадратом. 5) Составить программу нахождения корней квадратного уравнения у=ах2+bх+с. 6) Определить, можно ли сделать круглую заготовку с заданным радиусом R из квадратного листа фанеры с заданной стороной A. 7) Определить, хватит ли имеющейся суммы S на покупку N-го количества товара (при известной цене товара). 8) Определить, можно ли сделать две квадратных заготовки со стороной А из листа железа прямоугольной формы со сторонами В и С. 9) Определить, достаточно ли имеющейся ткани для изготовления изделий двух видов, если известны: расход ткани на каждое изделие, количество изделий каждого вида, количество имеющейся ткани. 10) Рассчитать сумму оплаты за потребленную энергию, если известны: стоимость 1 квт/час, расход энергии, коэффициент льгот (льготы могут отсутствовать). 11) Определить, достаточно ли бензина для поездки, если известны: длина пути, количество бензина в баке и расход бензина на 1 км. 12) Определить, будет ли начислена студенту стипендия по результатам экзаменов (стипендия начисляется, если все экзамены сданы на «хорошо» и «отлично»), если известны оценки по всем экзаменам. 13) Определить, будет ли зачислен абитуриент в студенты по результатам вступительных экзаменов, если известны: проходной балл; количество баллов, набранных абитуриентом по каждому экзамену. 14) Определить, изделия какой из двух групп товаров выгоднее сшить из одного рулона ткани, если известны: расход ткани на каждое изделие и цена готового изделия, количество метров в рулоне. 15) Определить, выполнен ли план по продаже товара за день, если известны: план продажи (в рублях), количество проданного товара и цена товара. 16) Определить, операции с какой из двух валют составили большую прибыль, если известны: курс продажи, количество продаж по каждой валюте. 17) Определить наибольшую выручку от продажи трех видов товаров, если известны: цена товара; количество проданных товаров каждого вида. 18) Определить количество корней уравнения y=ax2+bx+c. 19) Определить, является ли число А четным или нечетным. 20) Вычислить площадь треугольника со сторонами A, B, C и определить, является ли данный треугольник равносторонним. 2.9. Содержание отчета (см. пункт 1.11) 2.10. Контрольные вопросы 1) Назначение, формы записи и порядок выполнения оператора IF. 2) Особенности использования вложенных условных операторов. 3) Каковы отличия оператора выбора CASE от оператора условия IF? 4) Какие правила должны выполняться при использовании оператора выбора CASE? 5) Назначение и особенности оператора безусловного перехода. 6) Для чего нужна отладка программы? 7) Как выполнять программу в пошаговом режиме? 8) Как поставить и как отменить точки останова? 9) Как выполнить программу «до курсора»? 10) Как открыть окно Watch? 11) Как внести переменную в окно Watch? Лабораторная работа №3. Разработка циклической программы с известным количеством повторений 3.1. Цель работы Целью работы является освоение процесса разработки циклических программ с заданным (известным) числом повторений на языке Pascal. 3.2. Задание на лабораторную работу Разработать программу с использованием оператора цикла FOR, осуществляющую следующие действия: а) Вычисление заданной величины (суммы N слагаемых, произведения N сомножителей и т.п.); б) Обработка данных с использованием двумерных массивов. 3.3. Требования к программе Программа должна выводить: – номер варианта, назначение программы и ФИО автора; – меню выбора действия программы («а» или «б»); допускается сделать две отдельные программы без меню выбора; – информационные сообщения о необходимости ввода данных; – сообщение с результатами, полученными в ходе работы программы; 3.4. Порядок выполнения работы 1) Получить вариант задания (п. 3.8). 2) Изучить принцип действия FOR при разработке циклических программ на языке Pascal (п. 3.5). 3) Составить и отладить программу вычисления заданной величины (суммы N слагаемых, произведения N сомножителей и т.п.) в соответствии с подпунктом «а» варианта задания. 4) Изучить основы работы с данными типа «массив» (ARRAY) на языке Pascal (п. 3.6). 5) Разработать и отладить программу обработки данных с использованием двумерных массивов в соответствии с подпунктом «б» варианта задания. 6) Объединить обе разработанные программы в одну с использованием меню выбора (п. 3.7). 7) Ответить на контрольные вопросы (п. 3.10). 8) Оформить отчет (см. п. 1.11) 3.5. Оператор цикла FOR Очень часто перед программистом стоит задача организовать работу программы таким образом, чтобы некоторый участок кода выполнялся многократно (с заданным количеством повторений). В языке Pascal для этой цели предусмотрен оператор FOR, имеющий 2 формы записи: 1) for I := N1 to N2 do <тело цикла>; 2) for I := N1 downto N2 do <тело цикла>; Цикл FOR работает следующим образом. Вначале программа определяет значение переменных (выражений) N1 и N2. Далее переменная цикла I (счетчик цикла) получает начальное значение N1. После этого осуществляется сравнение переменной I с конечным значением N2 и если переменная I его не превышает (для первой формы FOR) либо если I больше или равно N2 (для второй формы FOR), то выполняется «тело цикла», т.е. заданный оператор (или группа операторов в BEGIN..END). После того, как тело цикла было выполнено, управление вновь переходит к оператору FOR, переменная I получает новое значение (на единицу больше, либо на единицу меньше, чем в прошлый раз), далее осуществляется ее сравнение с N2 и принимается решение о том, следует ли еще раз выполнить тело цикла. Ниже представлены примеры для обеих форм оператора FOR. Программа осуществляет перемножение заданной переменной Num с текущим значением счетчика цикла J и выводит на экран результат вычисления выражения, порядковый номер итерации и значение счетчика цикла. var Num, J: Integer; begin Num := 3; {объявляем цикл «вверх» от 1 до 5} for J := 1 to 5 do begin {Выводим результат умножения на экран } Writeln(J, ') ', Num, '*', J, '=', Num * J); {Выполняем умножение} Num := Num * J; end; end. | Результаты: 1) 3*1=3 2) 3*2=6 3) 6*3=18 4) 18*4=72 5) 72*5=360 | var Num, J, K: Integer; begin Num := 7; K := 1; {порядковый № итерации} {объявляем цикл «вниз» от 9 до 6} for J := 9 downto 6 do begin {Выводим результат умножения на экран} Writeln(K, ') ', Num, '*', J, '=', Num * J); {Выполняем умножение} Num := Num * J; K := K + 1; {Увеличиваем порядковый номер} end; end. | Результаты: 1) 7*9=63 2) 63*8=504 3) 504*7=3528 4)3528*6=21168 | Поскольку во втором примере используется оператор FOR с downto, а переменная J (счетчик цикла) изменяет свое значение от 9 до 6, то для определения порядкового номера итерации пришлось добавлять новую переменную «K». В первом примере этого не требовалось, поскольку счетчик цикла J изменяется от 1 до 5, а эти значения соответствуют номеру итерации. Следующий пример демонстрирует использование цикла FOR для вычисления суммы (слева) и произведения (справа): const n = 5; {Количество шагов} var I: Integer; Res, X: Real; begin X := 10; {Ввод Х} Res := 0; {Обнуление Res} for I := 1 to n do Res := Res + I * (X * X); Writeln('Res = ', Res:8:2); end. | const n = 4; {Количество шагов} var I: Integer; Res, X: Real; begin X := 15; {Ввод Х} Res := 1; {Присвоение единицы} for I := 1 to n do Res := Res * (X + I * I * I); Writeln('Res = ', Res:8:2); end. | При использовании оператора FOR необходимо учитывать следующие замечания: – переменная цикла (счетчик числа), а также выражения N1 и N2 должны иметь порядковый тип. Дробный тип REAL не допускается. В большинстве случаев для объявления счетчика цикла используется тип INTEGER; – внутри тела цикла запрещено изменение переменной цикла; – значение переменной цикла является актуальным только внутри тела цикла; после завершения работы цикла значение переменной цикла является неопределенным, т.е. установленным случайным образом; – переменную цикла можно использовать повторно, например, при программировании других циклов. Следующий пример демонстрирует печать на экране участка функции косинуса Cos. При этом используются 2 цикла FOR: внешний (со счетчиком цикла I) и внутренний (со счетчиком цикла J): program Cosinus; const Pi = 3.14159; {Константа Pi} {Границы внешнего цикла в градусах} MaxGradus = 90; var I, J: Integer; Rad, Value: Real; begin {Внешний цикл по I (от -90 до +90)} for I := -MaxGradus to MaxGradus do begin {Учитываются только градусы, кратные 5} if I mod 5 = 0 then begin {Пересчет градусов в радианы} Rad := Pi * I / 180; {Вычисление косинуса. В результате Value} {будет иметь значение от 0 до 1} Value := Cos(Rad); {Внутренний (вложенный) цикл (по J)} {Печатает на экране от 1 до 20 пробелов} {Round округляет число до целого} for J := 1 to Round(Value * 20) do Write(' '); {Печать символа «*»} Writeln('*'); end; end; Readln; {ожидание нажатия ENTER} end. |  | Ниже представлены необходимые пояснения к данному примеру: 1) Переменная внешнего чикла I меняет на каждой итерации значение, начиная с –90 и заканчивая +90. Этот диапазон выбран не случайно, поскольку функция Cos будет иметь в этом диапазоне только положительные значения от 0 до 1. 2) Операция «mod» возвращает остаток от деления двух целых чисел. Условие «if I mod 5 = 0 then» будет выполнено только в том случае, если значения I кратны 5 (т.е. -90, -85, -80,…, -10, -5…0, 5, 10…, 85, 90). Таким образом, символ «*» будет печататься на экране не для каждого градуса. Это сделано для того, чтобы весь график косинуса поместился на экране. Вместо 180 символов «*» на экране печатается только 37 символов. 3) Cos – это функция, принимающая в качестве аргумента величину угла, выраженную в радианах, и возвращающая значение косинуса в диапазоне от –1 до +1. Перед вызовом функции «Cos» осуществляется преобразование градусов в радианы: Rad := Pi * I / 180. 4) В примере присутствует дополнительный цикл FOR со счетчиком J. Он расположен внутри тела другого цикла, т.е. является «вложенным» или «внутренним». Он служит для заполнения строки пробелами. В зависимости от вычисленного значения косинуса, внутренний цикл выполняется от нуля до 20 раз, т.к. переменная Value в данном примере может иметь значения от 0 до 1. 5) Для печати символа «*» используется оператор Writeln. 6) Оператор Readln, указанный в программе без скобок, приостанавливает программу до тех пор, пока пользователь не нажмет Enter. При этом никакого ввода данных не происходит. Это избавляет от необходимости нажимать Alt+F5 для просмотра результатов работы программы. Важно отметить, что наименование переменной вложенного цикла должно отличаться от переменной внешнего цикла. Глубина вложенности циклов FOR может быть любой, однако на практике не приветствуется слишком большая вложенность, поскольку ухудшается читабельность кода. В таких случаях рекомендуется использовать методы процедурного программирования. При необходимости можно досрочно прервать работу цикла. Для этого следует вызвать оператор Break. В том случае, если требуется пропустить операторы тела цикла и перейти к следующей итерации, следует вызвать оператор Continue. Не рекомендуется злоупотреблять оператором Continue, поскольку его использование ухудшает читабельность кода, тем более из любой ситуации можно выйти, не используя Continue. Оператор Break, вызванный из вложенного цикла, не прерывает работу внешнего цикла. На рисунке 3.1 представлен пример участка схемы алгоритма, соответствующего циклу с известным числом повторений.  Рисунок 3.1 – Схема алгоритма участка программы с циклом for Возведение в степень В языке Pascal отсутствует операция возведения в степень. Для возведения любого числа в целую, положительную степень вы можете использовать следующий код: {Пример демонстрирует возведение числа X в степень N} program Stepen; Var X, Res: Real; N, I: Integer; Begin {*** Ввод данных ***} Write('Введите значения X и N:'); Readln(X, N); {*** Возведение в степень ***} Res := 1; {Присваиваем начальное значение переменной Res} for I := 1 to N do{Цикл возведения в степень} Res := Res * X; {*** Вывод результата на экран ***} Writeln('X^N=', Res:5:2); end. Цикл возведения в степень целесообразно применять, если значение степени заранее неизвестно. Если требуется возвести число в квадрат или в куб, то проще поступить следующим образом: Y := X * X или Y := X * X * X. Для возведения числа «–1» в целую, положительную степень рекомендуется следующий код: if Odd(N) then{Если число нечетное... } Y := –1 else {Иначе (если число четное)... } Y := 1; Odd – это функция, возвращающая логический результат True, если аргумент является нечетным числом, иначе возвращает False. 3.6. Тип данных «массив» – объявление и использование Массив — упорядоченный набор данных для хранения множества элементов одного типа, идентифицируемых с помощью одного или нескольких индексов. Количество используемых индексов массива может быть различным. Массивы с одним индексом называют одномерными, с двумя — двумерными и т.д. Одномерный массив соответствует вектору в математике, двумерный — матрице. Массивы с числом измерений > 2 встречаются редко. Формат объявления переменных типа «массив» представлен ниже: Var <список переменных> = array[<индексы>] of <тип данных>; где <список переменных> – наименование одной или нескольких переменных (через запятую); <индексы> – описание диапазона индексов для каждого измерения массива, например: - [1..10] – соответствует одномерному массиву (вектору), первый элемент которого имеет индекс «1», а последний «10» (всего 10 элементов); - [0..4] – соответствует одномерному массиву, первый элемент которого имеет индекс «0», а последний «4» (всего 5 элементов); - [1..5, 1..4] – соответствует двухмерному массиву (матрице), состоящему из 5 строк (индексация от 1 до 5) и 4 столбцов (индексация от 1 до 4); <тип данных> – любой тип данных, известный компилятору Pascal, например, Integer, Byte, Real, Boolean, Char, string, а также типы данных, объявленные программистом. Ниже приведены примеры объявления переменных типа «массив»: {2 вектора из 10 элементов типа Integer. Индексация начинается с «1»} Vect1, Vect2: array[1..10] of Integer; {Матрица вещественных чисел 8 х 6. Индексация начинается с «0»} Matr: array[0..7, 0..5] of Real; {Список из 20 строк. Индексация начинается с «1»} StrList: array[1..20] of string; Во многих случаях более удобным является однократное объявление типа данных «массив» в начале программы (в секции type). Объявленный таким способом тип данных в дальнейшем можно использовать при описании переменных. Данный способ имеет следующие преимущества: - при необходимости внесения изменений в объявление массива достаточно это сделать в одном месте; - переменные, объявленные в секции var с использованием отдельного типа, являются совместимыми, т.е. между ними допускается операция присвоения «:=»; - при использовании в программе процедур и функций у программиста появляется возможность объявления параметров процедуры, имеющих тип «массив». Ниже представлен пример объявления нового типа данных «массив», а также переменных этого типа: Type {Объявление нового типа данных «матрица»} TMatrix = array[1..10, 1..20] of Real; Var {Объявление переменных типа TMatrix} Matrix1, Matrix2, Matrix3: TMatrix; ....................................... Для любого элемента массива можно узнать его текущее значение, а также записать новое значение. Каждый элемент массива имеет свои координаты, указать которые можно в квадратных скобках. Ниже приведены примеры чтения и записи элементов одномерного массива: {Установка нового значения 3-го элемента вектора} Vect[3] := 3.45; {Установка заданного числового значения} Vect[3] := Random; {Установка случайного значения} Readln(Vect[3]); {Значение вводится пользователем с клавиатуры} {Чтение 2-го элемента вектора} Value := Vect[2]; {Присвоение в переменную Value} Writeln(Vect[2]); {Вывод на экран} {Вычисление суммы первых трех элементов} Summa := Vect[1] + Vect[2] + Vect[3]; Ниже приведены примеры чтения и записи элементов двухмерного массива (матрицы): {Установка заданного значения элемента матрицы с координатами 4, 3} {индекс 4 – это номер строки матрицы, 3 – номер столбца матрицы} Matrix[4, 3] := 123.456; Readln(Matrix[2, 4]); {Ввод элемента (2, 4) с клавиатуры} Writeln(Matrix[I, J]); {Вывод элемента (I, J) на экран} В качестве индекса элемента массива может выступать явно указанное целое значение, либо целочисленная переменная. Чаще всего обработка элементов массива выполняется в цикле, поэтому в качестве индекса используется переменная-счетчик цикла, например: for I := 1 to 10 do {цикл по I от 1 до 10} Vect[I] := Random; {I-му элементу присваивается случайное число} В приведенном ниже примере осуществляется заполнение элементов матрицы случайными числами с помощью функции Random, вывод полученных значений на экран, также осуществляется поиск наибольшего значения и вывод его (вместе с координатами) на экран. program FindMaxElement; const {Объявление констант} Rows = 5; {Число строк матрицы} Cols = 4; {Число столбцов матрицы} Var {Объявление массива размером Rows x Cols} Mas: array[1..Rows, 1..Cols] of Real; I, J: Integer; {Объявление переменных цикла} MaxValue: Real; {Максимальное значение} MaxRowIndex: Integer; {Номер строки максимального значения} MaxColIndex: Integer; {Номер столбца максимального значения} Begin {Цикл заполнения массива и вывода элементов на экран} for I := 1 to Rows do {Цикл по I (перебор строк матрицы)} begin {можно было обойтись и без этого begin..end } for J := 1 to Cols do {Цикл по J (перебор столбцов матрицы)} begin {а этот begin..end требуется обязательно} {Присваиваем элементу (I, J) случайное значение} Mas[I, J] := Random; {Печатаем значение элемента (все - на одной строке)} Write(Mas[I, J]:8:2, ' '); if J = Cols then {Если это последний столбец, } Writeln; {то осуществляем перевод строки} end; end; {Данный begin..end здесь - для улучшения читабельности кода} {Перед началом поиска максимального значения переменная MaxValue уже должна иметь любое значение, но это значение не должно быть больше, чем элементы матрицы. Поэтому достаточно взять в качестве первоначального значения любой элемент матрицы Mas, например самый первый} MaxValue := Mas[1, 1]; {Запоминаем первый элемент} MaxRowIndex := 1; {Запоминаем номер строки 1-го элемента} MaxColIndex := 1; {Запоминаем номер столбца 1-го элемента} {Цикл поиска максимального элемента} for I := 1 to Rows do {Цикл по I (перебор строк матрицы)} for J := 1 to Cols do {Цикл по J (перебор столбцов матрицы)} Begin {Если текущий элемент (I, J) больше, чем MaxValue, то записываем этот элемент в MaxValue и сохраняем его координаты} if Mas[I, J] > MaxValue then Begin MaxValue := Mas[I, J]; MaxRowIndex := I; MaxColIndex := J; end; end; {Выводим найденные значения на экран} Writeln('Max value=', MaxValue:8:2, '; Row=', MaxRowIndex, '; Col=', MaxColIndex); Readln; end. Данный пример весьма прост и снабжен подробными комментариями. Очень важно детально разобраться с данным примером, поскольку от этого зависит успешность выполнения задания из варианта (п. 3.8). 3.7. Использование меню для объединения подзадач а и б. program Laba3; Label M1; {Объявление метки безусловного перехода M1} Var SubTask: Char; {Переменная типа Char (символ)} {**** Здесь разместить дополнительные необходимые переменные ****} Begin Writeln('Выберите одну из подзадач:'); Writeln('a – вычисление заданной величины в цикле'); Writeln('b – обработка элементов матрицы'); Writeln('e – выход из программы'); M1: Write('Введите символ:'); Readln(SubTask); {Ожидаем ввод любого символа} case SubTask of 'a', 'A': begin {Если ввели букву "a" или "A", то выполнится эта ветка} Writeln('a) – вычисление заданной величины в цикле'); {******* Здесь разместить операторы, необходимые для выполнения подзадачи "а" *******} end; 'b', 'B': begin {Если ввели букву "b" или "B", то выполнится эта ветка} Writeln('b) - обработка элементов матрицы '); {******* Здесь разместить операторы, необходимые для выполнения подзадачи "б" *******} end; 'e', 'E': begin {Если ввели английскую "e" или "E", то закрываем программу} Exit; end; {begin..end здесь указывать не обязательно} else {Для этого ELSE (от CASE) не нужен дополнительный begin..end } {Если ввели любой другой символ, то выполнится эта ветка} Writeln('Введен недопустимый символ!'); Writeln('Вы должны повторить ввод!'); goto M1; {Переход на метку M1} end; Readln; {Ожидание нажатия Enter} end. Данный пример не должен вызывать вопросов, поскольку сочетает в себе элементы кода, которые были в достаточной степени разобраны в предыдущих лабораторных работах. Следует отметить, что Char – порядковый тип данных, обеспечивающий представление 256 символов, в том числе цифр, знаков препинания, всех больших и малых букв латинского алфавита, а также одного дополнительного алфавита (например, кириллицы). 3.8. Варианты заданий 1.а) Вычислить n! б) Определить количество элементов матрицы, значения которых не превышают заданное число. 2.а) Вычислить . б) Найти минимальный элемент матрицы. 3.а) Вычислить . б) Найти максимальный элемент матрицы. 4.а) Вычислить . б) Поменять местами минимальный и максимальный элемент матрицы. 5.а) Вычислить . б) Поменять местами два заданных элемента матрицы. 6.а) Вычислить . б) Поменять местами две заданных строки матрицы. 7.а) Вычислить . б) Транспонировать матрицу А. 8.а) Вычислить . б) Сформировать массив В, содержащий сумму элементов каждого столбца матрицы А. 9.а) Вычислить . б) Поменять местами два заданных столбца матрицы. 10.а) Вычислить . б) Определить количество отрицательных элементов матрицы. 11.а) Вычислить  б) Определить количество положительных элементов матрицы. 12.а) Вычислить . б) Вычислить среднее арифметическое элементов матрицы. 13.а) Вычислить . б) Вычислить произведение отрицательных элементов матрицы. 14.а) Вычислить . б) Вычислить сумму положительных элементов матрицы. 15.а) Вычислить . б) Все отрицательные элементы матрицы возвести в квадрат. 16.а) Вычислить  б) Сформировать массив B, содержащий максимальные элементы строк матрицы A. 17.а) Вычислить . б) Сформировать массив B, содержащий суммы элементов строк матрицы A. 18.а) Вычислить сумму n членов геометрической прогрессии. б) Вычислить сумму всех отрицательных элементов матрицы. 19.а) Вычислить . б) Заполнить матрицу А случайными числами с помощью функции Random. 20.а) Вычислить . б) Вычислить сумму элементов главной диагонали матрицы. 3.9. Содержание отчета (см. п. 1.11) 3.10. Контрольные вопросы 1) Каково назначение оператора цикла FOR? 2) Каковы правила записи оператора цикла FOR? 3) Каковы алгоритмы работы оператора цикла FOR? 4) Какие циклы называются вложенными? 5) Какие ограничения наложены на оператор FOR? 6) Как определяются данные типа «массив»? Запишите примеры определения данных типа массив с использованием разделов type и var (или только var). 7) Какой тип могут иметь имеет переменные, которые используются в качестве индексов массива? 8) Как получить доступ к элементам одно-, дву-, n-мерного массива? 9) Как можно организовать ввод (вывод) элементов одно-, дву, n-мерного массива? Лабораторная работа №4. Разработка циклической программы с неизвестным количеством повторений 4.1. Цель работы Целью работы является освоение процесса разработки циклических программ с использованием условных циклов (с заранее неизвестным числом повторений) на языке Pascal. 4.2. Задание на лабораторную работу Требуется разработать две программы (или одну с двумя циклами) с использованием операторов повтора (циклических операторов) WHILE и REPEAT. 4.3. Требования к программе Программа должна выводить: – номер варианта, назначение программы и ФИО автора; – информационные сообщения о необходимости ввода данных; – сообщение с результатами, полученными в ходе работы программы; Программа должна проверять допустимые значения аргумента при вычислениях, например, для избежания деления на ноль. 4.4. Порядок выполнения работы 1. Получить вариант задания (п. 4.8). 2. Изучить правила использован |