Технологии и методы программирования — на главную

Ветвления. Условный оператор. Множественный выбор

Условный оператор if-else, логические выражения и операторы, вложенные ветвления, конструкция else if, оператор switch и разобранные задачи.

лекции 2 ч
лаб. 4 ч
СРС 6 ч

Пока все наши программы выполнялись строго сверху вниз. Ветвление — первая конструкция, которая позволяет программе выбрать одно из нескольких продолжений в зависимости от данных. Вместе с ним появляется новый класс ошибок: программа компилируется, запускается и молча делает не то. В этом уроке — и сама конструкция, и типичные способы ошибиться в ней.

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

Условный оператор соответствует естественным понятиям «если» и «иначе». Если выполнено условие, нужно выполнять одно действие, а иначе — другое. По-английски «если» звучит как if, а «иначе» — как else.

Пусть перед нами стоит задача вывести модуль числа, не пользуясь функцией abs. В примерах этого урока мы пишем не программы полностью, а только те команды, которые непосредственно выполняются, — остальное дописывается само:

int a;
cin >> a;
if (a > 0) {
    cout << a;
} else {
    cout << -a;
}
cout << endl;

Первые две строки мы уже понимаем: создание переменной и её считывание. В следующей строке записано «если a больше нуля». Если условие выполнено, выполняются действия в фигурных скобках после if; если не выполнено — команды в скобках после else. Выполнение программы разветвляется, и будет выполнена ровно одна из двух ветвей. После окончания блока else программа продолжается как обычно.

Можно попробовать решить ту же задачу без else — двумя отдельными if:

int a;
cin >> a;
if (a > 0) {
    cout << a;
}
if (a < 0) {
    cout << -a;
}
cout << endl;

Запустите с вводом 0 — программа не напечатает ничего, кроме перевода строки. Ни одно из двух условий не выполнено, и ни одна ветвь не сработала. Поменяйте ввод на -5 — работает. Дефект проявляется на одном значении из миллиарда, и именно поэтому его легко не заметить: на всех «интересных» данных программа верна.

Отсюда практическое правило

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

Логические выражения

Условный оператор должен выглядеть как if (<логическое выражение>) { … }. Сначала пишется if, затем в круглых скобках — логическое выражение, затем в фигурных скобках команды, которые должны быть выполнены.

Логическое выражение — выражение, которое может принимать значения «истина» (true) и «ложь» (false). Простейшая его форма:

<арифметическое выражение> <сравнение> <арифметическое выражение>

Например, в выражении x + y < 3 * y первое арифметическое выражение — x + y, знак сравнения — < (меньше), второе арифметическое выражение — 3 * y.

Знаки сравнения:

ОписаниеЗнак
равно==
не равно!=
меньше<
больше>
меньше или равно<=
больше или равно>=

= вместо ==

Очень часто при сравнении на равенство возникает ошибка: вместо двух значков «равно» пишется один. Это корректная программа, но делает она совсем не то, чего от неё ждут. Напишем программу, которая считывает два числа и выводит Yes, если они одинаковые, и No в противном случае:

int a, b;
cin >> a >> b;
if (a = b) {
    cout << "Yes";
} else {
    cout << "No";
}
cout << endl;

Программа печатает Yes, хотя 3 и 5 разные. Причина: a = b — это не сравнение, а присваивание. Оно записывает 5 в a, и значением всего выражения становится записанное значение, то есть 5. Ненулевое число в условии — это «истина». Проверьте с вводом 3 0 — там будет No, и снова не потому, что числа равны.

Это ровно тот случай, ради которого включают предупреждения

g++ с флагом -Wall на такой код ругается: suggest parentheses around assignment used as truth value. Компилятор не может знать, ошиблись вы или так и хотели, но он обязательно скажет, что место подозрительное. Ошибку класса «программа компилируется и работает неправильно» иначе приходится искать вручную — а компилятор находит её за доли секунды. Читайте предупреждения.

Есть и приём, облегчающий борьбу с этой ошибкой: писать выражение слева от сравнения, а переменную — справа. Тогда опечатка перестаёт компилироваться: a * 2 = b внутри if — ошибка, а b = a * 2 ошибку не выдаст и будет работать неправильно.

Вложенные инструкции

Внутри блока инструкций могут находиться другие ветвления. По заданному количеству глаз и ног нужно отличить кошку, паука, морского гребешка и жучка. У морского гребешка бывает более сотни глаз, а у пауков их восемь; также у пауков восемь ног, а у морского гребешка их нет совсем. У кошки четыре ноги (и длинный хвост), а у жучка — шесть, но глаз у обоих по два.

int eyes, legs;
cin >> eyes >> legs;
if (eyes >= 8) {
    if (legs == 8) {
        cout << "spider";
    } else {
        cout << "scallop";
    }
} else {
    if (legs == 6) {
        cout << "bug";
    } else {
        cout << "cat";
    }
}
cout << endl;

Попробуйте все четыре варианта ввода: 8 8, 100 0, 2 6, 2 4.

Если вложенных условных операторов несколько, то к какому из них относится else, компилятор понимает по количеству закрывшихся фигурных скобок.

Отступы — это не оформление

В примере правильно расставлены отступы, и именно поэтому его структура видна с первого взгляда. Правило: открылась фигурная скобка — со следующей строки добавляется один отступ; в строке с закрывающей скобкой один отступ убирается.

Программы с правильными отступами приятнее читать и понимать, а работы с неправильными отступами не принимаются на проверку. Причина не в строгости: при вложенных ветвлениях отступ — единственное, по чему человек видит, какая ветвь к какому условию относится.

Ещё в этой программе хорошо названы переменные. Называйте их так, чтобы был понятен смысл: лучше всего английские слова (не транслит!), их стандартные сокращения, отдельные слова через подчёркивание, длина до 10–12 символов. Если переменная означает «количество слов», подойдёт word_cnt.

Логические операторы

Иногда нужно проверить условие сложнее, чем сравнение двух чисел. Задача похожа на предыдущую: программе даётся количество глаз и ног, и она должна пугаться, если это паук — с восемью глазами и восемью ногами.

int eyes, legs;
cin >> eyes >> legs;
if (eyes == 8 && legs == 8) {
    cout << "AAAAA!!!";
}
cout << endl;

Логический оператор && — это «и»: условие верно, если и левое, и правое логические выражения истинны одновременно. Кроме него есть:

  • || — «или»: верно, если истинно хотя бы одно из выражений;
  • ! — «отрицание», унарная операция, ставится перед выражением.

Порядок действий в логических выражениях: сначала отрицания, затем все арифметические операции, затем все «и», и только потом все «или». На порядок можно влиять скобками — и лучше ставить их, чем помнить приоритеты.

Високосный год

В России есть Новый год и старый Новый год: первый отмечается по григорианскому календарю, второй — по юлианскому. В юлианском календаре високосность проверяется просто: если номер года делится на 4, год високосный.

int year;
cin >> year;
if (year % 4 == 0) {
    cout << 366;
} else {
    cout << 365;
}
cout << endl;

Чтобы проверить любое число на делимость, считают остаток от деления и сравнивают его с нулём.

Теперь задача сложнее — количество дней по григорианскому календарю. Правило такое: год високосный, если его номер делится на 4, но не делится на 100, либо делится на 400.

Логическое выражение получается длинным, и его можно разбить на части, сохранив промежуточное значение в переменной. Для результата логического выражения существует тип bool: переменная такого типа хранит true или false.

int year;
cin >> year;
bool mod400 = year % 400 == 0;
if (year % 4 == 0 && year % 100 != 0 || mod400) {
    cout << 366;
} else {
    cout << 365;
}
cout << endl;

В переменной mod400 хранится «истина», если остаток от деления номера года на 400 равен нулю. Проверьте программу на трёх годах: 2024 (високосный), 1900 (не високосный, хотя делится на 4) и 2000 (високосный, потому что делится на 400). Если выражение не помещается на экран, его можно разбить на несколько строк — программа продолжит работать нормально.

Если вы боитесь перепутать приоритеты, поставьте скобки для уверенности. Наше выражение можно записать так:

if ((year % 4 == 0 && year % 100 != 0) || mod400) {

Конструкция «иначе-если»

Иногда нужно выбрать больше чем из двух вариантов. Пусть нам звонит кто-то из друзей и предлагает заняться чем-нибудь. Числом 1 обозначим друга Ваню, который зовёт играть в футбол, числом 2 — друга Сашу, который зовёт вместе учить C++. Если звонит кто-то другой, мы сидим дома и смотрим сериал.

int who_call;
cin >> who_call;
if (who_call == 1) {
    cout << "Football!!";
} else if (who_call == 2) {
    cout << "C++!!!!!11";
} else {
    cout << "Show";
}
cout << endl;

Конструкция else if имеет смысл «иначе-если». Дойти до сравнения с двойкой можно только в случае, если уже произошло сравнение с единицей и мы пошли по ветви «иначе». Последний else выполнится только после того, как число сравнилось и с единицей, и с двойкой, и ни одно сравнение не было верным. Так можно обработать сколько угодно вариантов поведения программы.

Вредные советы

Советы из этой рубрики принесут много ошибок в программе, но мы обязаны сказать правду.

Первый вредный совет. C++ умеет рассматривать арифметические выражения как логические: 0 считается «ложью», любое другое число — «истиной». Задачу про високосный год можно решить так:

int year;
cin >> year;
if (year % 4) {
    cout << 365;
} else {
    cout << 366;
}
cout << endl;

Обратите внимание, что ветви пришлось поменять местами: year % 4 равно нулю, то есть «ложь», ровно для високосных годов.

Второй вредный совет похож на первый, только в обратную сторону: результат логического выражения можно использовать в арифметическом, считая «ложь» нулём, а «истину» единицей. Пусть нужно вывести 1, если число чётное, и ноль иначе:

int a;
cin >> a;
cout << (a % 2 == 0) << endl;

Почему это вредные советы

Оба приёма работают, оба короче обычной записи, и оба ухудшают читаемость и повышают вероятность ошибки. Употреблять такие конструкции — плохой тон. Первый приём вдобавок легко перевернуть: в примере выше ветви поменялись местами, и заметить это на глаз тяжело. Знать о них надо — чтобы понимать чужой код, — а писать так не надо.

Оператор switch

Когда вариантов много и все они — сравнение одной величины с константами, цепочка else if становится громоздкой. Для такого случая есть оператор множественного выбора switch:

int who_call;
cin >> who_call;
switch (who_call) {
    case 1:
        cout << "Football!!" << endl;
        break;
    case 2:
        cout << "C++!!!!!11" << endl;
        break;
    default:
        cout << "Show" << endl;
        break;
}

Это та же программа, что и в разделе про else if. Как она устроена:

  • switch (выражение) — вычисляет выражение один раз;
  • case <константа>: — метка: с неё начнётся выполнение, если значение совпало;
  • break — выйти из switch;
  • default: — куда идти, если не совпало ни с чем; необязателен, но нужен по той же причине, по которой нужен else.

Ограничения оператора: в switch можно подавать только целые или символьные значения (int, char, bool, перечисление), а метки case должны быть константами. Ни double, ни строку, ни диапазон вида case x > 5 в switch не подать — для них остаётся else if.

Провал сквозь case

Самая частая ошибка со switch — забытый break. Метки case — это именно метки, а не отдельные блоки: выполнение начинается с совпавшей метки и идёт дальше по тексту, пока не встретит break или конец switch.

int n;
cin >> n;
switch (n) {
    case 1:
        cout << "один" << endl;
    case 2:
        cout << "два" << endl;
    case 3:
        cout << "три" << endl;
    default:
        cout << "это всё" << endl;
}

При вводе 2 печатаются три строки: два, три, это всё. Попробуйте 1 и 5. Затем расставьте break и запустите снова.

Иногда провал полезен — когда несколько значений обрабатываются одинаково:

switch (month) {
    case 12:
    case 1:
    case 2:
        cout << "зима";
        break;
    case 3: case 4: case 5:
        cout << "весна";
        break;
}

Здесь метки идут подряд без команд между ними, и это общепринятая запись «или-или». Но если между метками есть команды и break пропущен, почти наверняка это ошибка, а не замысел.

Задачи с решением

Наибольшее из двух чисел

Условие. Даны два целых числа. Выведите значение наибольшего из них. Если числа равны, выведите любое из них.

int a, b;
cin >> a >> b;
if (a >= b) {
    cout << a;
}
else {
    cout << b;
}
cout << endl;

Обратите внимание на >=, а не >. С обычным «больше» программа тоже была бы верна — при равенстве сработала бы ветвь else и напечатала b, что условие разрешает. Но >= точнее выражает намерение: «если a не меньше, печатаем a».

Сравнение двух чисел

Условие. Даны два целых числа. Программа должна вывести единицу, если первое число больше второго, двойку, если второе больше первого, или ноль, если они равны.

int a, b;
cin >> a >> b;
if (a > b) {
    cout << 1;
}
else if (a < b) {
    cout << 2;
}
else {
    cout << 0;
}
cout << endl;

Три взаимоисключающих случая — три ветви. Третье условие писать не нужно: если a не больше и не меньше, значит равно. Это тот же приём, что и с else в задаче про модуль: последнюю группу не проверяют, а покрывают else.

Сколько совпадающих из трёх

Условие. Даны три целых числа. Определите, сколько среди них совпадающих. Программа должна вывести одно из чисел: 3 (если все совпадают), 2 (если два совпадают) или 0 (если все числа различны).

int a, b, c;
cin >> a >> b >> c;
if (a == b && a == c) {
    cout << 3;
}
else if (a != b && a != c && b != c) {
    cout << 0;
}
else {
    cout << 2;
}
cout << endl;

Разберите порядок ветвей: сначала проверяется самый сильный случай («все три равны»), потом самый слабый («все различны»), а «ровно два совпадают» оказывается всем остальным и достаётся else. Попробуйте поменять первые две ветви местами — ответ не изменится. А теперь попробуйте написать условие для «ровно двух» напрямую и сравните, насколько оно длиннее.

Проверьте все три случая: 5 5 5, 4 4 7, 1 2 3.

Задание к лабораторной

Вариант 1 (из рабочей программы). Пользователь вводит два числа, программа выводит сообщение, какое из чисел наибольшее. Предусмотрите случай равенства.

Вариант 2 (из рабочей программы). Программа вычисляет сумму скидки в зависимости от суммы продажи:

Сумма продажиСкидка
0—50005 %
5000—1500012 %
15000—2500020 %
свыше 2500030 %

В отчёте отдельно опишите, как вы поступили с границами: в таблице РП значение 5000 попадает сразу в две строки, и решение об этом принимает автор программы.

Вариант 3 (из рабочей программы). Даны два целых числа. Выведите значение наименьшего из них.

Вариант 4 (из рабочей программы). Дано натуральное число. Определите, является ли год с данным номером високосным. Если год является високосным, выведите YES, иначе NO. Год является високосным, если его номер кратен 4, но не кратен 100, а также если он кратен 400. Проверьте программу на годах 2024, 1900, 2000, 2023.

Вариант 5 (из рабочей программы). Даны три целых числа. Определите, сколько среди них совпадающих: 3 (все совпадают), 2 (два совпадают) или 0 (все различны).

Вариант 6. Программа читает номер месяца (1—12) и печатает название времени года. Решите задачу оператором switch, используя подряд идущие метки case. Предусмотрите сообщение об ошибке для неверного номера.

Как оценивается лабораторная

Работа сдаётся преподавателю очно: сайт её не принимает и не оценивает. Шкала и показатели ниже — из рабочей программы дисциплины, раздел 7.

Показатели оценки

  1. степень соответствия выполненного задания поставленным целям, задачам и требованиям;
  2. оформление, структурирование и комментирование лабораторной работы;
  3. уникальность выполнения работы (отличие от работ коллег);
  4. успешные ответы на контрольные вопросы.

Баллы

  • 86–100
    отлично— оформление соответствует требованиям, критерии выдержаны, защита всего перечня контрольных вопросов.
  • 66–85
    хорошо— оформление соответствует требованиям, критерии выдержаны, защита только до 85 % контрольных вопросов.
  • 51–65
    удовлетворительно— оформление соответствует требованиям, критерии выдержаны, защита только до 51 % контрольных вопросов.
  • 0–50
    неудовлетворительно— оформление не соответствует требованиям, критерии не выдержаны, защита менее 51 % контрольных вопросов.

Проверьте себя

Викторина по теме

Вопрос 1 из 10
один вариант

Операция = = относится к

Ссылки на литературу

  1. Воробьев, Г. А. Основы программирования на C++ : учебно-методическое пособие. — Липецк : Липецкий ГПУ, 2022. — 89 с. — ISBN 978-5-907461-84-0. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
  2. Калитвин, В. А. Введение в программирование на C++ : учебное пособие. — Липецк : Липецкий ГПУ, 2023. — 84 с. — ISBN 978-5-907655-86-7. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
  3. Широбокова, С. Н., Кацупеев, А. А., Сулыз, А. В. Программирование на языке C++ для лабораторных занятий : учебное пособие. — Новочеркасск : ЮРГПУ, 2020. — 104 с. — ISBN 978-5-9997-0725-3. Лань : электронно-библиотечная система (дата обращения: 15.01.2026). Доступ: для авторизованных пользователей
Мой прогресс

Содержание