Изучаем C++. Часть 3. Ветвление и условные конструкции
Разбираемся, как сделать программу на C++ полезнее, чем обычный калькулятор.
Это третья часть из серии «Глубокое погружение в C++». В прошлый раз мы научились работать с данными: переменными, константами и операциями с ними. Сегодня поговорим о более сложных аспектах языка.
Полезные программы умеют выполнять различные инструкции в зависимости от обстоятельств. Например, браузер отображает сайт, если всё успешно загрузилось, или сообщает об ошибке, если что-то пошло не так. Это называется ветвлением.
Ветвление в программе может быть таким:
Нет ни одной IT-сферы, где не нужно проверять какие-то условия, чтобы выполнить определённые действия: от робототехники до игр. Давайте разбираться, что такое условные конструкции, какими они бывают и как ими пользоваться.
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Логические операции в C++
Есть тип данных bool (булев тип), в котором хранится значение либо истина, либо ложь. Благодаря ему и возможно ветвление.
Чтобы поместить в переменную булева типа какое-то значение, мы можем самостоятельно написать его (true или false) или ввести какое-либо логическое утверждение:
Дальше компьютер проверяет правдивость такого утверждения и возвращает результат.
Для написания таких утверждений необходимы логические операторы:
Вот несколько примеров:
При попытке вывести значение переменной result программа выведет 1 или 0.
ЗаданиеПопробуйте самостоятельно написать несколько логических утверждений и посмотреть, что покажет программа.
Конструкция if
Условная конструкция if позволяет выполнять инструкции только в том случае, если данное логическое утверждение верно. Записывается эта конструкция так:
После того как программа проверит утверждение, она выполнит (или не выполнит) всё, что написано внутри фигурных скобок. Вот пример программы с ветвлением:
Программа работает корректно, но такой код сложно читать из-за большого количества условных конструкций. Чтобы упростить запись, можно использовать оператор else (иначе).
Else используется, чтобы сказать компьютеру, какие инструкции нужно выполнить, если проверяемое утверждение было ложным.
Если нужно проверить несколько условий, то воспользуемся оператором else if.
Программа сначала проверит первое условие и, если оно ложно, будет проверять следующие за ним else if. Если ни одно из условий не было верным, выполняются инструкции внутри else, поэтому оно всегда должно стоять в конце.
Вы можете размещать условные конструкции внутри других условных конструкций:
Есть и более короткие варианты записи. Например, если должна быть выполнена только одна инструкция, то фигурные скобки лучше опустить:
Запись можно сократить ещё сильнее, если вы используете условие, чтобы указать значение для переменной:
Получается запись вида:
Задание Попробуйте написать как можно больше условных конструкций, перед тем как продолжать чтение статьи, — эта тема очень важна.
Булева алгебра
Иногда нам необходимо проверить сразу несколько условий. Например, чтобы выйти на улицу, нужно убедиться, что нет дождя или у нас есть зонт. Чтобы завести машину, нам нужны ключ и бензин в баке.
Такие условия называются сложными, а для их проверки применяется булева алгебра. В C++ для этого есть следующие операторы:
Вот простая таблица, в которой показаны вводные данные и результаты их логических умножений и сложений:
| A | B | && (И) | || (ИЛИ) |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 |
С оператором НЕ всё ещё проще:
| A | !A (НЕ A) |
|---|---|
| 1 | 0 |
| 0 | 1 |
Вот несколько примеров использования таких операторов:
Урок №64. Операторы условного ветвления if/else
Обновл. 13 Сен 2021 |
На этом уроке мы рассмотрим операторы условного ветвления if/else, а также то, как их можно использовать.
Условные ветвления if/else
Самыми простыми условными ветвлениями в языке С++ являются стейтменты if/else. Они выглядят следующим образом:
if (выражение)
стейтмент1
if (выражение)
стейтмент1
else
стейтмент2
Использование нескольких операций в ветвлениях if/else
Оператор if выполняет только одну операцию, если выражение является true, и также только одну операцию else, если выражение — false. Чтобы выполнить несколько операций подряд, используйте блок стейтментов:
Неявное указание блоков
Если программист не указал скобки для блока стейтментов if или else, то компилятор неявно сделает это за него. Таким образом, следующее:
if (выражение)
стейтмент1
else
стейтмент2
Будет выполняться как:
if (выражение)
<
стейтмент1
>
else
<
стейтмент2
>
По сути, это не имеет значения. Однако начинающие программисты иногда пытаются сделать что-то вроде следующего:
Программа не скомпилируется, и в итоге мы получим ошибку, что идентификатор a не определен. А произойдет это из-за того, что программа будет выполняться следующим образом:
В этом контексте становится понятным, что переменная a имеет локальную область видимости и уничтожается в конце блока, в котором выполняется её инициализация. И, когда мы дойдем до строчки с std::cout, переменная a уже перестанет существовать.
Связывание стейтментов if
Стейтменты if/else можно использовать в связке:
Вложенные ветвления if/else
Одни стейтменты if могут быть вложены в другие стейтменты if:
Обратите внимание, в программе, приведенной выше, мы можем наблюдать потенциальную ошибку двусмысленности оператора else. К какому if относится оператор else: к внешнему или к внутреннему?
Дело в том, что оператор else всегда относится к последнему незакрытому оператору if в блоке, в котором находится сам else. Т.е. в программе, приведенной выше, else относится к внутреннему if.
Чтобы избежать таких вот неоднозначностей при вложенности операторов условного ветвления, рекомендуется использовать блоки стейтментов (указывать скобки). Например, вот та же программа, приведенная выше, но уже без двусмысленности:
Оператор ветвления
Содержание
Общее описание
Виды условных инструкций
Существует две основные формы условной инструкции, встречающиеся в реальных языках программирования: условный оператор (оператор if) и оператор многозначного выбора (переключатель, case, switch).
Условный оператор
Встречаются следующие формы условного оператора:
Условный оператор с одной ветвью
Реализация в Pascal
Реализация в C++
C и C++ (а вслед за ними и Java, C#, PHP и множество других языков) имеют условный оператор, структурно аналогичный Паскалю. Отличие состоит в том, что условие должно быть записано в круглых скобках, а вместо ключевых слов begin и end используются фигурные скобки <> :
Nemerle
Переключатель
Конструкция переключателя имеет несколько (две или более) ветвей. Переключатель выполняет одну заданную ветвь в зависимости от значения вычисляемого ключевого выражения. Принципиальным отличием этой инструкции от условного оператора является то, что выражение, определяющее выбор исполняемой ветви, возвращает не логическое, а целое значение, либо значение, тип которого может быт приведён к целому. В некоторых языках допускается использовать в переключателе выражения некоторых типов, не приводимых к целому (например, текстовые строки).
Прототипом современной синтаксической конструкции была используемая в старых языках программирования команда перехода по вычисляемой метке. В этой команде указывалось выражение-селектор, возвращающее целое значение, и набор меток. При выполнении команды вычислялось выражение, а его значение использовалось как номер метки (в списке команды), на которую производился переход. Такие конструкции были, например, в языках программирования Фортран и Бейсик. Привлекательной стороной конструкции является её достаточно высокая эффективность: для определения нужной ветви (метки перехода) не требуется последовательно сравнивать результат выражения-селектора со многими занчениями, достаточно записать в память массив команд безусловного перехода с нужными адресами, чтобы при выполнении команды вычислять нужный элемент непосредственно из значения выражения. При этом скорость выполнения команды не зависит от количества меток. В современных языках реализация оператора-переключателя также часто выполняется в виде таблицы перехода, состоящей из команд безусловного перехода на соответствующие фрагменты кода. Вычисляемое выражение преобразовывается в значение сдвига по таблице перехода, определяющее выполняемую команду. В языках, где выражение-селектор может иметь нецелое значение, напрямую вычислить нужную ветвь конструкции переключателя можно далеко не всегда, поэтому в них используются другие методы оптимизации исполнения.
Например, в языке Си синтаксис команды следующий:
Синтаксис команды-переключателя Си унаследован множеством языков, но семантика его не всегда аналогична Си. Например, в Java конструкция имеет точно такой же вид, но любая ветвь, кроме default, обязана заканчиваться на break — отсутствие этого ключевого слова является синтаксической ошибкой. В C# допускается использовать выражение-селектор строкового типа и соответствующие метки.
Особенности вычисления логических выражений
На логику исполнения программы с условными операторами может существенно влиять принятая в языке логика вычисления условных выражений. Если утверждение представляет собой сложное логическое утверждение, к примеру «f(x) > 0 и g(y) > 0», существует две стратегии
Второй вариант является наиболее распространённым для промышленных языков (в частности, для Алгола, Фортрана, С++, С, Java, JavaScript, ECMAScript, JScript, C#). В этих языках действует жёсткое правило: «Логическое выражение всегда вычисляется слева направо и его вычисление останавливается сразу же, как только результат всего выражения становится определённым». Это означает, что если выражение состоит из нескольких подусловий, объединённых оператором «И» (AND), то вычисление выражения прекратится, как только одно из подусловий окажется ложным (так как «ложь AND любое значение» в результате всегда даёт «ложь»), и, наоборот, если несколько подусловий объединены оператором «ИЛИ» (OR), вычисление прекратится после первого же истинного подусловия, поскольку в этом случае всё выражение истинно, независимо от дальнейших вычислений. А вот выражение, содержащее оператор «Исключающее ИЛИ» (XOR) неполному вычислению не поддаётся, поскольку в нём одно из значений не может определить результат вычисления всего выражения.
Выбор именно такой логики исполнения связан с тем, что она позволяет упростить логические выражения, в которых используются зависимые элементы. Классическим примером подобной ситуации является поиск в массиве:
Алгоритм, реализуемый программой, совершенно очевиден, но в реализации есть одна тонкость (см. строку, помеченную восклицательными знаками): условие цикла состоит из двух частей, связанных оператором AND. Первое подусловие проверяет, не вышел ли индекс i за пределы массива, второе — не равен ли текущий элемент массива искомому значению. Если массив не содержит искомого значения, то после проверки последнего элемента значение переменной i увеличится на единицу. Если после этого будут вычисляться ОБА подусловия, то второе приведёт к ошибке — ведь i уже вышло за границы массива. Чтобы избежать этого эффекта, пришлось бы записать gоиск примерно в следующем виде:
Как видим, пришлось искусственно задать порядок вычисления условий выхода и ввести дополнительную переменную. Именно для того, чтобы избежать подобных трюков и введено неполное вычисление логических выражений.
Конструкция ветвления в C++ и операторы if/else: правильное применение
Любая компьютерная программа подразумевает ветвление. Это ситуация, когда нужно выбрать тот или иной вариант в зависимости от условий. Например, если некий результат вычислений меньше 100 — нужно вывести сообщение «Результат не дотягивает до сотни». Если больше — выводится «Результат превышает сотню и потрясающе выглядит».
Для этого в C++ есть так называемые операторы ветвления — особые команды, которые показывают компилятору, что можно выбирать из тех или иных вариантов. Сегодня мы поговорим о том, какие есть операторы ветвления в C++, как они функционируют, также приведем примеры их использования.
Конструкция ветвления в C++. Операторы условного ветвления if/else
Сфера применения операторов ветвления в C++ и других языках программирования крайне широка. С их помощью реализуется очень много задач, они позволяют изучить логику программирования и понять, как это все работает. Грубо говоря, эти операторы универсальны по своему значению и применяются везде.
Нажали одну кнопку — система выдала определенный результат на основании данных на входе. Нажали другую — система выдала иной результат на основании тех же входных данных. Не нажали, но прошло определенное время по таймеру — будет третий результат.
Само собой, это умозрительный пример ветвления, но, надеюсь, идею вы поняли. Давайте перейдем к практической стороне реализации.
Блок-схема простейшего варианта ветвления выглядит следующим образом:

Здесь все просто и понятно: если выражение принимает положительное значение — выполняется одна инструкция. Отрицательное — другая. В качестве наглядного примера возьмем вот такую небольшую программу на С++. В ней надо ввести любое произвольное число, которое может быть меньше 100, или же больше/равно 100.
Здесь, как видим, реализован простейший вариант — проверка идет по принципу больше/меньше. Помимо этого, никаких проверок. Ниже мы рассмотрим вариант, когда программа будет различать более точные вводные данные — меньше, больше или равно.
Само собой, эта простейшая программа не включает проверку корректности символов — туда можно ввести любые данные — цифры, буквы, символы из ASCII и так далее. Однако корректные результаты получить можно будет только на цифрах.
Использование нескольких операций в ветвлениях if/else
Бывает так, что нужно выбрать не из двух, а из большего числа вариантов — трех и так далее. Давайте посмотрим, как это можно сделать:
Мы добавили новое условие, которое позволяет уточнить результат — число строго больше 100 или строго равно ему. Как видите, ничего сложного. Это также называется связыванием стейтментов.
Вложенные ветвления if/else
Еще один способ сломать себе мозг осуществить выбор в программе — вложенные ветвления. Суть понятна из названия — внутри одной пары if/else есть другая или другие пары. Выглядит это логически примерно так:

Скриншот с bookflow.ru
Строго говоря, это ничем не отличается от обычного ветвления, разве что только для выполнения внешнего условия сначала должно выполниться внутреннее (вложенное).
И вот здесь надо быть внимательным, поскольку количество if и else должно быть одинаковым — как и фигурных скобок. Иначе говоря, оператор else всегда относится только к последнему незакрытому оператору if в том же блоке.
Для улучшения читабельности кода желательно использовать те самые фигурные скобки, чтобы не запутаться. Они не окажут влияния на работу программы или компилятора, однако помогут визуально улучшить код сам по себе.
Неявное указание блоков if/else
Таким образом, блок кода…
…превращается в такую конструкцию:
С точки зрения компилятора ничего не поменялось — логика та же самая, только изменилось написание. Это можно сравнить с синонимами в естественном языке — допустимо, но не обязательно, и не влияет на восприятие в целом.
Нулевые стейтменты
Пример неправильного кода:
Здесь мы закрыли оператор if с помощью точки с запятой, то есть фактически дополнили его нулевым стейтментом. В этом случае программа будет выполняться неверно, поскольку проверка, равна ли переменная a нулю, уже не проводится. Тут переменная получит значение 1 в любом случае.
А вот правильный код:
Вывод
В статье мы рассмотрели самые простые варианты ветвления и только для одного языка, хотя алгоритм работает аналогично и в других — разница только в синтаксисе. Конечно, есть и другие операторы ветвления даже в самом C++ — тот же весьма мощный по своим возможностям оператор switch или «переключатель». Его работу можно увидеть в так называемых «радиокнопках» в интерфейсе многих программ. Его специфика: он удобен при обработке множества опций выбора, там можно выбрать только один вариант.
К слову, то же самое, что было в статье, но более подробно, есть в этом тематическом видео:
Операторы ветвления
if-else
В языке программирования C синтаксис оператора ветвления if-else выглядит так:
Как и в других языках ветка else не является обязательной.
В языке С в простых логических выражениях используются следующие знаки операторов: >, =,
Условное выражение
В языке программирования C существует сокращенная запись инструкции if-else в виде условного выражения, которое относится к тернарным операторам. Результат такого выражения может быть присвоен переменной:
Переводится это так. Если логич_выражение вернуло истину, то все выражение возвращает выражение1; если логич_выражение вернуло ложь, то все выражение возвращает выражение2. Например:
Здесь z получит значение 15. Такое условное выражение бывает очень удобно, однако область его применения ограничена простейшими случаями ветвления, т. к. невозможно создавать сложные «тела» в такой конструкции.
Операторы И (&&) и ИЛИ (||)
Как известно логическое выражение может быть сложным. Логические операторы И и ИЛИ в языке программирования C обозначаются соответственно парными знаками амперсанда (&&) и вертикальной черты (||). Их приоритет меньше, чем у простых логических операторов, поэтому простые логические операции при их объединении в сложные логические выражения можно не заключать в скобки. Пример сложного логического выражения на языке C:
Проверьте и объясните, что выводит функция printf(), если ей передать простые или сложные логические выражения. Например:
Оператор switch
При организации множественного выбора, когда проверяется значение переменной на соответствие тому или иному значению, бывает удобно использовать не условный оператор if-else, а оператор переключения switch. Его синтаксис можно описать так:
В скобках после слова switch может стоять не только переменная, но и выражение, результат выполнения которого возвращает целое значение (может быть символ). Константы при case также могут быть результатом выполнения выражений. Константы можно группировать в одном case (например, case 12, 13, 18 ). Ветка default не обязательна.
При выполнении оператора switch, заданное значение в круглых скобках сравнивается с константами. Как только совпадение будет найдено, все последующие вложенные во все case операции начинают выполняться. Другими словами, выполняется не только кейс, где произошло совпадение, но и все нижележащие ветки case (и default тоже), константы которых не совпадают со значением при switch. Например, в результате выполнения вот такой программы:
на экране будет выведено:
, т. к. как только совпадение было обнаружено, все нижеследующие инструкции были выполнены.
Чтобы этого не происходило, в конце операций, принадлежащих определенному case, дописывают оператор break, который осуществляет принудительный выход из всей конструкции (в данном случае switch). Например:
выведет только единицу, т. к. выполнение всей инструкции switch прервется после выполнения инструкции break при case 1.







