Menu

if else в C: синтаксис, примеры и распространённые ошибки

Как C принимает решения: оператор if, else, цепочки else if, вложенность и тернарный оператор — плюс правило истинности (0 — ложь, всё остальное — истина) и ошибка = вместо ==, которая незаметно ломает условия.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Зачем программам ветвления

Все программы до сих пор выполнялись напрямую: строка 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 — когда нужно выполнить инструкции.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ