#9.1 Условный оператор IF (оператор ветвления if else) в Паскаль. Полная и неполная формы условного оператора. Вложенность
Primary tabs
Условный оператор -- что это такое
Условный оператор IF служит для программирования ситуаций выбора -- моделирования различных вариантов развития ситуации, с которым мы сталкиваемся в жизни и отражаем их в наших программах.
Структура условного оператора. Блочность
Условный оператор в общем виде состоит из трёх частей:
- Проверка логического значения
- Ветка истинности (обязательна) -- выполнится если логическое значение истинно (true)
- Ветка ложности (необязательна) -- выполнится если логическое значение ложно (false)
Сразу отметим, что логическое значение -- это фактически ответ на вопрос формата "да/нет" , напомним, что логическим типом значением обладают:
- логические литералы
- логические переменные
- и логические выражения
-- точно также как и любой простой тип данных может быть представлен литералами, переменными или выражениями из них.
В программном коде структуру условного оператора можно проиллюстрировать следующей схемой:
if (<логическое_значение>) then // проверка выражения и начало тела ветки истинности begin {здесь код, который выполнится, если логическое значение истинно} end else // начало ложной ветки (её тела) begin {здесь код, который выполнится, если логическое значение ложно} end; // конец ложной ветки и оператор ветвления
Например:
if ( 5 > 7) then // проверка выражения и начало тела ветки истинности begin writeln('5 > 7 верно'); writeln('5 > 7 верно'); end else // начало ложной ветки (её тела) begin writeln('5 > 7 неверно'); writeln('5 > 7 неверно'); end; // конец ложной ветки и оператор ветвления
-- в данном случае выполнится "ложная" ветка, так как $5 > 7$ возвращает результат false.
Точка с запятой перед else
Заметьте (см. примеры выше и ниже), что перед else точка с запятой не ставится.
Операторные скобки условного оператора
В предыдущем примере обратите внимание на операторные скобки, окружающие тела веток оператора ветвления -- begin и end необходимы, если в ветке выполняется более одной операции, если же в ветке содержится только одна операция, то операторные скобки не нужны.
Например для ситуации, изображённой на этой блок-схеме:
Эту же ситуацию можно проиллюстрировать кодом:
if ( 5 > 7) then // проверка выражения и начало тела ветки истинности writeln('5 > 7 верно') // конец ветки истинности else // начало ложной ветки (её тела) writeln('5 > 7 неверно'); // конец ветки ложности
-- здесь в обеих ветках только одна операция, а потому операторные скобки не нужны.
Полная и неполная формы оператора IF
Оператор IF в программе может быть представлен в следующих формах:
- Полная форма -- форма оператора if, в которой присутствуют обе ветки -- и then и else
- Неполная форма -- форма в которой присутствует только then.
Полная форма условного оператора IF
В полной форме оператора IF присутствуют обе ветки -- именно полную форму мы рассматривали выше, например:
if (a > 5) then b := 2 // в ветки истинности одно действие else begin b := 3; // в ветки ложности два действия a := 2; end.
-- здесь в качестве условия мы сравнивали переменную с числом, а потом описывали два сценария, один из которых выполнится в зависимости от значения условия.
В последнем примере кода, у нас в ветке истинности одна операция, а в ветки ложности 2 -- эту ситуацию можно изобразить на блок-схеме так (с каким-то предварительным действием до if):
Неполная форма условного оператора IF
В неполной форме условного оператора есть только сценарий истинности, ветка ложности же вообще не описывается, например:
if (a > 5) then b := 2 // в ветки истинности одно действие
-- в ветке ложности здесь вообще ничего нет, то есть если $a$ не больше $5$, то и никаких действий предпринято не будет.
На блок-схеме неполная форма оператора ветвления выглядит так:
-- правило использования операторных скобок действует и здесь: в данном же случае у нас только одна операция в ветке then, а потому begin и end не нужны.
Полная форма IF с пустой веткой then. Почему стоит избегать
Полная форма условного оператора с пустой веткой истинности, т.е. код вида:
if условие then else дейстия
-- является плохим стилем программирования, т.к. избыточен, его всегда можно переписать короче, "обратив" условие (т.е. сделав условие противоположным), тогда наш код примет вид:
if not(условие) then дейстия
Например, код:
var f : integer; begin write('Введите число : '); readln(f); if f = 0 then else // в ветке then ничего нет! writeln('Не равно нулю!'); readln(); end.
-- можно переписать так:
var f : integer; begin write('Введите число : '); readln(f); if not(f = 0) then writeln('Не равно нулю!'); readln(); end.
Или еще короче:
var f : integer; begin write('Введите число : '); readln(f); if f <> 0 then writeln('Не равно нулю!'); readln(); end.
Разбор задач
Пример №1 -- неполная форма IF
Сравните два числа, если первое больше второго, то выведите на экран "22" и затем отдельным вызовом writeln() число 555.
-- в этой задаче указано, что надо предпринимать какие-то действия только в одном случае ("если первое больше второго"), а значит будет использовать оператор ветвления в неполной форме:
var a,b: integer; begin writeln('vvedite dva celih chisla: '); readln(a, b); if (a > b) then // сравниваем begin writeln(22); writeln(555); end; readln(); end.
-- в ветке истинности здесь было две операции, а потому мы использовали для неё операторные скобки.
Пример №2 -- полная форма, по одному действию в каждой ветке
Сравните два числа, если первое больше второго, то выведите на экран "22", а иначе выведете на экран 'abc'.
-- в этой задаче указаны два альтернативных действия, а потому будем использовать оператор ветвления в его полной форме:
var a,b: integer; begin writeln('vvedite dva celih chisla: '); readln(a, b); if (a > b) then // сравниваем writeln(22) // если да else writeln('abc'); // если нет readln(); end.
-- обратите внимание, что перед else точка с запятой не ставится.
Пример №3 - логические выражения и оператор ветвления IF
Задача:
Коля набрал $k$ баллов, Миша $n$ баллов, а Петя $d$ баллов в ходе соревнований. Если:
- сумма баллов Коли и Миши больше $20$
- и сумма баллов Пети и Миши меньше $55$
--то тогда вывести в консоль сообщение о том, что ничья, в противном случае вывести сообщение, что победил Коля.
В этой задаче по условию требуется выполнение сразу двух требований, причем не одного либо другого из них, а двух одновременно, потому в логическом выражении для if мы будем использовать логическую операцию AND, тогда решение может выглядетьн например так:
// переменные для хранения баллов, набранных ребятами var k, n, d: integer; begin // сначала получаем данные от пользователя writeln('vvedite chislo ballov Koli: '); readln(k); writeln('vvedite chislo ballov Mishi: '); readln(n); writeln('vvedite chislo ballov Peti: '); readln(d); { далее начинаем проверку условий: используем "логическое И" (одновременность } if ((k + n > 20) AND (n + d < 55)) then writeln('Pobedila druzhba!') else writeln('Pobedil Kolya!'); readln(); end.
Пример №4 - вложенные условные операторы
Операторы могут вкладываться один в другой так, как как это показано на блок-схеме (на деле внутренний оператор вкладывается в одну из веток внешнего):
Рассмотрим задачу, решение которой будет соответствовать этой блок-схеме:
Получите от пользователя два целых числа, если первое больше второго, то выведите на экран их сумму, а затем их разность, иначе:
- сначала сравните их сумму с числом $25$, если она больше, то выведите на экран первое число, а если меньше, то только второе.
- затем выведите на экран второе число в квадрате
Реализуем решение в виде программы:
var a,b: integer; begin writeln('vvedite dva celih chisla: '); readln(a, b); if (a > b) then begin writeln('ih summa:', a + b); writeln('ih raznost:', a - b); end // перед else точка с запятой не ставится даже после end else begin { вложенные оператор условия -- первая вложенная операция в ветке ложности внешнего оператора } if ((a + b) > 25) then writeln('vivodim peroe:', a) else writeln('vivodim vtoroe:', b); // конец вложенного оператора ветвления и его ветки ложности (так как нет операторных скобок, то к ветке вложенности относится только одна операция) writeln(b*b); // вторая вложенная операция end; readln(); // удерживаем косоль end.
Пример №5 - вложенные условные операторы
Например задачу из более раннего примера:
Коля набрал $k$ баллов, Миша $n$ баллов, а Петя $d$ баллов в ходе соревнований. Если:
- сумма баллов Коли и Миши больше $20$
- и сумма баллов Пети и Миши меньше $55$
--то тогда вывести в консоль сообщение о том, что ничья, в противном случае вывести сообщение, что победил Коля.
можно было бы решить с помощью вложенных блоков условного оператора IF:
program Project1; var k, n, d: integer; // переменные для хранения баллов, набранных ребятами begin // сначала получаем данные от пользователя writeln('vvedite chislo ballov Koli: '); readln(k); writeln('vvedite chislo ballov Mishi: '); readln(n); writeln('vvedite chislo ballov Peti: '); readln(d); // далее начинаем проверку условий if ((k + n) > 20) then if ((n + d) < 55) then // вкладываем второе условие writeln('Pobedila druzhba!') else writeln('Pobedil Kolya!') else writeln('Pobedil Kolya!'); readln(); end.
-- обратите внимание, что begin и end не нужны для ветки истинности внешнего оператора, так как в него вложен лишь один if -- а остальные строки относятся к этому вложенному if.
ВАЖНО: В этом примере налицо дублирование кода, что является одним из признаков плохого стиля программирования. Более того, вложенные блоки в коде труднее понимать, поэтому:
Если можно не использовать вложенность -- не используйте её, лучше используйте более сложные условия с логическими операциями.
Пример №6 - жизненный выбор
То есть ситуацию, в которую попал богатырь на этой иллюстрации:
Можно запрограммировать следующим образом:
{Программа жизненного выбора} program qwe; var a: integer; // число, означающее выбор пользователя (богатыря) res: string; // его будущее begin writeln ('vvedite: 1 esli napravo, 2 esli pryamo, 3 esli nalevo '); readln(a); // читаем, куда пойдёт пользователь // далее определяем будущее if (a = 1) then res := ' konya poteryaesh ' else if (a = 2) then res := ' zhenat budesh ' else if (a = 3) then res := ' ubitum budesh ' else // если пользователь выбрал что-то другое res := ' buduchee ne izvestno '; writeln('otvet: ', res); readln(); end.
- по сути это тоже несколько вложенных один в другой операторов ветвления, причем вложение здесь на всех двух младших уровнях происходит в ветку ложности.
Пример №7 Вложение оператора if в неполной форме в оператор if в полной форме
При решении задач или при просмотре/анализе кода написанного не вами может возникнуть проблема понимания того, к какому именно then относится данный else, обычно такая проблема возникает в случае, если количество else не равно количеству then (если эти количества равны, то понять что во что вложено не трудно).
Рассмотрим пример (фрагмент кода), в котором есть подвох:
if (a > b) then if (a > c) then writeln('переменная а самая большая!') else // подразумеваем, что работает когда a<=b writeln('переменная a не больше b');
-- данный код отформатирован неверно, ведь он как бы показывает что else относится к первому then, в то время как Паскаль будет считать (всегда), что else относится к ближайшему then (не "отделённому" от этого else операторными скобками), итак, повторим эту идею ещё раз, назовём её правило "прикрепления" else:
В случае если число else не равно числу then (а это может быть только при вложенных блоках), else всегда "прикрепляется" (относится) к ближайшему "не изолированному" от него операторными скобками then.
Исходя из этого правила можно понять, что написанный выше код на самом деле имеет структуру:
if (a > b) then if (a > c) then writeln('переменная а самая большая!') else // !оказывается сработает если: c >= a >= b writeln('переменная a не больше b'); // значит это высказывание неверно!
-- но это значит, что уже неверна логика решения, из за того что на деле при подобной записи else относится к ближайшему then (мы показали это правильным форматированием и комментариями).
Но как же нам добиться задуманного в начале, т.е. той ситуации, когда в случае если a > b не верно, мы получили бы сообщение ""переменная a не больше b""?
Для этого нам придётся отделить ближайший then от else операторными скобками, то есть сделать так:
if (a > b) then begin if (a > c) then writeln('переменная а самая большая!') end else // работает когда a<=b writeln('переменная a не больше b');
Теперь ближайшим не изолированным операторными скобками от else словом then оказывается первое (то, где "if (a > b)"), а не второе (т.е. не то, где "if (a > c)") -- что мы и хотели изначально запрограммировать ;)
Пример №8 -- Интерактивный сценарий текстовой консольной игры
Пример сравнения строк для условного оператора:
var s, a: string; begin writeln('>>Куда пойдем? (домой/на улицу)'); readln(s); if (s = 'домой') then begin writeln('>>Вы пришли домой'); writeln('>>Будем делать уроки? (да/нет)'); readln(a); if (a = 'да') then writeln('>>Хороший выбор!') else writeln('>>Готовься к проблемам в школе'); end else writeln('>>Происходит что-то непонятное'); writeln('>>>>>>>>>Конец сценария<<<<<<<<<<<'); readln(); end.
Для лучшего понимания см. видео-разбор создания этого сценария.
Форматирование кода условного оператора
Мы уже начинали рассматривать вопрос форматирования кода, вернемся к нему в этом уроке. Это важно, т.к. теперь помимо блока тела программы мы знаем еще два блока:
- Блок ветки then ()
- и блок ветки else
-- оба этих блока требуют дополнительный (помимо базового отступа тела программы) отступ для кода, который находит в этих ветках.
Дополнительный отступ внутри блока равен базовому, например:
var a:integer; begin // нулевой отступ (ноль пробелов слева) readln(a); // одинарные отступ (два пробела слева) if (a > 2) then writeln('Больше'); // двойной отступ else writeln('Больше'); // двойной отступ readln(); // одинарный отступ end;
-- else пишется под тем if, которому он относится.
Для каждого вложенного блока отступ увеличивается на один базовый отступ, например:
var a:integer; begin // нулевой отступ (ноль пробелов слева) readln(a); // одинарные отступ (два пробела слева) if (a > 2) then // одинарный if (a > 5) then // двойной writeln('Больше!'); // тройной readln(); // одинарный отступ end;
-- в данном случае в тройном отступе у нас используется шесть пробелов (2x3=6)
Форматирование IF с операторными скобками
Если нам нужны операторные скобки (когда внутри ветки должно больше одного действия), то записываем открывающую под закрывающей:
var a:integer; begin // нулевой отступ (ноль пробелов слева) readln(a); // одинарные отступ (два пробела слева) if (a > 2) then // одинарный if (a > 5) then // двойной begin writeln('Больше'); // тройной writeln(' пяти!'); // тройной end else // двойной begin writeln('Не больше'); // тройной writeln(' пяти!'); // тройной end else // одинарный writeln('Не больше двух'); // двойной readln(); // одинарный отступ end;
-- открывающая операторная скобка begin располагается ровно под ключевым словом if или под else (в зависимости от того, к чему относится).
Видео-пояснения
Для этого урока есть следующие видео:
- IF, Условный оператор, оператор ветвления, разбор
- Когда работает Ветка ложности else в условном операторе IF для неравенств -- Часть 1
- Ветка ELSE и отрицание неравенств, пояснение с числовой прямой, "преобразование" строгих неравенств и нестрогие и обратно
Самостоятельная работа
Вопросы
- Для чего нужен оператор ветвления (условный оператор)?
- Какие ветви условного оператора вы знаете?
- Чем полная форма условного оператора отличается от неполной?
- Когда нужны операторные скобки в ветвях оператора IF, а когда нет?
Задачи
-
Сдавать/выладывать решение не обязательно:
Есть код:var a,b : integer; begin readln(a); if (a > 2) then writeln(a) else writeln(2); readln(); end.
Если он отфроматирован неправильно - исправьте это, и объясните для себя почему нужно исправить именно так.
-
Сдавать/выладывать решение не обязательно:
Есть код:var a, b, c, d : integer; begin writeln('vvedite a, b, c, d'); readln(a, b, c, d); if (a > b) then if (a > c) then begin if (a > d) then writeln ('Выбираем a'); writeln ('Может выбрали a'); end; readln(); end.
-- исправьте форматирование.
Подсказка: если непонятно как решить или хотите закрепить знания см. этот видео-разбор.
- Сравните два числа, если первое больше второго, то выведите на экран "12". (здесь нужно использовать неполную форму условного оператора)
- Сравните два числа, если первое больше второго, то выведите на экран "12", а если нет, то выведите на экран "888".
- Даны три целых числа: $A$, $B$, $C$. Проверить истинность высказывания: «Число $A$ находится между числами $B$ и $C$» -- выведите "да", если истинно и "нет" если ложно.
ПРИМЕЧАНИЕ: эта и следующая задача базируются на том, что мы уже решали (см. задачи в конце урока).
- Даны три целых числа: $A$, $B$, $C$. Проверить истинность высказывания: « Число $A$ и число $B$ больше 17, а $C$ > 7». -- выведите "да", если истинно и "нет" если ложно.
- Пользователь вводит два числа, найдите из них максимальное. (тут всё просто)
Примечание: если не просто или для лучшего понимания решения, см. этот видео-разбор.
-
Лишние операторные скобки.
Дан код:var a: integer; begin readln(a); if (a > 2) then begin writeln('2'); writeln('3'); end else writeln('0'); end.
-- есть ли здесь лишние операторные скобки? Объясните почему есть или нет и если есть, перепишите более кратким образом.
Примечание: для этой задачи можно сразу смотреть разбор (рассмотрен и этот код и еще пара примеров).
-
Дан код (ситуация "отрыва от блока"):
var a: integer; begin readln(a); if (a > 2) then writeln('*'); writeln('*'); readln(); end.
-- что с ним не так? Какие есть варианты по исправлению
Примечание: для этой задачи можно сразу смотреть разбор. -
Ситуация "неопределенности в ветке истинности" или "невозможности отделения else от if независимым кодом":
Дан код:var a: integer; begin readln(a); if (a > 2) then writeln('*'); writeln('*'); else writeln('#'); readln(); end.
-- это код не запустится? Почему? Какие есть варианты его переписать, чтобы он все-таки стал рабочим.
Примечание: для этой задачи можно сразу смотреть разбор. - Пользователь вводит три числа, найдите из них максимальное.
Решите тремя способами:
- С использованием логической операции and.
- С вложенными блоками (без and, все операторы if должны быть в полной форме).
(Если не получается - см. разбор решения) - Без вложенных блоков (без and) -- запомнив максимум из первых двух чисел в специальной переменной.
(Если не получается - см. разбор решения)
Указание: Сначала постарайтесь написать все три решения самостоятельно (хотя бы по 20 минут размышления на каждую задачу, но не более часа на каждую), если не получается (или после решения) также можно посмотреть это видео-пояснение.
- Пользователь вводит четыре числа, найдите из них максимальное -- решите через вложенные блоки if в полной форме (без использования логических операций).
Примечание: решение с помощью AND более удобно на практике, но для тренировки понимания тут мы решаем через вложенные блоки.
Подсказка: если не получается решить самостоятельно более 40 минут или для проверки/выясняния дополнительных моментов, см. этот видео-разбор решения.
- Коля набрал $k$ баллов, Миша $n$ баллов, а Петя $d$ баллов в ходе соревнований. Если:
- сумма баллов Коли и Миши больше $20$
- или произведение баллов Пети и Миши меньше $55$
--то тогда вывести в консоль сообщение о том, что ничья, в противном случае вывести сообщение, что победил Коля.
-
Есть программа, где стоит проверка на ввод пользователем числа 1 или числа 5:
var s:integer; begin writeln('Vvedite chislo 1 ili 5'); readln(s); if (s = 1) then writeln('soobchenie 1'); if (s = 5) then writeln('soobchenie 2'); readln(); end;
-- но сейчас код написан неоптимально и при каждом запуске выполняется 2 сравнения, при этом код можно переписать так, что при вводе одного из двух значений, которые приводят к выводу сообщения, сравнение будет выполняться только один раз.
Перепишите программу оптимальным образом.
Подсказка: если самостоятельно разобраться не получается, смотрите этот видео-разбор.
-
Есть программа:
var m,s:integer; begin writeln('Vvedite chislo M'); readln(m); writeln('Vvedite chislo M'); readln(s); if (s = 1) then writeln('soobchenie 1'); if (s = m) then writeln('soobchenie 2'); end;
-- при этом известно, что если
s
равно 1, то на экран должно вывестись только первое сообщение (а второе выводиться не должно), а еслиs
не равно 1, но равноm
, то второе (а первое выводиться не должно).
Но сейчас программа работает не так, исправьте это. -
Есть программа:
var z,s:integer; f:boolean; begin readln(z); f := z > 5; s:=1; if (z=s) and (f=false) then begin writeln();// делаем перенос строки z:=0; s:=s+1;//но увеличиваем кол-во строк end; if (z=s) and (f=true) then begin writeln(); // делаем перенос строки z:=0; s:=s-1;//но уменьшаем кол-во строк end; end.
-- в двух условных операторах действия частично совпадают, а значит наблюдается дублирование кода. Перепишите код так, чтобы дублирования не было.
Подсказка: используйте вложенные блоки
if()
.
Если идей нет, смотрите разбор решения. -
Изучите код:
var s, t:integer; f, b:boolean; begin f := true; b := false; if (f=true) then t:=1 else t:=2; if (b=false) then s:=3 else s:=4; end.
-- блоки условий можно переписать более кратко, без использования сравнения
= true
или= false
, с сохранением той же логики работы программы.Подсказки:
- оператор if итак неявно сравнивает значение логического выражения в скобках с true (и принимает решение, какую именно ветку then или else выполнить)
- для второго if в коде выше потребуется исползование оператора Not.
Если подсказки не помогают и/или для лучшего понимания - см. этот видео-разбор.
-
У вас есть код:
var f : integer; begin write('Введите число : '); readln(f); if f = 0 then else writeln('Не равно 0!'); readln(); end.
-- который сообщает пользователю, что число не равно нулю, если это действительно так, или в обратной ситуации не делает вообще ничего.
Задача: Перепешите это код в неполной форме (без использования else).
Примечание: если не получается решить, или для лучшего понимая решения см. этот видео-разбор.
-
У вас есть три числа (три переменные) найдите их медиану.
Примечание: это условие давалось как простая разминочная задачка для собеседования в Яндекс.
-
Решать по желанию, сдавать на проверку не обязательно:
Запрограммируйте историю:
- 1) Вы дома, пойдем в лес или в центр города?
- 2) Если пойдем в лес то будем жечь костер или кататься на лыжах?
- 3) Если будем кататься на лыжах, то по кругу или с гор (придумайте последния выбора)
- 4) Если будем жечь костер - то будем ли что-то готовить или просто (придумайте последствия выбора)
- 5) Если выбрали поход в центр - пойдем ли в кино или погуляем по центру
- 6) Если пойдем в кино будет смотреть исторический фильм или комедию (придумайте последствия выбора)
В качестве примера см. пример №8 выше, и/или видео-разбор.
-
Была программа
// Вариант 1: var a: integer; begin writeln('Введите а:'); readln(a); if (a > 5) then writeln('a') else writeln(5); readln(); end.
Ее переписали так:
// Вариант 2: var a: integer; begin writeln('Введите а:'); readln(a); if (a > 5) then writeln('a') else if (a < 5) then writeln(5); readln(); end.
Вопрос: изменилось ли что-то в поведении программы, если да, то почему? Объясните письменно, можно прокомментировать код, если изменения в логике есть
Форматирование кода условного оператора (необязательный блок)
Самостоятельное программирование
Источники (что ещё почитать)
- Урок 8. Блок-схема оператора if: http://learnpascal.ru/operator-if/blok-s...
- Log in to post comments
- 87557 reads
Evgeny1618
Sat, 05/14/2022 - 22:23
Permalink
Урок 9 задача 12
Есть программа:
Тут решение с помощью полной формы условного оператора невозможно посколько s всегда будет равно 1 не зависимо от m. Стоит ли тут избавиться от s := 1 и вводить в консоли ее?
Pages