Зачем программам ветвления
Все программы до сих пор выполнялись напрямую: строка 1, строка 2, строка 3. Реальные программы принимают решения. Верен ли пароль? Отрицательное ли число? Открылся ли файл? Оператор if — это способ задать вопрос в C и выполнить код только тогда, когда ответ «да».
Условие temperature > 30 проверяется один раз. Оно выполняется, поэтому сообщение выводится. Последняя строка находится вне фигурных скобок, поэтому печатается в любом случае. Замените 31 на 18 и запустите снова — первое сообщение исчезнет, а второе останется.
Синтаксис: скобки, фигурные скобки и никакой точки с запятой
У if в C фиксированная форма:
if (condition) {
// выполняется, когда условие ненулевое
}
Три правила стоит запомнить сразу. Круглые скобки вокруг условия обязательны. Ключевого слова then нет. И никакой точки с запятой после закрывающей скобки — случайная точка с запятой заканчивает инструкцию прямо там:
// БАГ: if ничего не делает; printf выполняется всегда
if (x > 10);
{
printf("big\n");
}
Это компилируется без единого замечания. ; — пустая инструкция, которая становится телом if, а фигурные скобки ниже — просто самостоятельный блок, который выполняется всегда. Компиляция с gcc -Wall ловит это.
Сами фигурные скобки необязательны для одной инструкции, но оставляйте их. if без скобок, у которого потом появляется вторая строка, — классический источник багов, потому что в C отступы не группируют инструкции.
else и else if
else задаёт вторую ветку:
Если исходов больше двух, соединяйте их через else if. C проверяет условия по порядку и останавливается на первом истинном:
Порядок здесь имеет огромное значение. Поскольку цепочка останавливается на первом совпадении, вторая проверка видит только результаты ниже 90 — поэтому score >= 80 не нужно дополнять && score < 90. Пишите цепочку от самого строгого условия к самому мягкому, иначе все значения попадут в первую ветку.
Завершающий else необязателен. Добавляйте его всегда, когда цепочка должна покрывать все случаи; его отсутствие означает «если ничего не совпало — ничего не делать», что нормально, но должно быть осознанным решением.
Истинность: 0 — ложь, всё остальное — истина
В ядре языка C у условий нет отдельного логического типа. if просто спрашивает, является ли выражение ненулевым.
Последние две строки показывают вторую половину правила: операторы сравнения — обычные выражения, дающие 1 для истины и 0 для лжи. Именно поэтому if (5 > 2) работает — на самом деле это if (1).
По той же причине -3 в C истинно. Правило — ненулевое, а не положительное. Если вам нужно узнать, положительно ли число, пишите if (n > 0), а не if (n).
В C99 появился <stdbool.h> с настоящим типом bool плюс true и false, и в новом коде это читается лучше. Под капотом это всё те же 1 и 0, поэтому правило выше не меняется — см. Логический тип в C.
Операторы сравнения и логические операторы, которые вы будете использовать в условиях:
== равно && логическое И (обе стороны истинны)
!= не равно || логическое ИЛИ (хотя бы одна сторона истинна)
< меньше ! логическое НЕ
> больше
<= меньше или равно
>= больше или равно
&& и || работают с коротким замыканием: a && b никогда не вычисляет b, если a ложно, а a || b никогда не вычисляет b, если a истинно. Это гарантия, а не оптимизация, поэтому безопасно писать if (n != 0 && total / n > 5) — деление не выполнится, когда n равно нулю.
Ошибка = вместо ==
Это самая частая ошибка в условиях C:
// БАГ: присваивает 5 переменной x, затем проверяет 5 (ненулевое), поэтому ВСЕГДА выполняется
if (x = 5) {
printf("x is five\n");
}
C разрешает присваивание внутри выражения, поэтому строка законна. Она сохраняет 5 в x, даёт значение 5, а 5 ненулевое — ветка выполняется каждый раз, а x был тихо перезаписан.
Две линии защиты. Во-первых, всегда компилируйте с включёнными предупреждениями:
gcc -Wall -Wextra program.c -o program
И GCC, и clang выдают «suggest parentheses around assignment used as truth value». Во-вторых, некоторые программисты пишут константу перед переменной — if (5 == x), — чтобы опечатка if (5 = x) стала жёсткой ошибкой компиляции, а не тихим багом. Этот стиль — дело вкуса; включение предупреждений — нет.
Вложенность
if может содержать другой if. Вложенность выражает условия, которые имеют смысл только тогда, когда выполнено предыдущее:
Два уровня читаются нормально. Четыре — нет. Когда вложенность углубляется, ищите способ её выпрямить — часто объединением условий через && или обработкой неудачных случаев первыми с ранним возвратом:
// плоский вариант: разбираемся с исключениями, потом переходим к делу
if (age < 18) { printf("Adults only.\n"); return 0; }
if (!hasTicket) { printf("Please buy a ticket.\n"); return 0; }
printf("Welcome in.\n");
Висячий else
Когда if без фигурных скобок вложен в другой, какому из них принадлежит else? Правило C: else связывается с ближайшим несопоставленным if, независимо от того, как расставлены отступы.
// else принадлежит ВНУТРЕННЕМУ if, несмотря на отступы
if (a > 0)
if (b > 0)
printf("both positive\n");
else
printf("a is not positive\n"); // НЕВЕРНО - выполняется при a > 0 и b <= 0
Отступы говорят, что else в паре с внешним if. Компилятор соединяет его с внутренним. Фигурные скобки полностью убирают эту неоднозначность, и это главный аргумент в пользу того, чтобы всегда их ставить:
if (a > 0) {
if (b > 0) {
printf("both positive\n");
}
} else {
printf("a is not positive\n");
}
Тернарный оператор
Когда ветвление существует только чтобы выбрать значение, условный оператор ? : выражает это одним выражением:
Читайте cond ? x : y как «если cond, то x, иначе y». Вычисляется ровно одна из двух веток, и всё выражение даёт значение — поэтому его можно присвоить или передать аргументом там, где инструкция не подошла бы.
Оставьте его для простого выбора значений. Вложенные тернарные операторы (a ? b : c ? d : e) законны и почти всегда читаются хуже, чем цепочка else if, которую они заменяют.
Часто задаваемые вопросы
Как написать конструкцию if else в C?
Поместите условие в круглые скобки, а код — в фигурные: if (score >= 60) { printf("Pass\n"); } else { printf("Fail\n"); }. Блок else выполняется только тогда, когда условие ложно, а ключевого слова then в C нет.
Что считается истиной в условии if в C?
Любое значение, кроме нуля. В ядре языка C нет отдельного логического типа для условий, поэтому if (n) срабатывает, когда n — что угодно кроме 0, а if (!n) — только когда n ровно 0. Операторы сравнения вроде == и < дают 1 для истины и 0 для лжи.
В чём разница между = и == в C?
== сравнивает, = присваивает. Запись if (x = 5) присваивает 5 переменной x, а затем проверяет 5 — оно ненулевое, поэтому ветка выполняется всегда. Компилируется это без ошибок, и именно поэтому это самая частая ошибка новичков в условиях C — большинство компиляторов предупреждают о ней с -Wall.
Как работает тернарный оператор в C?
условие ? значениеЕслиИстина : значениеЕслиЛожь — это выражение, дающее одно из двух значений, поэтому его можно поставить внутрь присваивания или аргумента printf: int max = a > b ? a : b;. Используйте его для выбора значения, а обычный if — когда нужно выполнить инструкции.