§2. Условный оператор

В рассматриваемых ранее задачах на программирование процесс вычисления был линейным, то есть программа не должна была выполнять разные действия в зависимости от того, какие данные ей ввели. Теперь рассмотрим задачи с ветвящимся алгоритмом.

Пример задачи

Ввести номер года. Вывести слово YES, если год високосный, и NO, если он - не високосный.

Решение

По условию очевидно, что в зависимости от входных данных программа должна будет выполнить один из двух операторов вывода: Writeln('YES') или Writeln('NO'). При этом написать в программе нам придётся оба, а вот выполняться должен будет только один из них. Для того чтобы реализовывать подобные ветвления алгоритма, в языке Pascal существует условный оператор. В общем виде он выглядит следующим образом:

if логическое выражение

   then оператор

   else оператор

Слова if, then и else являются служебными зарезервированными словами языка. Работает эта конструкция так: сначала вычисляется логическое выражение, стоящее после if. Если получилось значение true, то выполняется оператор, стоящий после слова then, а если получилось значение false, то выполняется оператор, стоящий после слова else.

Обратите внимание, что внутри условного оператора нет никаких точек с запятой, поскольку он является единой конструкцией, а точка с запятой - это разделитель между операторами. Для удобства чтения и отладки программ принято условие записывать на одной строке, а ветви then и else начинать с новой строки, однако это не является синтаксическим правилом языка.

В качестве примера условного оператора рассмотрим решение задачи, поставленной выше. Год считается високосным, если он делится нацело на `400`, или если он  делится нацело на `4`, но не делится нацело на `100`. Проверять делимость мы уже умеем, поэтому осталось только записать это условие в виде программы:

var y:integer;

begin

  write('Введите номер года ');

  readln(y);

  if(y mod 400=0)or(y mod 4=0)and(y mod 100<>0)

   then writeln('YES')

   else writeln('NO');

end

По грамматике языка после слов then и else должен стоять только один оператор языка. То есть запись if x>0 then x:=4; y:=0 else z:=9; является синтаксически неверной. А как быть, если всё-таки нужно выполнить более одного оператора? Для таких случаев в языке Pascal предусмотрен составной оператор, который позволяет превратить группу операторов в один. Выглядит он следующим образом: сначала записывается служебное зарезервированное слово begin, далее - интересующая нас последовательность операторов через точку с запятой, а в конце пишется служебное зарезервированное слово end. В отличие от конца программы, точка после этого слова не ставится. Слова begin и end называют операторными скобками. Запишем правильную версию условного оператора, приведённого выше: if x>0 then begin x:=4; y:=0 end else z:=9;

Обратите внимание на следующий тонкий момент: если требуется выполнить более одного оператора в ветке then, и при этом мы забудем написать операторные скобки, то это является синтаксической ошибкой, и программа просто не будет работать. Если же забыть написать операторные скобки в ветке else, то программа работать будет, но не так, как предполагалось.

Рассмотрим пример: 

Пример задачи

if x>0 then y:=9 else z:=8; c:=5;

В этом примере условный оператор заканчивается после z:=8;  в то время как оператор c:=5; является следующим оператором программы и выполняется независимо от результата сравнения `x` с нулём. Если же написать операторные скобки, то присваивание в `c` числа `5` произойдёт только в случае x<=0.

Ещё один тонкий момент заключается в том, что в ветке else в качестве оператора может стоять и пустой оператор. Рассмотрим следующий пример.

пример Задачи

Вводятся `3` целых числа – `a`, `b`, `c`. Требуется в переменную `a` записать минимальное из этих чисел, в `b` – среднее и в `c` – максимальное.

Решение

Алгоритм решения этой задачи такой: сначала сравним значения переменных `a` и `b`, если значение `a` - больше, поменяем их местами. После этого сравним значения переменных `a` и `с`, и если значение `a` - больше, поменяем их местами. После этих двух сравнений в переменной `a` гарантированно окажется наименьшее из трёх чисел. Осталось сравнить переменные `b` и `c`, и в случае, когда в переменной `b` находится большее значение, поменять их местами.

Очевидно, что в этом алгоритме у нас три сравнения, следовательно, три последовательных условных оператора. При этом в каждом из них какие-то действия (поменять местами значения двух переменных) нужно выполнять только в ветке then, в ветке else (например, если в первом сравнении в переменной a находится уже более маленькое число, чем в переменной `b`) никаких действий выполнять не нужно. Рассмортим код программы: В этом случае, грамматика языка программирования позволяет вообще не записывать даже слово else. Такая конструкция называется сокращённой формой условного оператора.

var a,b,c,x:integer;

begin

  writeln('введите три целых числа ');

  readln(a,b,c);

  if a>b then begin x:=a; a:=b; b:=x end;

  if a>c then begin x:=a; a:=c; c:=x end;

  if b>c then begin x:=b; b:=c; c:=x end;

  writeln(a,b,c);

  readln

end.

Как видно из примера, грамматика языка программирования позволяет вообще не записывать даже слово else, в случае, когда там не надо выполнять никаких действий. Такая конструкция называется сокращённой формой условного оператора. При использовании сокращённой формы условного оператора, если при вычислении логического выражения получилось значение false, то управление передаётся на следующий оператор программы.

Использование сокращённой формы условного оператора порождает проблему неоднозначности интерпретации логики действий программы в случае вложенных условных операторов. Рассмотрим следующий пример:

if x>0

 then if y>0

   then z:=0

 else c:=7;

Вопрос состоит в том, какой из двух условных операторов является полным, а какой - сокращённым. К сожалению, ответ на этот вопрос существует только в виде дополнительного семантического правила языка программирования. Принято, что ветка else всегда относится к ближайшему if без else (по принципу правильной скобочной системы). То есть, в нашем случае внутренний условный оператор является полным, а внешний - сокращённым. Если же мы хотим добиться обратной логики действий (чтобы внешний условный оператор был полным), нам необходимо заключить внутренний условный оператор в операторные скобки. Выглядеть это будет следующим образом:

if x>0

 then begin

  if y>0

   then z:=0

  end

 else c:=7;