Обычно операторы в программе выполняются в том порядке, в каком они записаны. Оператор перехода прерывает естественный порядок выполнения программы и указывает, что дальнейшее выполнение должно продолжаться, начиная с оператора, помеченного меткой, указанной в операторе перехода. Пример записи оператора перехода: go to N: .
С помощью одного оператора присваивания можно создавать достаточно сложные расчетные программы, однако реализовать абсолютное большинство алгоритмов, просто последовательно выполняя операторы присваивания, невозможно. Постоянно приходится изменять порядок выполнения последовательности вычислений в зависимости от определенных условий. Эти условия записываются в виде логических выражений и всегда принимают одно из двух значений — true или false (истинно или ложно). При этом происходит разветвление программы — выполнение в дальнейшем может продолжиться с разных операторов.
Синтаксис условного оператора примерно одинаков во всех языках программирования — он представляет собой конструкцию:
если условие истинно
то выполнить оператор-1
иначе выполнить оператор-2
После ключевого слова IF (если) следует условие, и если оно истинно, то выполняется оператор или блок операторов, следующих за ключевым словом THEN (то), если же оно ложно, то выполняется оператор или блок операторов, следующих за ключевым словом ELSE (иначе).
Синтаксис условного оператора
Бейсик |
Паскаль |
Си++ |
IF условие THEN |
if условие then |
if (условие) |
Примеры.
Бейсик:
IF A <> 0 THEN А = О ELSE А = -1 END IFПаскаль:
if а <> 0 then а := О else a := -1;Си++:
if( а <> 0 ) а = О else а - -1;Вторую часть условного оператора, выполняющуюся в случае, если условие ложно, всегда можно опускать.
IF х < 0 THEN у = х / 2 х = 1 END IFПаскаль:
if х < 0 then begin y := х / 2; x := 1; endСи++:
if( x < 0 ) { у = x / 2; x = 1; };
Структурные операторы строятся из специальных зарезервированных слов, логических выражений и других операторов. Каждый такой оператор явно или неявно содержит одну или несколько логических проверок.
Оператор if..then... называется условным оператором и имеет вид
if expression1 then statewntl;
где выражение expression1 является логическим.
Логическое выражение принимает одни из двух (возможных значений — True (истина) или False (ложь), Часто в роли логического выражения выступает какое-то условие, которое может выполняться либо нет. В первом случае его значение — «истина», и во втором — «ложъ». Программирование логических выражений
мы будем разбирать позже. Если логическое выражение expressionl принимает значение «истина, то выполняется оператор statement1. В противном случае выполняться будет оператор, следующий за данным логическим оператором.
Следует отметить, что, согласно формальным правилам языка, в условном операторе после then допускается применение только одного оператора. Но в практике программирования чаще возникают ситуации, когда при выполнении условия в логическом выражении expression1 следует выполнить нескольку операторов языка. Решается эта проблема, как уже были сказано, применением составного оператора. Операторы if...then... можно вкладывать друг в друга, так как конструкция
if expression2 then statement2;
также является оператором и может заместить оператор statement1:
if expression1 then if expression2 then statement2;
Пример условного оператора:
if Centigrade = 0 then Write('Температура замерзания воды');
Этот оператор является полной версией условного оператора и имеет вид
if expression then statement1 else statement2;
Выполняется данный оператор следующим образом: если выражение expression принимает значение «истина», то управление передается на оператор statement1, если же нет, то на оператор statement2. Приведем ошибочный вариант данного оператора:
if expression ther statementl else; statement2;
Здесь первая точка с запятой завершает оператор if...then...e1se, не выполняя никаких действий в случае else, а затем (в любом случае) выполняется оператор statement2.
Оператор
if expression1 then
if expression2 then
statement2
else
statement1;
допускает двоякую интерпретацию. Первый вариант соответствует последовательности операторов
if expression1 then begin
if expression2 then
statement2
else
statementl;
end;
Второй вариант:
if expression1 then begin
if expression2 then
statement2
end;
else
statementl;
Компилятор Паскаля всегда выбирает первый из приведенных вариантов -каждому else соответствует ближайший предшествующий if. Если требуется реализация второго варианта, можно использовать операторные скобки begin...end. В общем случае, чтобы четко определить, что чему подчинено, используйте begin...end аналогично круглым скобкам в арифметических выражениях.
Пример условного оператора;
if Two = 2 then
Writeln(‘Два равно 2’)
else
Writeln(' В чем дело? ');
Как уже отмечалось, условные операторы можно вкладывать друг в друга, программируя таким образом сложные ветвления. Рассмотрим следующий оператор:
if expression_1 then
statement_l;
else
if expression_2 then
statement_2
else if expression_3 then
statement3
…
else if expression_n then
statement_n;
Вначале вычисляется значение логического выражения expression_l. Если оно истинно, выполняется оператор statement_1, если же это значение ложно, вычисляется значение выражения expression_2. В том случае, когда полученное значение истинно, будет выполняться оператор statement_2, при значении «ложь» будет вычисляться выражение expression_3 и т. д.
Если выражения expression_i независимы, то есть вычисление их значений в любом порядке дает одни и тот же результат для каждого из них, имеет смысл располагать их в таком порядке, чтобы выражение с наибольшей вероятностью, принимающее значение «истина», стояло на первом месте, выражение, принимающее значение «истина» с меньшей вероятностью, — на втором и т. д. Это уменьшит время выполнения данного фрагмента программы, особенно если вложенный оператор появляется в цикле, который выполняется многократно.
Пример вложенных условных операторов:
if Two = 2 then
if One = 1 then
Writeln(‘Единица равна 1’)
else
Writeln(‘Единица не равна 1’)
else
if Three = 3 then
Writeln(‘Три равно 3’)
else
Writeln ('Три не равно 3');
Для ситуаций, где имеется несколько (три и более) альтернатив, больше подходит оператор case. Этот оператор называется оператором выбора и имеет следующий вид:
case expression of
values_l: statement_l;
values_2: statement_2;
values_n: statemen_n;
else statement;
end;
Рассмотрим элементы этой конструкции. Во-первых, это три зарезервированных слова: case, of и end. Между case и of находится выражение expression, принимающее значение, которое, возможно, имеется в одном из списков значений, находящихся слева от двоеточий. Данное выражение называется селектором оператора case. Каждый оператор, идущий за двоеточием, отделяется от следующего списка значений точкой с запятой. Ветвь else, отвечающая всем не перечисленным значениям выражения expression, необязательна. При выполнении данного оператора вначале вычисляется значение селектора. Затем выбирается тот список значений, которому принадлежит полученное значение, и выполняется соответствующий оператор.
В списках значений оператора case допустимыми являются типы переменных, называемые скалярными (они будут обсуждаться позже), включая целые и исключая вещественные типы. Любое заданное значение селектора может входить в список значений неоднократно, но выполняться будет лишь первая подходящая ветвь. Замечу, что «стилистически» такая конструкция выглядит не очень изящно. Если значение селектора отсутствует в списках значений, ни одна из альтернатив выполняться не будет. В этом случае выполняется ветвь else оператора case или (если эта ветвь отсутствует) следующий за case оператор.
Поясним применение данного оператора следующим примером. Пусть необходимо преобразовать целое число N в зависимости от величины остатка от его деления на 17 следующим образом:
если N mod 17 = 0, то N := 0;
если N mod 17 = 1 или 6, то N := -. N;
если N mod 17 = 2, 3 или 5, то N := 2xN;
если N mod 17 = 4, то N := 3x N;
во всех прочих случаях N : 5xN.
Решение этой задачи на Паскале выглядит следующим образом:
case N mod 17 of 0: N := 0; 1,6: N := -N; 2,3,5: N := 2*N; 4: N := 3*N; ' else N := 5*N; end;В данном примере селектором является выражение N mod 17. Кроме того, имеются 4 списка значений и ветвь else.
С помощью условных операторов и операторов присваивания теоретически можно реализовать сколь угодно сложный алгоритм. Однако на практике при необходимости организовать обработку тысяч элементов массива (например, присвоить каждому элементу начальное значение) вручную набирать тысячу операторов присваивания крайне тяжело.
Поэтому в языках программирования имеются средства для организации повторных вычислений, называемые операторами цикла. Они бывают двух видов: с фиксированным числом повторений и условные операторы цикла.
Каждый оператор цикла состоит из заголовка цикла, определяющего число повторений, и тела цикла — повторяемого оператора или блока операторов.
Первый вид оператора цикла (цикл с предусловием)
При решении задачи примерно в половине случаев заранее известно, сколько раз понадобится выполнить тело цикла. Так бывает, как правило, при обработке массивов, размер которых всегда или известен заранее, или легко определяется.
Заголовок такого оператора состоит из трех частей — инициализации переменной-счетчика или параметра цикла (присваивания ей начального значения), определения конечного значения счетчика, по достижении которою тело цикла надо выполнить в последний раз, и приращения счетчика, определяющего, на сколько будет меняться значение счетчика после каждого выполнения тела цикла.
Синтаксис оператора цикла |
|
Бейсик |
FOR счетчик = начальное_значение ТО конечное_ значение STEP приращение |
Паскаль |
for счетчик := начальное_значение to конечное_значение do |
Си++ |
for( счетчик – начальное_значение; условие_завершения; счетчик = счетчик + приращение) |
Примеры инициализации тысячи элементов массива а. Бейсик:
FOR I = 1 ТО 1000 A(I) = О NEXTПаскаль:
for i := 1 to 1000 do a[i] := 0;Си++:
for( i = 0; i < 1000; i = i + 1 ) a[i] = 0;В последнем примере счетчик будет принимать значения от 0 до 999, потому что нумерация элементов массива в Си++ начинается с нуля.
Синтаксис оператора цикла |
||
Бейсик |
Паскаль |
Си++ |
DO WHILE условие группа операторов LOOP |
while условие do |
while( условие ) |
Бейсик:
DO WHILE A > В А - А - 0.01 LOOPПаскаль:
while a > Ь do а := а - 0.01;Си++:
while ( a > b ) а = а - 0.01;
При использовании условных операторов цикла программиста подстерегает одна опасность. Как показывает практика, достаточно легко сделать ошибку и неверно задать условие окончания цикла, которое всегда будет истинным, — при этом тело цикла станет выполняться бесконечно. Подобная ситуация называется зацикливанием.
Например:
а = 0; b = 1;
while( a < b )
a = a - 0.01;
Так как исходное значение переменной а меньше, чем значение переменной b, и это значение будет только уменьшаться, то подобный цикл никогда не закончится.
В некоторых случаях программисты специально применяют подобный трюк, чтобы организовать бесконечный цикл, в котором будут приниматься и обрабатываться внешние сообщения (события). Тогда использование условного оператора цикла может выглядеть так:
while true do
begin / / тело цикла
end;
Контроль за выходом из цикла при наступлении определенного события при этом полностью возлагается на программиста.
В Бейсике есть специальная форма оператора цикла, позволяющая явно описывать такие бесконечные циклы:
DO
тело цикла
LOOP
Оператор цикла является важнейшим оператором и имеется и большинстве современных языков программирования (а сама идея цикла возникла еще в XIX веке!). Цикл позволяет многократно выполнить некоторое множество действий, задаваемых операторами, составляющими его тело. В Паскале имеется несколько разновидностей оператора цикла. Начнем с оператора цикла с предусловием. Данный оператор имеет вид
while expression do statement;
При выполнении этого оператора вначале вычисляется значение логического выражения expression. Если это значение истинно, выполняется оператор statement, затем значение выражения проверяется вновь и т. д., до тех пор, пока выражение не примет значение «ложь». Если выражение принимает значение «ложь» при первой же проверке, то оператор statement не выполняется вообще. Особо отмечу частный случай:
while True do statement;
Здесь оператор statement будет выполняться бесконечно. Пример оператора цикла с предусловием:
while Counter < 10 do begin
Write('Значение счетчика равно', Counter);
Wnteln;
Counter := Counter + 2;
end;
Оператор цикла с постусловием имеет вид
repeat statement until expession;
Здесь вначале выполняется оператор statement, а затем вычисляется значение логического выражения expression. Процесс повторяется, пока выражение expression принимает значение «ложь». Как только это значение станет истинным, выполнение цикла прекращается. Оператор statement может быть любым, в том числе и составным оператором:
begin
statement_l;
statement_2;
...
statement_n;
end;
В цикле repeat…until… операторные скобки begin_end могут быть опущены. Таким образом, в общем случае оператор repeat…until… имеет следующий вид:
repeat
statement_l;
statement_2;
...
statement_n;
until expession;
Точка с запятой перед зарезервированным словом until необязательна. В приведенном ниже частном случае
repeat
statement_l;
statement_2;
statement_n;
until False;
цикл выполняется бесконечно. Еще раз следует обратить внимание на то, что если в операторе while…do… проверка выполняется в начале цикла, то в цикле repeat...until... проверка выполняется в последнюю очередь, и тело цикла в любом случае выполняется хотя бы один раз.
Вот пример цикла с постусловием:
repeat
Write('Значение счетчика равно', Count);
Writeln;
Count := Count + 2;
until Court = 10;
Третий вариант оператора цикла — цикл со счетчиком. Можно считать, что есть две очень похожих друг на друга разновидности цикла со счетчиком.
for j := expression1 to expression2 do statement;
Здесь переменная j, называемая управляющей переменной цикла for, является произвольным идентификатором, который объявляется как переменная любого скалярного типа (к скалярным относятся целый, символьный, булев и перечислимые типы).
При выполнении оператора for сначала вычисляется значение выражения expression1, затем вычисляется значение выражения expression2, далее управляющая переменная цикла последовательно пробегает все значения от expression1 до expression2. В том случае, когда значение expression оказывается больше значения expression2, тело цикла не будет выполняться вовсе. Эти значения остаются неизменными в ходе выполнения всего цикла for. Рассматриваемый вариант цикла for эквивалентен следующей последовательности операторов:
j := expressionl;
k := expression2;
while j <= k do begin
statement;
inc(j);
end;
в предположении, что при каждом выполнении оператора statement не изменяются значения j и k.
Оператор for вида for j:=expression1 to expression2 do statement; неэквивалентен последовательности операторов
begin
j := expression1;
while j <= expression2 do
begin
statement;
j := j + 1;
end;
end;
потому что выражение expression2 может изменяться при каждом выполнении оператора statement к цикле while.
В теле цикла for следует избегать операторов, изменяющих значение управляющей переменной j. Несмотря на то, что использование подобных конструкций не приводит к ошибкам компиляции, они потенциально опасны и могут приводить к неприятным последствиям. Рассмотрим пример:
sum := 0;
for k := 1 to 100 do
begin
sum := sum + Sqr(k); k := k + 2;
end;
Этот фрагмент программы является попыткой просуммировать n2 по всем целым значениям вида n = (3*k+1), лежащим в диапазоне от 1 до 100. Здесь допущена ошибка реализации алгоритма, так как управляющая переменная k изменяется в составном операторе, управляемом той же переменной k. Правильной будет конструкция следующего вида:
sum := 0;
for k := 0 to 33 do sum := sum + Sqr(3*k + 1);
или
sum := 0; k := 1;
repeat
sum := sum + Sqr(k); k := k + 3;
until k > 100;
После выполнения цикла for значение управляющей переменной становится неопределенным.
Вариант for_downto...do... цикла for аналогичен циклу for...to…do... за исключением того, что в нем управляющая переменная на каждом шаге выполнения не увеличивается, а уменьшается на единицу:
for j := expression1 downto expression2 do statement;
Подводя итоги, для применения циклов можно сформулировать следующие рекомендации:
Иногда бывает удобно проводить проверку на возможный выход из цикла где-нибудь и его середине, а не в начале или конце. Такой? выход из цикла обеспечивается процедурой Break модуля System, которая прерывает выполнение самого внутреннего вложенного цикла, будь то for, while или repeat. Указанный модуль подключается к программе автоматически, если в этом есть необходимость. Пример:
while true do
begin
statement1;
if expression then Break;
statenent2;
end;
Следуем также упомянуть процедуру Continue, которая прерывает выполнение тела самого внутреннего цикла for, while или repeat и передает управление на его заголовок, так что начинается выполнение очередной итерации цикла.
Управление порядком выполнения программы может происходить не только с помощью условных операторов и операторов цикла, но и при возникновении исключений — ситуаций в программе или операционной системе, требующих немедленного реагирования. Например, при выполнении оператора присваивания и вычислении выражения произошло деление на ноль. Программа остановилась, так как не знает, что ей делать дальше, — ведь получено ошибочное значение. Чаще всего выполнение программы просто прекращается по ошибке, но современные системы разработки позволяют программисту явно контролировать возникновение самых разных исключений (они еще называются исключительными ситуациями, требующими немедленного вмешательства) и указывать, какие операторы следует выполнять при их возникновении.