if выбирает, какую инструкцию выполнить, а не какое значение получить.
Условие в скобках преобразуется к bool, при истине выполняется первая ветвь,
при лжи — ветвь после else.
Зачем нужно
Пока программа считает одно выражение, выбирать не из чего. Как только ответ зависит от данных — например, делить можно, а делить на ноль нельзя — нужен способ выполнить разные действия:
if (y != 0) {
std::cout << x / y << '\n';
} else {
std::cout << "Error\n";
}Выбирать между числом и строкой внутри одного выражения не пришлось: выбор сделан на уровне инструкций.
Как работает
Ветка else необязательна:
if (x > 0) {
std::cout << x << '\n';
}После if и после else синтаксически стоит ровно один оператор. Фигурные
скобки превращают в этот оператор целый блок. Даже для одной инструкции ставим
скобки — так границы видны и человеку, и через месяц себе.
Несколько вариантов — цепочка:
if (value == 0) {
std::cout << "Zero\n";
} else if (value == 1) {
std::cout << "One\n";
} else {
std::cout << "Other\n";
}Условия проверяются сверху вниз, и как только выбрана ветвь, остальные ветви
цепочки пропускаются. else if — не отдельное ключевое слово, а обычный if,
поставленный в ветвь else.
Несколько независимых if означают другое:
int value = 0;
if (value == 0) {
value = 1;
}
if (value == 1) { // сработает тоже
std::cout << "One\n";
}Выполнятся оба блока: первый изменил значение, второй независимо проверил уже
изменённое. Замените второй if на else if — и его условие после сработавшей
первой ветви проверяться не будет.
Условие — это выражение типа bool
Любое значение приводится к bool: ноль даёт false, любое ненулевое true.
Отсюда две распространённые записи:
if (n) { ... } // то же, что n != 0
if (!n) { ... } // то же, что n == 0Сравнение само по себе выражение, его не обязано «съедать» условие — см. Логические операции и короткое замыкание.
Объявление внутри условия
Переменную можно определить прямо в условии:
if (int x = 0) {
std::cout << x << '\n';
} else {
std::cout << "Zero\n"; // выполнится это
}Проверяется значение созданного x. Здесь оно равно нулю, ноль приводится
к false, поэтому работает else. Переменная доступна в обеих ветвях,
но после всего условного оператора её имя уже недоступно. Инициализатор
в такой форме обязателен: if (int x) недопустимо.
Приём удобен, когда значение нужно проверить и тут же использовать, не оставляя лишнее имя жить дальше по функции.
Тонкости
-
Лишняя точка с запятой ломает всё молча:
if (x > 0); { std::cout << "Positive\n"; // печатается всегда };образовала пустой оператор — именно его выполняетif. Блок ниже существует сам по себе и выполняется независимо от условия. -
Потерявшийся
elseотносится к ближайшемуif, у которого его ещё нет:if (true) if (false) std::cout << "A\n"; else std::cout << "B\n"; // выведет BОтступ синтаксис не меняет —
elseпринадлежит внутреннемуif. Со скобками такая двусмысленность невозможна. -
=вместо==в условии компилируется и почти всегда означает не то:if (x = 0)присваивает ноль и всегда ложно.
Частые ошибки
- Писать ветви без фигурных скобок и потом добавить вторую строку.
- Ставить
;сразу после условия. - Городить цепочку независимых
ifтам, где нужна цепочкаelse if, и получать срабатывание нескольких веток подряд. - Проверять
if (x == true)вместоif (x).