1. Синтаксис ветвлений: if, else, else if
Когда вы только начинаете программировать, кажется, что программа — это просто калькулятор: ввели числа, получили ответ. Но довольно быстро выясняется, что реальная программа почти всегда «ветвится»: если пользователь ввёл одно — делаем так, если другое — иначе. Даже в стандарте C++ отдельно выделяют понятие condition («условие») как важную часть управляющих конструкций вроде if.
Самая простая мысль на сегодня: if — это как развилка на дороге. Условие — это вопрос, на который программа отвечает true или false, и выбирает одну из веток.
Прежде чем лепить «умные» условия, важно навести порядок в голове: if — это не магия, а очень строгая конструкция. В скобках после if должно быть выражение типа bool (или то, что к нему приводится), а дальше идёт команда или блок команд. И вот тут начинается первая битва новичка с синтаксисом: где скобки круглые, где фигурные, и почему одна лишняя точка с запятой ; ломает смысл.
Базовый if: «если (…) то …»
Мини-скелет выглядит так:
if (condition) {
// действия, если condition == true
}
if
Пример: «совершеннолетний или нет»
Сделаем очень прямолинейно: вводим возраст и печатаем статус.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
if (age >= 18) {
std::cout << "adult\n"; // например, при вводе 18 -> adult
}
}
Здесь важно прочувствовать: age >= 18 — это выражение, которое вычисляется в true или false. Если оно true, выполняется блок.
else: «иначе делаем вот это»
Если if — это «если правда», то else — это «если неправда». Он всегда относится к ближайшему if, у которого нет своего else (это важный момент: отступы и {} реально спасают нервы).
Базовая форма:
if (condition) {
// true-ветка
} else {
// false-ветка
}
if / else
И это уже полноценная развилка «налево/направо».
Пример: «adult/minor»
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
if (age >= 18) {
std::cout << "adult\n"; // 18 -> adult
} else {
std::cout << "minor\n"; // 17 -> minor
}
}
Обратите внимание на читабельность: две ветки почти как два абзаца текста. Это именно то, к чему мы стремимся: код должен читаться глазами, а не угадываться как ребус.
else if: «иначе если … иначе если … иначе …»
Теперь переходим к части, где нужно выбрать одну ветку из нескольких. Это суперчастая ситуация: число может быть положительным/отрицательным/нулём, команда может быть "add"/"remove"/"exit", оценка может быть «отлично/хорошо/удовлетворительно/плохо».
Цепочка выглядит так:
if (cond1) {
...
} else if (cond2) {
...
} else if (cond3) {
...
} else {
...
}
Правило дня: в такой цепочке выполнится ровно одна ветка — первая подходящая сверху вниз.
Пример: знак числа
#include <iostream>
int main() {
int x = 0;
std::cin >> x;
if (x > 0) {
std::cout << "positive\n"; // 5 -> positive
} else if (x < 0) {
std::cout << "negative\n"; // -3 -> negative
} else {
std::cout << "zero\n"; // 0 -> zero
}
}
Почему порядок важен? Потому что проверки идут сверху вниз. Если бы мы по ошибке написали x >= 0 первой строкой, то ветка else if (x < 0) стала бы почти бесполезной: всё, что не отрицательное, уже «съелось» бы первой проверкой.
3. Читаемость ветвлений: {}, уровни смысла и имена проверок
Есть две категории новичков: те, кто ставит {} всегда, и те, кто однажды потерял два часа из‑за отсутствующих {} — и потом тоже стал ставить всегда.
Формально C++ разрешает писать так:
if (condition)
std::cout << "Hello\n";
Но для начинающего это как кататься на велосипеде без рук: кто-то умеет, но мы пока учимся ездить, а не впечатлять прохожих.
Почему «одна строка без {}» опасна
Проблема появляется, когда вы сначала написали одну строку, а потом добавили вторую и забыли скобки. Код компилируется, но делает «что-то странное».
Сравните:
// ПЛОХО: легко сломать при добавлении строк
if (age >= 18)
std::cout << "adult\n";
std::cout << "welcome!\n"; // выполняется ВСЕГДА
и
// ХОРОШО: структура всегда очевидна
if (age >= 18) {
std::cout << "adult\n";
std::cout << "welcome!\n";
}
Вторая версия буквально визуально говорит: «эти две строки — одно действие для ветки».
else if и вложенный if: это разные смыслы
Очень частая путаница: «а можно я просто вложу if внутрь if?» Можно. Но смысл будет другой. И если смысл другой — лучше писать так, чтобы читатель (включая вас через неделю) сразу это увидел.
else if — это «выбор одной ветки из набора взаимоисключающих вариантов».
Вложенный if — это «мы уже выбрали ветку, и внутри неё уточняем».
Пример: где нужен вложенный if
Допустим: сначала проверяем, что возраст вообще корректный (не отрицательный), а уже потом решаем adult/minor.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
if (age < 0) {
std::cout << "invalid\n"; // -5 -> invalid
} else {
if (age >= 18) {
std::cout << "adult\n"; // 20 -> adult
} else {
std::cout << "minor\n"; // 7 -> minor
}
}
}
Смысл тут такой: «если возраст плохой — сразу invalid; иначе решаем взрослый/ребёнок».
Если попытаться это «впихнуть» в одну цепочку else if, тоже получится, но новичку обычно сложнее читать, потому что смешиваются разные уровни смысла: валидность данных и классификация данных.
Делайте условия читаемыми: называйте проверки
В этой лекции мы говорим не только «как работает if», но и «как сделать так, чтобы ваш код не выглядел как шифр». Очень простой приём — вынести часть проверки в переменную типа bool с нормальным именем.
Это не «лишние переменные», а подписи на проводах. Без подписи можно тоже подключить, но потом ремонтировать больно.
#include <iostream>
int main() {
int age = 0;
std::cin >> age;
bool is_adult = (age >= 18);
if (is_adult) {
std::cout << "adult\n";
} else {
std::cout << "minor\n";
}
}
Плюс такого подхода: условие if (is_adult) читается почти как английское предложение. Минус: нужно придумать имя. Но это «минус» только первые пару недель, потом мозг начинает делать это автоматически.
4. Практический мини‑пример: «обработчик команды» без циклов
Сейчас мы соберём маленькую заготовку приложения, которое будет развиваться дальше по курсу. Пока без циклов (мы их ещё не проходили), поэтому программа обработает одну команду и завершится. Но даже в таком виде она уже будет похожа на реальный консольный интерфейс: пользователь вводит команду, программа выбирает, что делать.
Идея простая: читаем строку cmd и делаем разные действия.
Версия 1: три команды
#include <iostream>
#include <string>
int main() {
std::string cmd;
std::cin >> cmd;
if (cmd == "hello") {
std::cout << "Hello!\n"; // hello -> Hello!
} else if (cmd == "help") {
std::cout << "Commands: hello, help, exit\n";
} else if (cmd == "exit") {
std::cout << "Bye!\n"; // exit -> Bye!
} else {
std::cout << "Unknown command\n"; // qwerty -> Unknown command
}
}
Заметьте, как читабельно это выглядит: сверху вниз — как список правил. Это одна из причин, почему цепочка else if так популярна на ранних этапах обучения.
Версия 2: команда с числом
Пусть команда будет "age", и после неё пользователь вводит число. Мы не делаем сейчас сложных проверок ввода (это будет отдельно), но покажем, как ветка if может содержать свой маленький сценарий.
#include <iostream>
#include <string>
int main() {
std::string cmd;
std::cin >> cmd;
if (cmd == "age") {
int age = 0;
std::cin >> age;
if (age >= 18) {
std::cout << "adult\n"; // age 20 -> adult
} else {
std::cout << "minor\n"; // age 7 -> minor
}
} else {
std::cout << "Try command: age\n";
}
}
Обратите внимание: внутри ветки cmd == "age" мы делаем ещё одно ветвление. Это нормальная и очень жизненная история: «сначала выбираем режим, потом внутри режима выбираем действие».
Небольшая схема: как выполняется if / else if / else
Иногда полезно увидеть else if не как «магические слова», а как простой алгоритм: проверили первое — если да, выполнили и ушли; если нет, пошли дальше.
flowchart TD
A[Начало] --> B{cond1?}
B -->|да| C[ветка 1]
B -->|нет| D{cond2?}
D -->|да| E[ветка 2]
D -->|нет| F{cond3?}
F -->|да| G[ветка 3]
F -->|нет| H[else-ветка]
C --> Z[Конец]
E --> Z
G --> Z
H --> Z
Эта схема полезна тем, что объясняет главный факт дня: выполняется только одна ветка, и проверка идёт сверху вниз.
5. Типичные ошибки при работе с if/else
Ошибка №1: точка с запятой после if.
Новички иногда пишут if (cond); — и это выглядит почти правильно, но смысл ломается полностью. Точка с запятой — это «пустая команда»: условие проверилось, а дальше «ничего не сделали». Блок после этого выполняется уже как обычный блок, то есть почти всегда. Если видите странное поведение «ветка выполняется всегда», первым делом ищите лишний ;.
Ошибка №2: ветки без {} и «убежавшая строка».
Сначала всё работает: в ветке одна строка. Потом вы добавили вторую, но забыли фигурные скобки, и вторая строка стала выполняться всегда (или никогда) — в зависимости от того, куда она попала. Это одна из самых обидных ошибок: компилятор не ругается, а логика уже другая. Привычка «всегда ставить {}» лечит это почти на 100%.
Ошибка №3: перепутали смысл else if и вложенного if.
Если вам нужно выбрать «один вариант из многих» — используйте цепочку else if. Если вам нужно «сначала проверить одно, а внутри уже уточнить другое» — используйте вложенный if. Когда эти смыслы смешиваются, код становится трудным для чтения: вроде бы работает, но непонятно, что автор хотел сказать.
Ошибка №4: плохой порядок проверок в цепочке else if.
Проблема появляется, когда первая проверка слишком «широкая» и перехватывает случаи, которые должны были попасть в нижние ветки. Например, if (x >= 0) перед else if (x == 0) — и ветка x == 0 никогда не выполнится. Лечится простым правилом: сначала более специфичные случаи, потом более общие (или продумываем «лестницу» сверху вниз словами и только потом пишем код).
Ошибка №5: длинные ветки и «потеря смысла».
Иногда начинающий пишет в каждой ветке по 40 строк. Формально это нормально, но читать тяжело: вы забываете, какое условие выбрало ветку, пока долистали до конца. На этом этапе курса мы не разбираем функции, поэтому рецепт простой: держите ветки короткими, печатайте понятные сообщения, а условия делайте максимально ясными. Когда появятся функции, мы научимся «утончать main», но пока тренируем аккуратный стиль прямо здесь.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ