На этом уроке мы рассмотрим операторы условного ветвления if/else, а также то, как их можно использовать.
Условные ветвления if/else
Самыми простыми условными ветвлениями в языке С++ являются стейтменты if/else. Они выглядят следующим образом:
if (выражение)
стейтмент1
Либо так:
if (выражение)
стейтмент1
else
стейтмент2
выражение
называется условием (или «условным выражением»). Если результатом выражения
является true (любое ненулевое значение), то выполняться будет стейтмент1
. Если же результатом выражения
является false (0), то выполняться будет стейтмент2
. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) std::cout << a << " is greater than 15\n"; else std::cout << a << " is not greater than 15\n"; return 0; } |
Использование нескольких операций в ветвлениях if/else
Оператор if выполняет только одну операцию, если выражение
является true, и также только одну операцию else, если выражение
— false. Чтобы выполнить несколько операций подряд, используйте блок стейтментов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { // Обе операции будут выполнены, если a > 15 std::cout << "You entered " << a << "\n"; std::cout << a << " is greater than 15\n"; } else { // Обе операции будут выполнены, если a <= 15 std::cout << "You entered " << a << "\n"; std::cout << a << " is not greater than 15\n"; } return 0; } |
Неявное указание блоков
Если программист не указал скобки для блока стейтментов if или else, то компилятор неявно сделает это за него. Таким образом, следующее:
if (выражение)
стейтмент1
else
стейтмент2
Будет выполняться как:
if (выражение)
{
стейтмент1
}
else
{
стейтмент2
}
По сути, это не имеет значения. Однако начинающие программисты иногда пытаются сделать что-то вроде следующего:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { if (1) int a = 4; else int a = 5; std::cout << a; return 0; } |
Программа не скомпилируется, и в итоге мы получим ошибку, что идентификатор a
не определен. А произойдет это из-за того, что программа будет выполняться следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { if (1) { int a = 4; } // переменная a уничтожается здесь else { int a = 5; } // переменная a уничтожается здесь std::cout << a; // переменная a здесь не определена return 0; } |
В этом контексте становится понятным, что переменная a
имеет локальную область видимости и уничтожается в конце блока, в котором выполняется её инициализация. И, когда мы дойдем до строчки с std::cout, переменная a
уже перестанет существовать.
Связывание стейтментов if
Стейтменты if/else можно использовать в связке:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) std::cout << a << " is greater than 15\n"; else if (a < 15) std::cout << a << " is less than 15\n"; else std::cout << a << " is exactly 15\n"; return 0; } |
Вложенные ветвления if/else
Одни стейтменты if могут быть вложены в другие стейтменты if:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) // внешний оператор if // Это плохой способ написания вложенных стейтментов if if (a < 25) // внутренний оператор if std::cout << a << " is between 15 and 25\n"; // К какому if относится следующий else? else std::cout << a << " is greater than or equal to 25\n"; return 0; } |
Обратите внимание, в программе, приведенной выше, мы можем наблюдать потенциальную ошибку двусмысленности оператора else. К какому if относится оператор else: к внешнему или к внутреннему?
Дело в том, что оператор else всегда относится к последнему незакрытому оператору if в блоке, в котором находится сам else. Т.е. в программе, приведенной выше, else относится к внутреннему if.
Чтобы избежать таких вот неоднозначностей при вложенности операторов условного ветвления, рекомендуется использовать блоки стейтментов (указывать скобки). Например, вот та же программа, приведенная выше, но уже без двусмысленности:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { if (a < 25) std::cout << a << " is between 15 and 25\n"; else // относится к внутреннему оператору if std::cout << a << " is greater than or equal to 25\n"; } return 0; } |
Теперь понятно, что оператор else относится к внутреннему оператору if. Использование скобок также позволяет явно указать привязку else к внешнему стейтменту if:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::cout << "Enter a number: "; int a; std::cin >> a; if (a > 15) { if (a < 25) std::cout << a << " is between 15 and 25\n"; } else // относится к внешнему оператору if std::cout << a << " is less than 15\n"; return 0; } |
Используя блоки стейтментов, мы уточняем, к какому if следует прикреплять определенный else. Без блоков оператор else будет прикрепляться к ближайшему незакрытому оператору if.
Использование логических операторов в ветвлениях if/else
Также вы можете проверить сразу несколько условий в ветвлениях if/else, используя логические операторы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int main() { std::cout << "Enter an integer: "; int a; std::cin >> a; std::cout << "Enter another integer: "; int b; std::cin >> b; if (a > 0 && b > 0) // && - это логическое И. Проверяем, являются ли оба условия истинными std::cout << "Both numbers are positive\n"; else if (a > 0 || b > 0) // || - это логическое ИЛИ. Проверяем, является ли истинным хоть одно из условий std::cout << "One of the numbers is positive\n"; else std::cout << "Neither number is positive\n"; return 0; } |
Основные использования ветвлений if/else
Ветвления if/else активно используются для проверки ошибок. Например, чтобы вычислить квадратный корень значения, параметр, который передается в функцию для вычисления, — обязательно должен быть положительным:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> #include <cmath> // для функции sqrt() void printSqrt(double value) { if (value >= 0.0) std::cout << "The square root of " << value << " is " << sqrt(value) << "\n"; else std::cout << "Error: " << value << " is negative\n"; } |
Также операторы if используют для ранних возвратов — когда функция возвращает управление обратно в caller еще до завершения выполнения самой функции. В программе, приведенной ниже, если значением параметра является отрицательное число, то функция сразу же возвращает в caller символьную константу или перечислитель в качестве кода ошибки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <iostream> enum class ErrorCode { ERROR_SUCCESS = 0, ERROR_NEGATIVE_NUMBER = -1 }; ErrorCode doSomething(int value) { // Если параметром value является отрицательное число, if (value < 0) // то сразу же возвращаем код ошибки return ErrorCode::ERROR_NEGATIVE_NUMBER; // Что-нибудь делаем return ErrorCode::ERROR_SUCCESS; } int main() { std::cout << "Enter a positive number: "; int a; std::cin >> a; if (doSomething(a) == ErrorCode::ERROR_NEGATIVE_NUMBER) { std::cout << "You entered a negative number!\n"; } else { std::cout << "It worked!\n"; } return 0; } |
Ветвления if/else также обычно используют для выполнения простых математических операций. Например, рассмотрим функцию min(), которая возвращает минимальное из двух чисел:
1 2 3 4 5 6 7 |
int min(int a, int b) { if (a > b) return b; else return a; } |
Эта функция настолько проста, что её можно записать с помощью условного тернарного оператора:
1 2 3 4 |
int min(int a, int b) { return (a > b) ? b : a; } |
Нулевые стейтменты
Также в C++ можно не указывать основную часть оператора if. Такие стейтменты называются нулевыми стейтментами (или «null-стейтментами»). Объявить их можно, используя точку с запятой вместо выполняемой операции. В целях улучшения читабельности кода, точка с запятой нулевого стейтмента обычно пишется с новой строки. Таким образом, мы явно указываем, что хотим использовать null-стейтмент, уменьшая вероятность не заметить его использования:
1 2 |
if (a > 15) ; // это нулевой стейтмент |
Хотя нулевые стейтменты редко используются в сочетании с оператором if, но, из-за неосторожности, это может привести к проблемам. Рассмотрим следующий фрагмент кода:
1 2 |
if (a == 0); a = 1; |
В вышеприведенном примере мы случайно указали точку с запятой в конце оператора if. Эта неосмотрительность приведет к тому, что код будет выполняться следующим образом:
1 2 3 |
if (a == 0) ; // точка с запятой указывает, что это нулевой стейтмент a = 1; // и эта строка выполнится в любом случае! |
Предупреждение: Всегда проверяйте, не «закрыли» ли вы случайно оператор if точкой с запятой.
А как же присвоить значение переменной по определенному условию и вывести из ветвления для дальнейшей обработки?
Можно объявить переменную перед if, например
…
int a;
If (условие)
a = 3;
else
a = 5
Прямо второе дыхание открылось.
Честно говоря — не люблю перечислители. Пока что не видел большого применения.
Юра, в стейтменте
'\0' — что означает?
Я не Юра, но попробую ответить.
\0 — это завершающий нулевой символ, показывающий, что строка на этом заканчивается. Это обязательный последний символ для символьных массивов, дальше него массив не выводится, а без него вывод массива приведёт к ошибке.
Например, если есть массив {'С', 'А', 'Ш', 'А', '/0', '!'}, и мы выводим его на экран, то получим только САША
а прямой ли, обратный ли слэш — без разницы?!
Спасибо за проделанную работу.
Ценность не только в переводе хорошего учебника (хотя это титанический труд) но и в поддержке студентов. Отвечаете на вопросы, комментируете тонкости, просматриваете ответы на задачи и так далее. Это очень важно!!!
Сам студент и понимаю, что так и должно быть. Если есть возможность — даю фидбек 🙂
Не уточните, зачем вообще используются стейтменты null? Программа же просто проигнорирует эти две строки, разве нет?
Стейтменты null ничего не делают, но существуют из-за синтаксических причин. Наиболее часто они используются в качестве заполнителей в итерационных операциях, циклах, ветвлениях if. Например, вы хотите написать свою функцию определения длины строки:
Стейтмент null здесь служит чисто для заполнения тела цикла for (тело должно быть обязательно). return i; поместить в тело цикла for нельзя, так как тогда мы получим просто 0.
Еще вариант применения:
В этом случае внутренний оператор else и стейтмент null удерживают внешний else от привязки к внутреннему if.
Также еще может быть случай, когда вы хотите сохранить прежний код, закомментировав его, тем самым сохраняя возможность легкого восстановления, если он потребуется:
Все, понял, спасибо большое
Пожалуйста 🙂