Паскаль. Отладка программ

Укороченная форма оператора if В операторе if часть,
начинающаяся словом else, может отсутствовать. Часть, следующая за словом then,
выполняется, если логическое условие, стоящее после слова if, имеет значение
true. Если это логическое выражение имеет значение false, непосредственно
выполняется оператор, следующий за if. Наша программа может быть переписана с
применением укороченной формы оператора if. Алгоритм сводится к
последовательности проверок попадания переменной Аде в различные диапазоны
значений. Приведем измененный текст программы: Rep(y1 =
'Паскаль — прост, но первый компилятор Паскаля был написан на
Паскале'; Reply3 = 'Паскаль — разумный
компромисс между желательным и эффективным'; WriteLn(Question);
ReadLn(Name); {Ввод имени} WriteLn('Hello,', Name,'!'); {Вывод приветствия}
WriteLn('How old are you?'); {Вопрос о возрасте} ReadLn(Age); {Ввод возраста} if
12 < Age then WriteLn(Reply1 ); if (20 <= Age) and (Age
< 40) then WriteLn(Reply3); Алгоритмически этот вариант решения задачи с использованием сокращенной
формы оператора if существенно слабее первого варианта, в котором использовалась
полная форма. При исполнении программы будут проверены все четыре условия, даже
если при первой проверке найдено окончательное решение. Однако этот алгоритм не
имеет вложенных друг в друга операторов и поэтому проще для
понимания. Оператор if — один из
наиболее часто используемых структурных элементов языка — обеспечивает ветвление
алгоритма только на два направления. Вместе с тем ясно, что первый алгоритм
решения задачи удачнее выражает ее сущность. Для реализации подобных алгоритмов
необходим оператор множественного ветвления (выбора из нескольких ветвей
команд). Таким оператором в Паскале является оператор выбора case. < альтернатива 2>:< оператор 2 Case и of — зарезервированные слова, которые являются
отличительным признаком оператора множественного ветвления.
это переменная или выражение порядкового типа. В зависимости от значения данного
выражения или переменной происходит ветвление программы. После заголовка
оператора идет перечисление различных альтернатив, по которым может выполняться
программа. Альтернативы отделяются друг от друга точкой с запятой. Альтернатива
состоит из метки, двоеточия и исполняемого оператора данной альтернативы.
Используемая в операторе case метка может состоять из констант и диапазонов.
Диапазоны значений в Паскале — это два крайних значения, написанные через
двоеточие. Такая запись эквивалентна перечислению всех целых чисел в данном
диапазоне. В общем случае метка может состоять из различных констант и
диапазонов, разделенных запятыми, например, допустима такая метка: 4, 8..10, 12,
14.. 16. В качестве селектора нельзя использовать логические результаты
сравнения чисел (условия), поэтому использованные в операторах if неравенства
здесь неприменимы. Часть оператора case, состоящая из слова else и последнего
альтернативного варианта, является необязательной, она выполняется в том случае,
если вычисленный в программе селектор не соответствует ни одной из перечисленных
выше альтернатив. Если эта часть оператора case отсутствует, а селектор не
подходит ни под одну из альтернатив, то оператор case не выполнит никаких
действий. Завершается оператор case обязательным словом end; Question =' What is your name?'; Reply21 = 'Вас
ждет удивительное путешествие'; 'Паскаль — разумный компромисс между
желательным и эффективным'; WriteLn(Question);
ReadLn(Name); 12..19 : begin WriteLn
(Reply21); WriteLn (Reply22) end; Переменная Age играет роль селектора. В зависимости от
значения данной переменной происходит дальнейшее ветвление программы. В нашем
примере в качестве альтернатив применяются диапазоны значений, поскольку нельзя
использовать результаты сравнения чисел, как в предыдущей программе. Исходные
неравенства заменены диапазонами. Например, проверка логического условия Age
< 12 заменена проверкой принадлежности диапазону 0..11. В заключение
подчеркнем, что оператор case имеет существенные отличия от оператора if.
Используемые для выбора альтернатив метки должны быть количественно определены
до начала вычислений, поэтому в них могут применяться только константы,
приведенные непосредственно или описанные в разделе описаний. Кроме того,
оператор ограничен порядковыми типами данных, используемых для выбора
альтернатив. If Ready then Exam_ok := true else Exam_ok :=
false; В математических
задачах часто встречается необходимость неоднократного повторения одинаковых
действий. Рассмотрим, например, вычисление суммы N членов гармонического
ряда (1) обозначим искомую
сумму S и присвоим ей значение, равное нулю; Многократные повторения
одних и тех же действий можно выполнить с помощью конструкций, которые в
программировании называются циклами. Повторяемые действия называются телом
цикла. В Паскале существует несколько операторов цикла. Оператор for повторяет
тело цикла заданное число раз. Он имеет следующие синтаксические формы: <тело цикла>; do
Счетчик цикла — это переменная одного из порядковых
типов (из порядковых типов мы пока знаем только целые и логический тип, в главе
7 понятие порядкового типа будет расширено). Назначение этой переменной
очевидное — она хранит число повторений операторов тела цикла, следующего за
словом do. Значение счетчика цикла изменяется автоматически от первого до
последнего значения и увеличивается на единицу для первой формы записи (с
оператором to) или уменьшается на единицу для второй формы записи (с оператором
downto). Дополнительные изменения значения счетчика цикла в части, обозначенной
здесь как запрещены. В качестве первого и последнего
значения могут использоваться конкретные числа, другие переменные целого типа,
вычисленные ранее, и выражения, имеющие значения целого типа. Операторы тела
цикла выполняются только один раз, если верхнее и нижнее значения счетчика
совпадают. Если в операторе for .. to последнее значение счетчика цикла меньше
первого, то тело цикла не выполняется ни одного раза. В операторе for.. downto
цикл не выполняется, если последнее значение счетчика больше
первого. Program Sum; {сумма N членов гармонического
ряда} Write('N = '); ReadLn(N); {ввод числа членов
ряда} WriteLn( 'S = ', s); {вывод результата} Оператор, следующий после слова do, может быть составным
(представлять собой группу операторов). Пример. Найти нечетные и кратные трем
числа в диапазоне от 30 до 60 включительно. Распечатать их в порядке
убывания. Условие нечетности целого числа — Odd(J). Условие кратности трем —
равенство нулю остатка от деления i mod 3=0. Нас интересуют числа,
удовлетворяющие обоим условиям, то есть числа, для которых истинно Odd(i) and (i
mod 3 = 0). Убывающий порядок следования чисел обеспечивает оператор for..
downto. Таким образом, программа будет иметь вид if
Odd(i) and (i mod 3=0) then WriteLn(i) end. В приведенном примере многократно
повторялся один оператор, однако во многих случаях необходимо повторять группу
операторов. Вспомним, что говорилось в предыдущей главе о вложенности операторов
друг в друга. Чтобы использовать вместо одного оператора группу, нужно эту
группу превратить в один сложный оператор. Осуществляется это с помощью так
называемых "программных скобок" — операторов begin и
end. Любая группа операторов, начинающаяся со слова begin и
кончающаяся словом end в любой конструкции языка Паскаль может использоваться
как один сложный оператор. Сложный оператор, в свою очередь, может иметь в своем
составе сложные операторы следующего уровня вложенности и так далее. Операторы
begin и end подобны открывающим и закрывающим скобкам, и на их употребление
накладываются те же ограничения, что и на обыкновенные скобки в арифметических
выражениях: каждой "открывающей скобке" begin должна соответствовать
"закрывающая скобка" end. Слово end не может предшествовать парному ему слову
begin. При компиляции программы проверяется правильность расстановки скобок и
дается сообщение об ошибке. Это сообщение не всегда попадает в то место, где
действительно нужна скобка, поэтому не спешите вставлять операторы туда, куда
предлагает компилятор, а тщательно проанализируйте Вашу программу. Пример.
Имеется логическое выражение not a and b xor с. Требуется вывести на печать
значения логических переменных а, Ь, с, при которых данное выражение истинно. Мы
предлагаем перебор всех возможных значений а, b, с с проверкой выполнения
условия для каждого сочетания значений.
for с := false to true do В
результате выполнения этой программы на экран будет выведено: b =TRUE Программа состоит из одного сложного
оператора for a := false to true do, в который вложены последовательно еще два
оператора for и оператор if. Часть then последнего содержит сложный оператор,
состоящий из трех простых операторов, охваченных программными скобками begin и
end. Введенный в предыдущей главе оператор
цикла for обеспечивает выполнение цикла заданное количество раз, однако часто
циклические действия заканчиваются по условию, то есть выполняются до достижения
определенного результата. В Паскале есть два таких оператора цикла, отличающиеся
тем, что в одном из них условие проверяется в начале цикла (while...do), а в
другом — в конце цикла (repeat...until). <логическое
выражение> Цикл While обеспечивает
выполнение тела цикла, следующего за словом do до тех пор, пока условие имеет
значение true (истина). В качестве тела цикла может использоваться простой или
сложный оператор. Условие проверяется перед началом каждого выполнения тела
цикла, поэтому, если до первого выполнения цикла условие имеет значение false
(ложь), оператор не выполняется ни одного раза (рис. 5.2). Пример. Необходимо
преобразовать значение угла в градусах к стандартному диапазону ±180° путем
исключения полных оборотов окружности ±360°. Эта процедура может быть выполнена
с помощью оператора цикла Оператор while в
начале цикла проверяет, превышает ли угол по абсолютному значению 180 градусов.
Если это не справедливо, тело цикла не выполняется. Если угол больше
допустимого, начинается выполнение цикла. Цикл состоит из оператора if.
Допустим, угол равен —700. Тогда условие Angle > 0 в операторе if имеет
значение false, при этом выполняется часть else оператора if, и угол получит
значение —340. Снова происходит проверка условия выполнения цикла, и цикл
выполняется второй раз, после чего угол равен 20. При третьей проверке условия
выполнения цикла он заканчивается, поскольку условие его выполнения
Abs(20)>180 приняло значение false. Оператор цикла repeat... until... (повторять до тех пор, пока) имеет
вид Repeat <тело цикла> until -<логическое
выражение>; Принципиальное отличие оператора repeat...until от оператора
while...do в том, что проверка условия производится не перед началом выполнения
оператора, а в его конце, когда решается вопрос, повторить ли еще раз действия.
Поэтому тело этого цикла всегда выполняется по крайней мере один раз (рис. 5.3).
Это важное отличие: приведенный для цикла while... do пример реализовать с
оператором цикла repeat... until невозможно без дополнительных проверок и
усложнений. Второе отличие от оператора while...do — в логике завершения
цикла. Цикл оператора repeat...until выполняется до тех пор, пока не станет
истинным логическое выражение, следующее за словом until. Таким образом,
использование логического выражения здесь имеет противоположный оператору
while...do смысл. Здесь при истинности логического выражения (условия) цикл
прекращается, а у оператора while...do при истинности логического выражения цикл
продолжается. начальную и завершающую, которые охватывают группу операторов,
составляющих тело цикла. Оператор while...do не имеет завершающей части и
требует для организации тела цикла из нескольких операторов программных скобок
begin-end. Для оператора repeat...until таких скобок не требуется — их роль
выполняют составные части оператора. Пример. Найти методом подбора
целочисленное решение Диофантова уравнения 5x-3y=1. В качестве первой пробы
берутся единичные значения. Далее, если 5x-3y>1, то у увеличивается на 1,
если 5x-3y<1, то на 1 увеличивается х. if (5 * x -
3 * у) < 1 then х := х + 1 until(5*x-3*y)=1; Пример. С помощью цикла
repeat...until можно организовать процедуруввода данных с защитой программы от
завершения при ошибочном наборе. Если тип данных не соответствует
инициализируемой при стандартном вводе переменной (например, требуется ввести
целое число, а набрано дробное), то возникает ошибка в выполнении программы, и
мы должны снова запускать программу, и, естественно, повторить набор. Чтобы
защититься от последствий таких ошибок, можно использовать собственную процедуру
ввода. Такая процедура должна отключить автоматическую проверку правильности
ввода и проводить ее самостоятельно, причем при ошибке требовать повторного
набора. Отключение проверки правильности ввода производится директивой
компилятора {$!-} (Input/Output checking в окне настройки опций компилятора).
После каждого действия по вводу-выводу специальная функция lOResult возвращает
целое значение, соответствующее ошибкам ввода-вывода. Правильной работе ввода-
вывода соответствует нулевое значение, возвращаемое этой функцией. Надежный ввод
целого числа i выполняет фрагмент программы: Write ('Введите i = '); {вывод на экран предложения для
ввода} until lOResult = 0; {lOResult —
функция, равная 0, если нет ошибки} {$!+} {восстановление проверки ввода-
вывода} вводится число; если при вводе была
сделана ошибка, условие lOResult = 0 имеет значение false, и ввод будет
повторяться до тех пор, пока он не будет сделан правильно. В последних версиях языка Borland Pascal введены два новых
оператора, Break и Continue, применяемые внутри циклов. Они расширяют
возможности использования циклов и улучшают структуру программ. В процессе
выполнения тела цикла до его завершения могут возникнуть дополнительные условия,
требующие завершения цикла. В этом случае цикл может быть прекращен оператором
Break. Пример. Игра с ЭВМ в кости. Условия игры. Компьютер выдает себе или Вам
случайные числа от 1 до 6. Задача —набрать максимальную сумму очков. Набравший
больше 21 очка проигрывает, в любой момент один из игроков может отказаться от
набора очков (спасовать). SumComp, {сумма очков
компьютера} SumComp:=12; {начальное количество
очков} write ('Бросить кость для Вас?
(у/n)'); {выход из цикла — при корректном ответе} {метание кости для игрока
при положительном ответе} {Random(6) дает
случайные числа от 0 до 5} WriteLn( вам выпало ', count,' очков.'); {вывод
выпавшего количества очков} SumYour := SumYour + count; {подсчет суммы очков
игрока} if
SumYour >= MaxSum then Вгеаk{прекращение игры при переборе} end; if SumComp
< 18 then {если компьютер продолжает игру} begin Count := Random(6) + 1;
{число очков компьютера} WriteLn('мнe выпало ', count,' очков.'); {вывод
количества очков} SumComp := SumComp + count; {подсчет суммы очков компьютера}
Writeln('y меня всего ', SumComp,' очков.'); {вывод суммы очков} write(' пас. Будете продолжать? (у/п)'); {запрос о
продолжении игры} if (reply = 'n') or (reply = 'N') then
Break {прекращение игры if SumYour > MaxSum
then writeln('Bы проиграли!') else if SumYour
< SumComp then writeln('Я выиграл!') else writeln('Вы
выиграли!'); Первая часть реализует бесконечный цикл метания
костей, ограниченный оператором repeat ... until false. Выбор оператора repeat
мотивирован тем, что должен быть сделан, по крайней мере, один ход игры. Цикл
может быть прерван оператором Break при переборе очков любым из игроков и при
отказе обоих партнеров от продолжения игры. Объединение трех условий в одно и
использование его как завершающего условия цикла repeat... until усложнит
алгоритм, а применение для прекращения игры оператора Break алгоритм
упрощает. продолжается до тех пор, пока
не будет введен допустимый символ ('у', 'Y', 'п' или 'N') при ответе на вопрос о
продолжении игры. Для имитации метания костей применена функция Random с
параметром — целым числом, равным 6. При таком использовании она дает случайные
целые числа в диапазоне от 0 до 5 включительно. Подведение итогов игры
выполняют вложенные друг в друга операторы if. Возможные итоги игры проверяются
последовательно. Если возможен вывод, выполняется часть then оператора. Если не
возможен, выполняется часть else, в которой стоит оператор дальнейшего ветвления
if. Среда
Borland Pascal имеет несколько встроенных инструментальных средств отладки
программ. С некоторыми из них мы уже познакомились. Механизм пошагового
выполнения программы, вызываемый функциональной клавишей F7, и его варианты:
пошаговое выполнение без входа в процедуры, вызываемое клавишей F8, и исполнение
до заданной строки (клавиша F4) позволяют проверить, соответствует ли
последовательность выполнения команд Вашим требованиям к
алгоритму. Эффективность отладки возрастает при совместном использовании
различных инструментальных средств среды программирования. Для использования
средств отладки должны быть включены опции компилятора: Debug information, Local
symbols и Symbol information (меню Options/ Compiler). Если опции установлены, в
файл включается специальная информация, допускающая применение средств отладки.
В отлаженной программе эта информация не требуется, поэтому при компиляции
программы как готового продукта опции отладки рекомендуется отключить.
Инструментальные средства отладки доступны через меню Debug (отладка),
приведенное на рисунке 5.4. Из меню Debug можно вызвать три окна: Output,
Watch и Call stack, которые как объекты интерфейса подобны окну с текстом
программы. Они имеют порядковый номер, их размеры и положение изменяются так же,
как размеры и положение любых текстовых окон. Они приводятся в списке окон меню
Windows, могут активизироваться из этого меню. Любое из этих окон закрывается
клавишами Alt + F3. Отличие от текстовых окон в том, что мы не можем выполнять в
них свободную запись. Пункт User screen позволяет увидеть пользовательский
экран — экран, в который выводится текстовая и графическая информация при
исполнении программы. Естественно, такая потребность возникает часто,
поэтому Контрольные точки Окно регистров Окно
программы стоит запомнить
комбинацию клавиш Alt + F5 для его быстрого вызова. Если требуется одновременно
наблюдать на экране текст программы и результаты ее работы в текстовом режиме,
можно открыть окно Output — окно, в которое будут выводиться результаты
исполнения программы. Размер окна Output можно отрегулировать клавишами
перемещения курсора после нажатия Control + F5 или мышью, как описано
ранее. Окно отладки программ Watch может быть открыто пунктом меню Watch или
Add watch. В каждой строчке окна может быть задана некоторая переменная или
выражение. В процессе выполнения программы текущее значение заданной переменной
или выражения выводится в это окно. Отладка с использованием окна Watch обычно
сочетается с пошаговой отладкой, когда можно проверить не только
последовательность выполнения команд, но и значения величин, приводящие к такой
последовательности выполнения. Для создания окна Watch нет необходимости
вызывать пункт меню Watch. Можно просто нажать клавиши Control + F7 — и Вы
получите окно Add Watch, в котором надо ввести имя переменной для вывода в окно
отладки. В строке для набора имени будет подсвечено то имя, на котором стоял
текстовый курсор в момент нажатия клавиш Control + F7. Если Вы нажмете Enter, в
окно Watch добавится набранная в окне Add Watch переменная или выражение, если
начнете набор другого имени, это имя исчезнет без дополнительных действий для
удаления. Если сразу после открытия окна Add Watch нажать стрелку курсора
вправо, то в окно ввода начинают вводиться символы из текста программы,
следующие за курсором. Когда окно Watch активно, в нижней строке появляются
указания на наиболее актуальные действия, которые можно совершить в данном
состоянии. Подсказка напоминает Вам, что пошаговая отладка проводится по нажатию
клавиш F7 или F8, предлагает нажать Insert для добавления новой переменной в
окно, Delete для удаления записи, Enter для редактирования записи, на которой
стоит курсор окна отладки. Загрузим, например, программу определения
наибольшего общего делителя. Откроем окно Output для диалога в процессе
выполнения программы. Откроем окно Watch и поместим в него все три переменные
нашей программы: Common, First и Second. При пошаговой отладке программы по
клавише F7 мы увидим, что до исполнения программы переменные не определены. По
мере ввода чисел переменные First и Second получают введенные значения. В начале
цикла получает значение и переменная Common, которая изменяется при каждом
прохождении цикла. Вы также увидите, что строка бывает подсвечена очень редко, так
как для большинства чисел предыдущий оператор continue завершает данный проход
цикла, и эта строка действительно не выполняется. Пошаговый проход программы в
том случае, когда выполняется большое число циклов, — занятие весьма
утомительное, а иногда и невозможное. Поэтому предусмотрен механизм введения в
программу контрольных точек Контрольная точка — это логическое условие,
которое вычисляется каждый раз при выполнении заданной строки программы. Если
выполняются условия прерывания, программа останавливается в контрольной точке.
Далее мы можем вводить другие контрольные точки или применять пошаговую отладку
с просмотром в окне Watch. Чтобы добавить контрольную точку в программу, надо
ввести имя файла, номер строки, в которой производится проверка, логическое
условие, по достижению которого происходит остановка программы, и число проходов
заданной строки, в которых данное логическое условие не просчитывается. Если
логическое условие не задано, остановка возникает по достижению данной строки.
Число проходов данной строки без анализа по умолчанию устанавливается равным 0,
то есть анализ проводится, начиная с первого прохода. Предположим, в программе
определения наибольшего общего делителя Common.pas мы хотим проверить отношения,
возникающие при кратности переменных Second и Common. Тогда в окне Add
Breakpoint в поле Condition мы вводим условие прерывания программы Second mod
Common = 0. В поле FileName автоматически вносится имя файла, активного окна, а
в поле Line number — номер строки, в которой находится курсор. В строку Pass
count записывается число 0, так как мы хотим остановить программу уже при первом
выполнении условия прерывания . Окно, открывающееся
при выборе пункта меню Evaluate/Modify, также, как окно Watch, позволяет
просмотреть значение любой переменной или выражения, но при этом можно изменить
значение переменной. Окно Evaluate/Modify может быть вызвано, если выполнение
программы остановлено через механизм точки прерываний или при пошаговой отладке,
и должно быть закрыто для продолжения работы программы . Это окно удобно
использовать как "калькулятор". Для выполнения вспомогательных вычислений
достаточно ввести соответствующее выражение в поле Expression и прочитать
результат в поле Result.