Турбо Паскаль 7.0
ТЕМА: ТурбоПаскаль7.0
Логические операторы и операторы цикла.
Отладка программ.
Укороченная форма оператора if
В операторе if часть, начинающаяся словом else, может отсутствовать. Часть, следующая за словом then, выполняется, если логическое условие, стоящее после слова if, имеет значение true. Если это логическое выражение имеет значение false, непосредственно выполняется оператор, следующий за if.
Наша программа может быть переписана с применением укороченной формы оператора if. Алгоритм сводится к последовательности проверок по¬падания переменной Аде в различные диапазоны значений. Приведем изме¬ненный текст программы:
Program Dialog; {расширенный диалог — второй вариант) const
Question =\\\' What is your name?\\\';
Rep(y1 =
\\\'Паскаль — прост, но первый компилятор Паскаля был написан на Паскале\\\';
Reply21 = \\\'Вас ждет удивительное путешествие\\\';
Reply22 = \\\'сквозь джунгли особенностей и возможностей языка\\\';
Reply3 =
\\\'Паскаль — разумный компромисс между желательным и эффективным\\\';
Reply4 = \\\'Паскаль академически элегантен\\\';
var
Name: string;
Age: byte;
begin
WriteLn(Question); ReadLn(Name); {Ввод имени} WriteLn(\\\'Hello,\\\ Name,\\\'!\\\'); {Вывод приветствия} WriteLn(\\\'How old are you?\\\'); {Вопрос о возрасте} ReadLn(Age); {Ввод возраста} if 12 < Age then WriteLn(Reply1 );
if (12 <= Age) and (Age < 20) then begin
WriteLn (Reply21);
WriteLn (Reply22) end;
if (20 <= Age) and (Age < 40) then WriteLn(Reply3);
if Age >= 40 then WriteLn(Reply4) end.
Алгоритмически этот вариант решения задачи с использованием сокра¬щенной формы оператора if существенно слабее первого варианта, в кото¬ром использовалась полная форма. При исполнении программы будут про¬верены все четыре условия, даже если при первой проверке найдено окончательное решение. Однако этот алгоритм не имеет вложенных друг в друга операторов и поэтому проще для понимания.
Оператор выбора case
Оператор if — один из наиболее часто используемых структурных элемен¬тов языка — обеспечивает ветвление алгоритма только на два направления. Вместе с тем ясно, что первый алгоритм решения задачиудачнее выражает ее сущность. Для реализации подобных алгоритмов необходим оператор множественного ветвления (выбора из нескольких ветвей ко¬манд). Таким оператором в Паскале является оператор выбора case.
Общий вид этого оператора:
case <селектор> of < альтернатива 1 > : < оператор 1>;
< альтернатива 2>:< оператор 2 >;
< альтернатива N >: < оператор N > else < оператор части Else> end;
Case и of — зарезервированные слова, которые являются отличитель¬ным признаком оператора множественного ветвления. Селектор — это пере¬менная или выражение порядкового типа. В зависимости от значения дан¬ного выражения или переменной происходит ветвление программы. После заголовка оператора идет перечисление различных альтернатив, по кото¬рым может выполняться программа. Альтернативы отделяются друг от друга точкой с запятой. Альтернатива состоит из метки, двоеточия и исполняемого оператора данной альтернативы. Используемая в операторе case метка может состоять из констант и диапазонов. Диапазоны значений в Паскале — это два крайних значения, написанные через двоеточие. Такая запись эквивалентна перечислению всех целых чисел в данном диапазоне. В общем случае метка может состоять из различных констант и диапазо¬нов, разделенных запятыми, например, допустима такая метка: 4, 8..10, 12, 14.. 16. В качестве селектора нельзя использовать логические результаты сравнения чисел (условия), поэтому использованные в операторах if нера¬венства здесь неприменимы.
Часть оператора case, состоящая из слова else и последнего альтернатив¬ного варианта, является необязательной, она выполняется в том случае, если вычисленный в программе селектор не соответствует ни одной из перечис¬ленных выше альтернатив. Если эта часть оператора case отсутствует, а се¬лектор не подходит ни под одну из альтернатив, то оператор case не выпол¬нит никаких действий. Завершается оператор case обязательным словом end;
Пример. С использованием оператора case наша программа приобрета¬ет следующий вид
Program Dialog;
const
Question =\\\' What is your name?\\\';
Replyl =
\\\'Паскаль — прост, но первый компилятор Паскаля был написан на Паскале\\\';
Reply21 = \\\'Вас ждет удивительное путешествие\\\';
Reply22 = \\\'сквозь джунгли особенностей и возможностей языка\\\';
ReplyS =
\\\'Паскаль — разумный компромисс между желательным и эффективным\\\';
Reply4 = \\\'Паскаль академически элегантен\\\';
var
Name: string;
Age: byte;
begin
WriteLn(Question); ReadLn(Name);
WriteLn(\\\'Hello,\\\ Name,\\\'!\\\');
WriteLn(\\\'Howold are you?\\\'); ReadLn(Age);
case Age of
0..11 :WriteLn(Reply1);
12..19 : begin WriteLn (Reply21); WriteLn (Reply22) end;
20..39: WriteLn(Reply3);
40..150:WriteLn(Reply4)
else WriteLn(\\\'Bbi ошиблись при вводе\\\')
end
end.
Переменная Age играет роль селектора. В зависимости от значения дан¬ной переменной происходит дальнейшее ветвление программы. В нашем примере в качестве альтернатив применяются диапазоны значений, по¬скольку нельзя использовать результаты сравнения чисел, как в предыду¬щей программе. Исходные неравенства заменены диапазонами. Например, проверка логического условия Age < 12 заменена проверкой принадлежно¬сти диапазону 0..11.
В заключение подчеркнем, что оператор case имеет существенные отличия от оператора if. Используемые для выбора альтернатив метки должны быть количественно определены до начала вычислений, поэтому в них могут применяться только константы, приведенные непосредственно или описанные в разделе описаний. Кроме того, оператор ограничен поряд¬ковыми типами данных, используемых для выбора альтернатив.
If Ready then Exam_ok := true;
Идеальная логика эквивалентности:
If Ready then Exam_ok := true else Exam_ok := false;
Управление вычислительным процессом, цикл for
В математических задачах часто встречается необходимость неоднократно¬го повторения одинаковых действий. Рассмотрим, например, вычисление суммы N членов гармонического ряда
Естественный алгоритм для решения такой задачи:
(1) обозначим искомую сумму S и присвоим ей значение, равное нулю;
(2) последовательно N раз вычислим слагаемые ряда и прибавим их к переменной S.
Многократные повторения одних и тех же действий можно выполнить с помощью конструкций, которые в программировании называются цикла¬ми. Повторяемые действия называются телом цикла. В Паскале существует несколько операторов цикла. Оператор for повторяет тело цикла заданное число раз. Он имеет следующие синтаксические формы:
for < счетчик цикла> := < первое значение> to < последнее значение> do
<тело цикла>;
for < счетчик цикла> := < первое значение>
downto < последнее значение> do <тело цикла>;
Счетчик цикла — это переменная одного из порядковых типов (из по¬рядковых типов мы пока знаем только целые и логический тип, в главе 7 понятие порядкового типа будет расширено). Назначение этой переменной очевидное — она хранит число повторений операторов тела цикла, сле¬дующего за словом do. Значение счетчика цикла изменяется автоматически от первого до последнего значения и увеличивается на единицу для первой формы записи (с оператором to) или уменьшается на единицу для второй формы записи (с оператором downto). Дополнительные изменения значе¬ния счетчика цикла в части, обозначенной здесь как <тело цикла>, запреще¬ны. В качестве первого и последнего значения могут использоваться кон¬кретные числа, другие переменные целого типа, вычисленные ранее, и вы¬ражения, имеющие значения целого типа.
Операторы тела цикла выполняются только один раз, если верхнее и нижнее значения счетчика совпадают. Если в операторе for .. to последнее значение счетчика цикла меньше первого, то тело цикла не выполняется ни одного раза. В операторе for.. downto цикл не выполняется, если последнее значение счетчика больше первого.
Программа с циклом for, которая вычисляет сумму N членов гармо¬нического ряда1:
Program Sum; {сумма N членов гармонического ряда}
var x: byte; {счетчик цикла}
s : real;{сумма ряда}
N : byte; {число членов ряда}
begin
Write(\\\'N = \\\'); ReadLn(N); {ввод числа членов ряда}
s := 0;{начальное значение суммы}
тогх:= 1 toNdos:=s+ 1/х; {подсчет суммы}
WriteLn( \\\'S = \\\ s); {вывод результата}
ReadLn {ожидание нажатия клавиши Enter}
end.
Оператор, следующий после слова do, может быть составным (пред¬ставлять собой группу операторов).
Пример. Найти нечетные и кратные трем числа в диапазоне от 30 до 60 включительно. Распечатать их в порядке убывания.
Условие нечетности целого числа — Odd(J). Условие кратности трем — равенство нулю остатка от деления i mod 3=0. Нас интересуют числа, удов¬летворяющие обоим условиям, то есть числа, для которых истинно Odd(i) and (i mod 3 = 0). Убывающий порядок следования чисел обеспечивает опе¬ратор for.. downto. Таким образом, программа будет иметь вид
Program Sample;
var i: byte;
begin
for i := 60 downto 30 do{цикл по убывающей от 60 до 30}
if Odd(i) and (i mod 3=0) then WriteLn(i) end.
В результате выполнении программы получим в столбик значения 57, 51,45,39, 33.
В приведенном примере многократно повторялся один оператор, одна¬ко во многих случаях необходимо повторять группу операторов. Вспомним, что говорилось в предыдущей главе о вложенности операторов друг в друга. Чтобы использовать вместо одного оператора группу, нужно эту группу превратить в один сложный оператор. Осуществляется это с по¬мощью так называемых «программных скобок» — операторов begin и end.
begin
<оператор1>;
< оператор 2>;
< оператор М> end;
Любая группа операторов, начинающаяся со слова begin и кончающаяся словом end в любой конструкции языка Паскаль может использоваться как один сложный оператор. Сложный оператор, в свою очередь, может иметь в своем составе сложные операторы следующего уровня вложенности и так да¬лее. Операторы begin и end подобны открывающим и закрывающим скобкам, и на их употребление накладываются те же ограничения, что и на обыкно¬венные скобки в арифметических выражениях: каждой «открывающей скоб¬ке» begin должна соответствовать «закрывающая скобка» end. Слово end не может предшествовать парному ему слову begin. При компиляции програм¬мы проверяется правильность расстановки скобок и дается сообщение об ошибке. Это сообщение не всегда попадает в то место, где действительно нужна скобка, поэтому не спешите вставлять операторы туда, куда предлага¬ет компилятор, а тщательно проанализируйте Вашу программу.
Пример. Имеется логическое выражение not a and b xor с. Требуется вы¬вести на печать значения логических переменных а, Ь, с, при которых дан¬ное выражение истинно. Мы предлагаем перебор всех возможных зна¬чений а, b, с с проверкой выполнения условия для каждого сочетания значений.
Program Sample;
Vara, b, с : boolean;
begin
for a := false to true do
for b := false to true do
for с := false to true do
if not a and b xor с then
begin
Write(\\\'a=\\\a);
Write(\\\'b=\\\b);
WriteLn(\\\'c=\\\c)
End
End.
В результате выполнения этой программы на экран будет выведено:
a =FALSE
b =FALSE
с =TRUE
a =FALSE
b =TRUE
с =FALSE
a =TRUE
b =FALSE
c =TRUE
a =TRUE
b =TRUE
с =TRUE
Программа состоит из одного сложного оператора for a := false to true do, в который вложены последовательно еще два оператора for и оператор if. Часть then последнего содержит сложный оператор, состоящий из трех простых операторов, охваченных программными скобками begin и end.
Циклы с логическими условиями
Введенный в предыдущей главе оператор цикла for обеспечивает выполне¬ние цикла заданное количество раз, однако часто циклические действия за¬канчиваются по условию, то есть выполняются до достижения определен¬ного результата. В Паскале есть два таких оператора цикла, отличающиеся тем, что в одном из них условие проверяется в начале цикла (while...do), а в другом — в конце цикла (repeat...until).
Оператор while.. do
Оператор цикла while (пока, в то время как) имеет вид:
While <логическое выражение> do <тело цикла>;
Цикл While обеспечивает выполнение тела цикла, следующего за сло¬вом do до тех пор, пока условие имеет значение true (истина). В качестве те¬ла цикла может использоваться простой или сложный оператор. Условие проверяется перед началом каждого выполнения тела цикла, поэтому, если до первого выполнения цикла условие имеет значение false (ложь), опера¬тор не выполняется ни одного раза (рис. 5.2).
Пример. Необходимо преобразовать значение угла в градусах к стандарт¬ному диапазону ±180° путем исключения полных оборотов окружности ±360°. Эта процедура может быть выполнена с помощью оператора цикла
While abs(Angle) > 180 do
if Angle > 0 then Angle := Angle — 360
else Angle := Angle + 360;
Оператор while в начале цикла проверяет, превышает ли угол по абсо¬лютному значению 180 градусов. Если это не справедливо, тело цикла не вы¬полняется. Если угол больше допустимого, начинается выполнение цикла.
Цикл состоит из оператора if. Допустим, угол равен —700. Тогда условие An¬gle > 0 в операторе if имеет значение false, при этом выполняется часть else оператора if, и угол получит значение —340. Снова происходит проверка условия выполнения цикла, и цикл выполняется второй раз, после чего угол равен 20. При третьей проверке условия выполнения цикла он заканчивает¬ся, поскольку условие его выполнения Abs(20)>180 приняло значение false.
Оператор repeat... until...
Оператор цикла repeat... until... (повторять до тех пор, пока) имеет вид Repeat <тело цикла> until -<логическое выражение>;
Принципиальное отличие оператора repeat...until от оператора while...do в том, что проверка условия производится не перед началом выполнения оператора, а в его конце, когда решается вопрос, повторить ли еще раз дей¬ствия. Поэтому тело этого цикла всегда выполняется по крайней мере один раз (рис. 5.3). Это важное отличие: приведенный для цикла while... do при¬мер реализовать с оператором цикла repeat... until невозможно без дополни¬тельных проверок и усложнений.
Второе отличие от оператора while...do — в логике завершения цикла. Цикл оператора repeat...until выполняется до тех пор, пока не станет истинным логическое выражение, следующее за словом until. Таким образом, использование логического выражения здесь имеет противоположный опе¬ратору while...do смысл. Здесь при истинности логического выражения (условия) цикл прекращается, а у оператора while...do при истинности ло¬гического выражения цикл продолжается.
Третье отличие в том, что оператор repeat...until имеет две части:
начальную и завершающую, которые охватывают группу операторов, со¬ставляющих тело цикла. Оператор while...do не имеет завершающей части и требует для организации тела цикла из нескольких операторов програм¬мных скобок begin-end. Для оператора repeat...until таких скобок не требу¬ется — их роль выполняют составные части оператора.
Пример. Найти методом подбора целочисленное решение Диофантова уравнения 5x-3y=1. В качестве первой пробы берутся единичные значения. Далее, если 5x-3y>1, то у увеличивается на 1, если 5x-3y<1, то на 1 увеличивается х.
Program Diophant;
var х, у: byte;
begin
x:=1;y:=1;
repeat
if(5*x-3*y)>1theny:=y+1;
if (5 * x - 3 * у) < 1 then х := х + 1 until(5*x-3*y)=1;
writeln(\\\'x= \\\x, \\\'y=\\\y) end.
В результате на экране получим х=2у=3.
Пример. С помощью цикла repeat...until можно организовать процедуру ввода данных с защитой программы от завершения при ошибочном наборе. Если тип данных не соответствует инициализируемой при стандартном вводе переменной (например, требуется ввести целое число, а набрано дробное), то возникает ошибка в выполнении программы, и мы должны снова запускать программу, и, естественно, повторить набор. Чтобы защи¬титься от последствий таких ошибок, можно использовать собственную процедуру ввода. Такая процедура должна отключить автоматическую про¬верку правильности ввода и проводить ее самостоятельно, причем при ошибке требовать повторного набора. Отключение проверки правильности ввода производится директивой компилятора {$!-} (Input/Output checking в окне настройки опций компилятора). После каждого действия по вводу-выводу специальная функция lOResult возвращает целое значение, соответ¬ствующее ошибкам ввода-вывода. Правильной работе ввода-вывода соответствует нулевое значение, возвращаемое этой функцией. Надежный ввод целого числа i выполняет фрагмент программы:
{$!-}{отключение проверки ввода-вывода} repeat
Write (\\\'Введите i = \\\'); {вывод на экран предложения для ввода}
ReadLn (i) {ввод целого числа}
until lOResult = 0; {lOResult — функция, равная 0, если нет ошибки} {$!+}{восстановление проверки ввода-вывода}
По крайней мере один раз вводится число; если при вводе была сделана ошибка, условие lOResult = 0 имеет значение false, и ввод будет повторяться до тех пор, пока он не будет сделан правильно.
Операторы Break и Continue
В последних версиях языка Borland Pascal введены два новых оператора, Break и Continue, применяемые внутри циклов. Они расширяют возможности использова¬ния циклов и улучшают структуру программ. В процессе выполнения тела цикла до его завершения могут возникнуть дополнительные условия, требующие завер¬шения цикла. В этом случае цикл может быть прекращен оператором Break.
Пример. Игра с ЭВМ в кости. Условия игры. Компьютер выдает себе или Вам случайные числа от 1 до 6. Задача — набрать максимальную сум¬му очков. Набравший больше 21 очка проигрывает, в любой момент один из игроков может отказаться от набора очков (спасовать).
Program Bones;
Const MaxSum = 1;{максимальное число очков}
var SumYour, {сумма очков игрока}
SumComp, {сумма очков компьютера}
count: byte; {очередные выпавшие очки}
reply: string;{ответ на запрос ЭВМ}
begin
SumYour := 0;
SumComp:=12; {начальное количество очков}
Randomize; {установка датчика случайных чисел}
repeat{начало общего цикла, организующего игру}
write (\\\'Бросить кость для Вас? (у/n)\\\');
repeat {Начало цикла для ввода корректного ответа} readln(reply){ввод ответа}
{выход из цикла — при корректном ответе}
until (reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply =\\\'n\\\') or (reply = \\\'N\\\');
{метание кости для игрока при положительном ответе}
if (reply = \\\'у\\\') or (reply = \\\'Y\\\') then {если ответ »да»}
begin Count := Random(6) + 1; {число очков игрока}
{Random(6) дает случайные числа от 0 до 5}
WriteLn( вам выпало \\\ count,\\\' очков.\\\'); {вывод выпавшего количества очков} SumYour := SumYour + count;{подсчет суммы очков игрока}
Writeln(\\\'y Вас всего \\\ SumYour,\\\' очков.\\\'); {вывод суммы очков}
if SumYour >= MaxSum then Вгеаk{прекращение игры при переборе} end;
{метание кости для компьютера — он играет,
если сумма очков меньше 18}
if SumComp < 18 then {если компьютер продолжает игру}
begin Count := Random(6) + 1;{число очков компьютера} WriteLn(\\\'мнe выпало \\\ count,\\\' очков.\\\'); {вывод количества очков} SumComp := SumComp + count; {подсчет суммы очков компьютера} Writeln(\\\'y меня всего \\\ SumComp,\\\' очков.\\\'); {вывод суммы очков}
if SumYour >= MaxSum then Break {прекращение игры при переборе} end
else begin {если компьютер пасует}
write(‘ пас. Будете продолжать? (у/п)’);{запрос о продолжении игры}
repeat
read(reply) until (reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply = \\\'n\\\') or (reply = \\\'N\\\');
if (reply = \\\'n\\\') or (reply = \\\'N\\\') then Break{прекращение игры
по взаимному согласию}
end
until false;{замыкание цикла метания костей}{подведение итогов}
if SumYour > MaxSum then writeln(\\\'Bы проиграли!\\\')
{перебор игрока}
else if SumComp > MaxSum then writeln(‘Я проиграл!\\\')
{перебор у компьютера}
else if SumYour < SumComp then writeln(\\\'Я выиграл!\\\')
{сравнение очков}
else if SumYour = SumComp then writeln (\\\'Ничья!\\\')
{равенство очков}
else writeln(\\\'Вы выиграли!\\\');
ReadLn
end.
Программа разбита на две основные части: метание костей и подведе¬ние итогов.
Первая часть реализует бесконечный цикл метания костей, ограничен¬ный оператором repeat ... until false. Выбор оператора repeat мотивирован тем, что должен быть сделан, по крайней мере, один ход игры. Цикл может быть прерван оператором Break при переборе очков любым из игроков и при отказе обоих партнеров от продолжения игры. Объединение трех усло¬вий в одно и использование его как завершающего условия цикла re¬peat... until усложнит алгоритм, а применение для прекращения игры опера¬тора Break алгоритм упрощает.
Цикл repeat... until с завершающим условием
(reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply =\\\'n\\\') or (reply = \\\'N\\\');
продолжается до тех пор, пока не будет введен допустимый символ (\\\'у\\\ \\\'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, которая изменяется при каждом прохождении цикла. Вы также увидите, что строка
if (First mod Common) = 0 then begin WriteLn(\\\'HCVl = \\\ Common); Break end
бывает подсвечена очень редко, так как для большинства чисел предыду¬щий оператор continue завершает данный проход цикла, и эта строка дей¬ствительно не выполняется.
Пошаговый проход программы в том случае, когда выполняется боль¬шое число циклов, — занятие весьма утомительное, а иногда и невозмож¬ное. Поэтому предусмотрен механизм введения в программу контрольных точек
Контрольная точка — это логическое условие, которое вычисляется каждый раз при выполнении заданной строки программы. Если выпол¬няются условия прерывания, программа останавливается в контрольной точке. Далее мы можем вводить другие контрольные точки или применять пошаговую отладку с просмотром в окне Watch.
Чтобы добавить контрольную точку в программу, надо ввести имя фай¬ла, номер строки, в которой производится проверка, логическое условие, по достижению которого происходит остановка программы, и число проходов заданной строки, в которых данное логическое условие не просчитывается. Если логическое условие не задано, остановка возникает по достижению данной строки. Число проходов данной строки без анализа по умолчанию устанавливается равным 0, то есть анализ проводится, начиная с первого прохода. Предположим, в программе определения наибольшего общего де¬лителя Common.pas мы хотим проверить отношения, возникающие при кратности переменных Second и Common. Тогда в окне Add Breakpoint в по¬ле Condition мы вводим условие прерывания программы Second mod Com¬mon = 0. В поле FileName автоматически вносится имя файла, активного окна, а в поле Line number — номер строки, в которой находится курсор. В строку Pass count записывается число 0, так как мы хотим остановить про¬грамму уже при первом выполнении условия прерывания .
Все введенные в программу точки прерывания можно просмотреть и отредактировать в окне Breakpoints
Окно, открывающееся при выборе пункта меню Evaluate/Modify, так¬же, как окно Watch, позволяет просмотреть значение любой переменной или выражения, но при этом можно изменить значение переменной. Окно Evaluate/Modify может быть вызвано, если выполнение программы остановлено через механизм точки прерываний или при пошаговой отладке, и должно быть закрыто для продолжения работы программы . Это окно удобно использовать как «калькулятор». Для выполнения вспомога¬тельных вычислений достаточно ввести соответствующее выражение в по¬ле Expression и прочитать результат в поле Result.
Логические операторы и операторы цикла.
Отладка программ.
Укороченная форма оператора if
В операторе if часть, начинающаяся словом else, может отсутствовать. Часть, следующая за словом then, выполняется, если логическое условие, стоящее после слова if, имеет значение true. Если это логическое выражение имеет значение false, непосредственно выполняется оператор, следующий за if.
Наша программа может быть переписана с применением укороченной формы оператора if. Алгоритм сводится к последовательности проверок по¬падания переменной Аде в различные диапазоны значений. Приведем изме¬ненный текст программы:
Program Dialog; {расширенный диалог — второй вариант) const
Question =\\\' What is your name?\\\';
Rep(y1 =
\\\'Паскаль — прост, но первый компилятор Паскаля был написан на Паскале\\\';
Reply21 = \\\'Вас ждет удивительное путешествие\\\';
Reply22 = \\\'сквозь джунгли особенностей и возможностей языка\\\';
Reply3 =
\\\'Паскаль — разумный компромисс между желательным и эффективным\\\';
Reply4 = \\\'Паскаль академически элегантен\\\';
var
Name: string;
Age: byte;
begin
WriteLn(Question); ReadLn(Name); {Ввод имени} WriteLn(\\\'Hello,\\\ Name,\\\'!\\\'); {Вывод приветствия} WriteLn(\\\'How old are you?\\\'); {Вопрос о возрасте} ReadLn(Age); {Ввод возраста} if 12 < Age then WriteLn(Reply1 );
if (12 <= Age) and (Age < 20) then begin
WriteLn (Reply21);
WriteLn (Reply22) end;
if (20 <= Age) and (Age < 40) then WriteLn(Reply3);
if Age >= 40 then WriteLn(Reply4) end.
Алгоритмически этот вариант решения задачи с использованием сокра¬щенной формы оператора if существенно слабее первого варианта, в кото¬ром использовалась полная форма. При исполнении программы будут про¬верены все четыре условия, даже если при первой проверке найдено окончательное решение. Однако этот алгоритм не имеет вложенных друг в друга операторов и поэтому проще для понимания.
Оператор выбора case
Оператор if — один из наиболее часто используемых структурных элемен¬тов языка — обеспечивает ветвление алгоритма только на два направления. Вместе с тем ясно, что первый алгоритм решения задачиудачнее выражает ее сущность. Для реализации подобных алгоритмов необходим оператор множественного ветвления (выбора из нескольких ветвей ко¬манд). Таким оператором в Паскале является оператор выбора case.
Общий вид этого оператора:
case <селектор> of < альтернатива 1 > : < оператор 1>;
< альтернатива 2>:< оператор 2 >;
< альтернатива N >: < оператор N > else < оператор части Else> end;
Case и of — зарезервированные слова, которые являются отличитель¬ным признаком оператора множественного ветвления. Селектор — это пере¬менная или выражение порядкового типа. В зависимости от значения дан¬ного выражения или переменной происходит ветвление программы. После заголовка оператора идет перечисление различных альтернатив, по кото¬рым может выполняться программа. Альтернативы отделяются друг от друга точкой с запятой. Альтернатива состоит из метки, двоеточия и исполняемого оператора данной альтернативы. Используемая в операторе case метка может состоять из констант и диапазонов. Диапазоны значений в Паскале — это два крайних значения, написанные через двоеточие. Такая запись эквивалентна перечислению всех целых чисел в данном диапазоне. В общем случае метка может состоять из различных констант и диапазо¬нов, разделенных запятыми, например, допустима такая метка: 4, 8..10, 12, 14.. 16. В качестве селектора нельзя использовать логические результаты сравнения чисел (условия), поэтому использованные в операторах if нера¬венства здесь неприменимы.
Часть оператора case, состоящая из слова else и последнего альтернатив¬ного варианта, является необязательной, она выполняется в том случае, если вычисленный в программе селектор не соответствует ни одной из перечис¬ленных выше альтернатив. Если эта часть оператора case отсутствует, а се¬лектор не подходит ни под одну из альтернатив, то оператор case не выпол¬нит никаких действий. Завершается оператор case обязательным словом end;
Пример. С использованием оператора case наша программа приобрета¬ет следующий вид
Program Dialog;
const
Question =\\\' What is your name?\\\';
Replyl =
\\\'Паскаль — прост, но первый компилятор Паскаля был написан на Паскале\\\';
Reply21 = \\\'Вас ждет удивительное путешествие\\\';
Reply22 = \\\'сквозь джунгли особенностей и возможностей языка\\\';
ReplyS =
\\\'Паскаль — разумный компромисс между желательным и эффективным\\\';
Reply4 = \\\'Паскаль академически элегантен\\\';
var
Name: string;
Age: byte;
begin
WriteLn(Question); ReadLn(Name);
WriteLn(\\\'Hello,\\\ Name,\\\'!\\\');
WriteLn(\\\'Howold are you?\\\'); ReadLn(Age);
case Age of
0..11 :WriteLn(Reply1);
12..19 : begin WriteLn (Reply21); WriteLn (Reply22) end;
20..39: WriteLn(Reply3);
40..150:WriteLn(Reply4)
else WriteLn(\\\'Bbi ошиблись при вводе\\\')
end
end.
Переменная Age играет роль селектора. В зависимости от значения дан¬ной переменной происходит дальнейшее ветвление программы. В нашем примере в качестве альтернатив применяются диапазоны значений, по¬скольку нельзя использовать результаты сравнения чисел, как в предыду¬щей программе. Исходные неравенства заменены диапазонами. Например, проверка логического условия Age < 12 заменена проверкой принадлежно¬сти диапазону 0..11.
В заключение подчеркнем, что оператор case имеет существенные отличия от оператора if. Используемые для выбора альтернатив метки должны быть количественно определены до начала вычислений, поэтому в них могут применяться только константы, приведенные непосредственно или описанные в разделе описаний. Кроме того, оператор ограничен поряд¬ковыми типами данных, используемых для выбора альтернатив.
If Ready then Exam_ok := true;
Идеальная логика эквивалентности:
If Ready then Exam_ok := true else Exam_ok := false;
Управление вычислительным процессом, цикл for
В математических задачах часто встречается необходимость неоднократно¬го повторения одинаковых действий. Рассмотрим, например, вычисление суммы N членов гармонического ряда
Естественный алгоритм для решения такой задачи:
(1) обозначим искомую сумму S и присвоим ей значение, равное нулю;
(2) последовательно N раз вычислим слагаемые ряда и прибавим их к переменной S.
Многократные повторения одних и тех же действий можно выполнить с помощью конструкций, которые в программировании называются цикла¬ми. Повторяемые действия называются телом цикла. В Паскале существует несколько операторов цикла. Оператор for повторяет тело цикла заданное число раз. Он имеет следующие синтаксические формы:
for < счетчик цикла> := < первое значение> to < последнее значение> do
<тело цикла>;
for < счетчик цикла> := < первое значение>
downto < последнее значение> do <тело цикла>;
Счетчик цикла — это переменная одного из порядковых типов (из по¬рядковых типов мы пока знаем только целые и логический тип, в главе 7 понятие порядкового типа будет расширено). Назначение этой переменной очевидное — она хранит число повторений операторов тела цикла, сле¬дующего за словом do. Значение счетчика цикла изменяется автоматически от первого до последнего значения и увеличивается на единицу для первой формы записи (с оператором to) или уменьшается на единицу для второй формы записи (с оператором downto). Дополнительные изменения значе¬ния счетчика цикла в части, обозначенной здесь как <тело цикла>, запреще¬ны. В качестве первого и последнего значения могут использоваться кон¬кретные числа, другие переменные целого типа, вычисленные ранее, и вы¬ражения, имеющие значения целого типа.
Операторы тела цикла выполняются только один раз, если верхнее и нижнее значения счетчика совпадают. Если в операторе for .. to последнее значение счетчика цикла меньше первого, то тело цикла не выполняется ни одного раза. В операторе for.. downto цикл не выполняется, если последнее значение счетчика больше первого.
Программа с циклом for, которая вычисляет сумму N членов гармо¬нического ряда1:
Program Sum; {сумма N членов гармонического ряда}
var x: byte; {счетчик цикла}
s : real;{сумма ряда}
N : byte; {число членов ряда}
begin
Write(\\\'N = \\\'); ReadLn(N); {ввод числа членов ряда}
s := 0;{начальное значение суммы}
тогх:= 1 toNdos:=s+ 1/х; {подсчет суммы}
WriteLn( \\\'S = \\\ s); {вывод результата}
ReadLn {ожидание нажатия клавиши Enter}
end.
Оператор, следующий после слова do, может быть составным (пред¬ставлять собой группу операторов).
Пример. Найти нечетные и кратные трем числа в диапазоне от 30 до 60 включительно. Распечатать их в порядке убывания.
Условие нечетности целого числа — Odd(J). Условие кратности трем — равенство нулю остатка от деления i mod 3=0. Нас интересуют числа, удов¬летворяющие обоим условиям, то есть числа, для которых истинно Odd(i) and (i mod 3 = 0). Убывающий порядок следования чисел обеспечивает опе¬ратор for.. downto. Таким образом, программа будет иметь вид
Program Sample;
var i: byte;
begin
for i := 60 downto 30 do{цикл по убывающей от 60 до 30}
if Odd(i) and (i mod 3=0) then WriteLn(i) end.
В результате выполнении программы получим в столбик значения 57, 51,45,39, 33.
В приведенном примере многократно повторялся один оператор, одна¬ко во многих случаях необходимо повторять группу операторов. Вспомним, что говорилось в предыдущей главе о вложенности операторов друг в друга. Чтобы использовать вместо одного оператора группу, нужно эту группу превратить в один сложный оператор. Осуществляется это с по¬мощью так называемых «программных скобок» — операторов begin и end.
begin
<оператор1>;
< оператор 2>;
< оператор М> end;
Любая группа операторов, начинающаяся со слова begin и кончающаяся словом end в любой конструкции языка Паскаль может использоваться как один сложный оператор. Сложный оператор, в свою очередь, может иметь в своем составе сложные операторы следующего уровня вложенности и так да¬лее. Операторы begin и end подобны открывающим и закрывающим скобкам, и на их употребление накладываются те же ограничения, что и на обыкно¬венные скобки в арифметических выражениях: каждой «открывающей скоб¬ке» begin должна соответствовать «закрывающая скобка» end. Слово end не может предшествовать парному ему слову begin. При компиляции програм¬мы проверяется правильность расстановки скобок и дается сообщение об ошибке. Это сообщение не всегда попадает в то место, где действительно нужна скобка, поэтому не спешите вставлять операторы туда, куда предлага¬ет компилятор, а тщательно проанализируйте Вашу программу.
Пример. Имеется логическое выражение not a and b xor с. Требуется вы¬вести на печать значения логических переменных а, Ь, с, при которых дан¬ное выражение истинно. Мы предлагаем перебор всех возможных зна¬чений а, b, с с проверкой выполнения условия для каждого сочетания значений.
Program Sample;
Vara, b, с : boolean;
begin
for a := false to true do
for b := false to true do
for с := false to true do
if not a and b xor с then
begin
Write(\\\'a=\\\a);
Write(\\\'b=\\\b);
WriteLn(\\\'c=\\\c)
End
End.
В результате выполнения этой программы на экран будет выведено:
a =FALSE
b =FALSE
с =TRUE
a =FALSE
b =TRUE
с =FALSE
a =TRUE
b =FALSE
c =TRUE
a =TRUE
b =TRUE
с =TRUE
Программа состоит из одного сложного оператора for a := false to true do, в который вложены последовательно еще два оператора for и оператор if. Часть then последнего содержит сложный оператор, состоящий из трех простых операторов, охваченных программными скобками begin и end.
Циклы с логическими условиями
Введенный в предыдущей главе оператор цикла for обеспечивает выполне¬ние цикла заданное количество раз, однако часто циклические действия за¬канчиваются по условию, то есть выполняются до достижения определен¬ного результата. В Паскале есть два таких оператора цикла, отличающиеся тем, что в одном из них условие проверяется в начале цикла (while...do), а в другом — в конце цикла (repeat...until).
Оператор while.. do
Оператор цикла while (пока, в то время как) имеет вид:
While <логическое выражение> do <тело цикла>;
Цикл While обеспечивает выполнение тела цикла, следующего за сло¬вом do до тех пор, пока условие имеет значение true (истина). В качестве те¬ла цикла может использоваться простой или сложный оператор. Условие проверяется перед началом каждого выполнения тела цикла, поэтому, если до первого выполнения цикла условие имеет значение false (ложь), опера¬тор не выполняется ни одного раза (рис. 5.2).
Пример. Необходимо преобразовать значение угла в градусах к стандарт¬ному диапазону ±180° путем исключения полных оборотов окружности ±360°. Эта процедура может быть выполнена с помощью оператора цикла
While abs(Angle) > 180 do
if Angle > 0 then Angle := Angle — 360
else Angle := Angle + 360;
Оператор while в начале цикла проверяет, превышает ли угол по абсо¬лютному значению 180 градусов. Если это не справедливо, тело цикла не вы¬полняется. Если угол больше допустимого, начинается выполнение цикла.
Цикл состоит из оператора if. Допустим, угол равен —700. Тогда условие An¬gle > 0 в операторе if имеет значение false, при этом выполняется часть else оператора if, и угол получит значение —340. Снова происходит проверка условия выполнения цикла, и цикл выполняется второй раз, после чего угол равен 20. При третьей проверке условия выполнения цикла он заканчивает¬ся, поскольку условие его выполнения Abs(20)>180 приняло значение false.
Оператор repeat... until...
Оператор цикла repeat... until... (повторять до тех пор, пока) имеет вид Repeat <тело цикла> until -<логическое выражение>;
Принципиальное отличие оператора repeat...until от оператора while...do в том, что проверка условия производится не перед началом выполнения оператора, а в его конце, когда решается вопрос, повторить ли еще раз дей¬ствия. Поэтому тело этого цикла всегда выполняется по крайней мере один раз (рис. 5.3). Это важное отличие: приведенный для цикла while... do при¬мер реализовать с оператором цикла repeat... until невозможно без дополни¬тельных проверок и усложнений.
Второе отличие от оператора while...do — в логике завершения цикла. Цикл оператора repeat...until выполняется до тех пор, пока не станет истинным логическое выражение, следующее за словом until. Таким образом, использование логического выражения здесь имеет противоположный опе¬ратору while...do смысл. Здесь при истинности логического выражения (условия) цикл прекращается, а у оператора while...do при истинности ло¬гического выражения цикл продолжается.
Третье отличие в том, что оператор repeat...until имеет две части:
начальную и завершающую, которые охватывают группу операторов, со¬ставляющих тело цикла. Оператор while...do не имеет завершающей части и требует для организации тела цикла из нескольких операторов програм¬мных скобок begin-end. Для оператора repeat...until таких скобок не требу¬ется — их роль выполняют составные части оператора.
Пример. Найти методом подбора целочисленное решение Диофантова уравнения 5x-3y=1. В качестве первой пробы берутся единичные значения. Далее, если 5x-3y>1, то у увеличивается на 1, если 5x-3y<1, то на 1 увеличивается х.
Program Diophant;
var х, у: byte;
begin
x:=1;y:=1;
repeat
if(5*x-3*y)>1theny:=y+1;
if (5 * x - 3 * у) < 1 then х := х + 1 until(5*x-3*y)=1;
writeln(\\\'x= \\\x, \\\'y=\\\y) end.
В результате на экране получим х=2у=3.
Пример. С помощью цикла repeat...until можно организовать процедуру ввода данных с защитой программы от завершения при ошибочном наборе. Если тип данных не соответствует инициализируемой при стандартном вводе переменной (например, требуется ввести целое число, а набрано дробное), то возникает ошибка в выполнении программы, и мы должны снова запускать программу, и, естественно, повторить набор. Чтобы защи¬титься от последствий таких ошибок, можно использовать собственную процедуру ввода. Такая процедура должна отключить автоматическую про¬верку правильности ввода и проводить ее самостоятельно, причем при ошибке требовать повторного набора. Отключение проверки правильности ввода производится директивой компилятора {$!-} (Input/Output checking в окне настройки опций компилятора). После каждого действия по вводу-выводу специальная функция lOResult возвращает целое значение, соответ¬ствующее ошибкам ввода-вывода. Правильной работе ввода-вывода соответствует нулевое значение, возвращаемое этой функцией. Надежный ввод целого числа i выполняет фрагмент программы:
{$!-}{отключение проверки ввода-вывода} repeat
Write (\\\'Введите i = \\\'); {вывод на экран предложения для ввода}
ReadLn (i) {ввод целого числа}
until lOResult = 0; {lOResult — функция, равная 0, если нет ошибки} {$!+}{восстановление проверки ввода-вывода}
По крайней мере один раз вводится число; если при вводе была сделана ошибка, условие lOResult = 0 имеет значение false, и ввод будет повторяться до тех пор, пока он не будет сделан правильно.
Операторы Break и Continue
В последних версиях языка Borland Pascal введены два новых оператора, Break и Continue, применяемые внутри циклов. Они расширяют возможности использова¬ния циклов и улучшают структуру программ. В процессе выполнения тела цикла до его завершения могут возникнуть дополнительные условия, требующие завер¬шения цикла. В этом случае цикл может быть прекращен оператором Break.
Пример. Игра с ЭВМ в кости. Условия игры. Компьютер выдает себе или Вам случайные числа от 1 до 6. Задача — набрать максимальную сум¬му очков. Набравший больше 21 очка проигрывает, в любой момент один из игроков может отказаться от набора очков (спасовать).
Program Bones;
Const MaxSum = 1;{максимальное число очков}
var SumYour, {сумма очков игрока}
SumComp, {сумма очков компьютера}
count: byte; {очередные выпавшие очки}
reply: string;{ответ на запрос ЭВМ}
begin
SumYour := 0;
SumComp:=12; {начальное количество очков}
Randomize; {установка датчика случайных чисел}
repeat{начало общего цикла, организующего игру}
write (\\\'Бросить кость для Вас? (у/n)\\\');
repeat {Начало цикла для ввода корректного ответа} readln(reply){ввод ответа}
{выход из цикла — при корректном ответе}
until (reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply =\\\'n\\\') or (reply = \\\'N\\\');
{метание кости для игрока при положительном ответе}
if (reply = \\\'у\\\') or (reply = \\\'Y\\\') then {если ответ »да»}
begin Count := Random(6) + 1; {число очков игрока}
{Random(6) дает случайные числа от 0 до 5}
WriteLn( вам выпало \\\ count,\\\' очков.\\\'); {вывод выпавшего количества очков} SumYour := SumYour + count;{подсчет суммы очков игрока}
Writeln(\\\'y Вас всего \\\ SumYour,\\\' очков.\\\'); {вывод суммы очков}
if SumYour >= MaxSum then Вгеаk{прекращение игры при переборе} end;
{метание кости для компьютера — он играет,
если сумма очков меньше 18}
if SumComp < 18 then {если компьютер продолжает игру}
begin Count := Random(6) + 1;{число очков компьютера} WriteLn(\\\'мнe выпало \\\ count,\\\' очков.\\\'); {вывод количества очков} SumComp := SumComp + count; {подсчет суммы очков компьютера} Writeln(\\\'y меня всего \\\ SumComp,\\\' очков.\\\'); {вывод суммы очков}
if SumYour >= MaxSum then Break {прекращение игры при переборе} end
else begin {если компьютер пасует}
write(‘ пас. Будете продолжать? (у/п)’);{запрос о продолжении игры}
repeat
read(reply) until (reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply = \\\'n\\\') or (reply = \\\'N\\\');
if (reply = \\\'n\\\') or (reply = \\\'N\\\') then Break{прекращение игры
по взаимному согласию}
end
until false;{замыкание цикла метания костей}{подведение итогов}
if SumYour > MaxSum then writeln(\\\'Bы проиграли!\\\')
{перебор игрока}
else if SumComp > MaxSum then writeln(‘Я проиграл!\\\')
{перебор у компьютера}
else if SumYour < SumComp then writeln(\\\'Я выиграл!\\\')
{сравнение очков}
else if SumYour = SumComp then writeln (\\\'Ничья!\\\')
{равенство очков}
else writeln(\\\'Вы выиграли!\\\');
ReadLn
end.
Программа разбита на две основные части: метание костей и подведе¬ние итогов.
Первая часть реализует бесконечный цикл метания костей, ограничен¬ный оператором repeat ... until false. Выбор оператора repeat мотивирован тем, что должен быть сделан, по крайней мере, один ход игры. Цикл может быть прерван оператором Break при переборе очков любым из игроков и при отказе обоих партнеров от продолжения игры. Объединение трех усло¬вий в одно и использование его как завершающего условия цикла re¬peat... until усложнит алгоритм, а применение для прекращения игры опера¬тора Break алгоритм упрощает.
Цикл repeat... until с завершающим условием
(reply = \\\'у\\\') or (reply = \\\'Y\\\') or (reply =\\\'n\\\') or (reply = \\\'N\\\');
продолжается до тех пор, пока не будет введен допустимый символ (\\\'у\\\ \\\'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, которая изменяется при каждом прохождении цикла. Вы также увидите, что строка
if (First mod Common) = 0 then begin WriteLn(\\\'HCVl = \\\ Common); Break end
бывает подсвечена очень редко, так как для большинства чисел предыду¬щий оператор continue завершает данный проход цикла, и эта строка дей¬ствительно не выполняется.
Пошаговый проход программы в том случае, когда выполняется боль¬шое число циклов, — занятие весьма утомительное, а иногда и невозмож¬ное. Поэтому предусмотрен механизм введения в программу контрольных точек
Контрольная точка — это логическое условие, которое вычисляется каждый раз при выполнении заданной строки программы. Если выпол¬няются условия прерывания, программа останавливается в контрольной точке. Далее мы можем вводить другие контрольные точки или применять пошаговую отладку с просмотром в окне Watch.
Чтобы добавить контрольную точку в программу, надо ввести имя фай¬ла, номер строки, в которой производится проверка, логическое условие, по достижению которого происходит остановка программы, и число проходов заданной строки, в которых данное логическое условие не просчитывается. Если логическое условие не задано, остановка возникает по достижению данной строки. Число проходов данной строки без анализа по умолчанию устанавливается равным 0, то есть анализ проводится, начиная с первого прохода. Предположим, в программе определения наибольшего общего де¬лителя Common.pas мы хотим проверить отношения, возникающие при кратности переменных Second и Common. Тогда в окне Add Breakpoint в по¬ле Condition мы вводим условие прерывания программы Second mod Com¬mon = 0. В поле FileName автоматически вносится имя файла, активного окна, а в поле Line number — номер строки, в которой находится курсор. В строку Pass count записывается число 0, так как мы хотим остановить про¬грамму уже при первом выполнении условия прерывания .
Все введенные в программу точки прерывания можно просмотреть и отредактировать в окне Breakpoints
Окно, открывающееся при выборе пункта меню Evaluate/Modify, так¬же, как окно Watch, позволяет просмотреть значение любой переменной или выражения, но при этом можно изменить значение переменной. Окно Evaluate/Modify может быть вызвано, если выполнение программы остановлено через механизм точки прерываний или при пошаговой отладке, и должно быть закрыто для продолжения работы программы . Это окно удобно использовать как «калькулятор». Для выполнения вспомога¬тельных вычислений достаточно ввести соответствующее выражение в по¬ле Expression и прочитать результат в поле Result.