Условные операторы: if, else, switch
Урок разбирает ветвление в C: конструкцию if/else if/else, компактный тернарный оператор и многоветочный switch, где забытый break вызывает коварное «проваливание» вниз.
В switch без break выполнение «проваливается» в следующую ветку и идёт дальше, пока не встретит break или конец. Это поведение по умолчанию — и самая частая ошибка при работе со switch.
Базовое ветвление в C выглядит знакомо. Помните: условие истинно, если оно не равно нулю.
int score = 75;
if (score >= 90) {
printf("Отлично\n");
} else if (score >= 60) {
printf("Зачёт\n");
} else {
printf("Незачёт\n");
}
Для коротких выборов есть тернарный оператор условие ? а : б — он возвращает одно из двух значений:
int a = 5, b = 8;
int max = (a > b) ? a : b; // если a>b, то a, иначе b
printf("Максимум: %d\n", max);
Когда вариантов много и все сравниваются с одной переменной, удобен switch:
switch (grade) {
case 'A': printf("Превосходно\n"); break;
case 'B': printf("Хорошо\n"); break;
case 'C': printf("Нормально\n"); break;
default: printf("Неизвестно\n");
}
Как работает под капотом
Ключевое слово в switch — break. Без него выполнение не останавливается на сработавшей ветке, а «проваливается» в следующую. Сравните два сценария:
С break (правильно): Без break (проваливание):
grade = 'B' grade = 'B'
| |
v v
case 'A' -- нет case 'A' -- нет
case 'B' -> "Хорошо" case 'B' -> "Хорошо"
| | (нет break!)
break -> ВЫХОД v
case 'C' -> "Нормально" (тоже!)
|
v
default -> "Неизвестно" (и это!)
Иногда проваливание используют намеренно — например, чтобы несколько вариантов делали одно и то же: case 'a': case 'A': .... Но в 99% случаев забытый break — это баг.
Частые ошибки
- Забытый break в switch. Выполнение проваливается в соседние ветки, и программа делает лишнее.
- Присваивание вместо сравнения.
if (x = 5)присваивает 5 и всегда истинно; нужно==. - Лишняя точка с запятой.
if (x > 0);— точка с запятой завершает if пустым телом, и следующий блок выполнится всегда. - switch только по целым. Нельзя написать
caseдля строки или дробного числа — только целые и символы (которые тоже целые).
Best practices
- Всегда добавляйте
defaultв switch — он ловит непредусмотренные случаи. - Ставьте фигурные скобки даже для однострочного if:
if (x) { ... }. Это спасает от ошибок при дописывании кода. - Если намеренно опускаете break ради проваливания — оставьте комментарий
/* fall through */, чтобы было видно, что это не забывчивость.
Логику switch с проваливанием удобно прочувствовать на Python, где такого механизма нет — придётся смоделировать его явно через список веток.
# Моделируем switch с break и без него
def run_switch(grade, use_break):
branches = ['A', 'B', 'C']
started = False
for b in branches:
if b == grade:
started = True
if started:
print("Ветка", b, "сработала")
if use_break:
break # как break в C — выходим сразу
print("С break:")
run_switch('B', use_break=True)
print("Без break (проваливание):")
run_switch('B', use_break=False)
Та же логика на Python ▶ — видно, как без break выполнение «течёт» через все ветки ниже сработавшей. Именно это происходит в C при забытом break.
Истинность в C
За компактностью условий C скрывается простое правило, которое стоит усвоить раз и навсегда: истинно всё, что не равно нулю. Это значит, что if (n) срабатывает для любого ненулевого n, а if (!n) — только когда n равно нулю. Отсюда идиомы: проверка указателя if (p) вместо if (p != NULL), проверка строки на пустоту через первый символ. Но эта же гибкость порождает коварную ошибку: if (x = 5) присваивает 5 и, поскольку 5 ненулевое, всегда истинно. Многие компиляторы предупреждают о таком присваивании в условии — ещё один довод компилировать с -Wall. Современный стандарт добавил тип bool из <stdbool.h> со значениями true и false, и для ясности кода его стоит использовать.
Итоги
Ветвление в C — это if/else if/else, компактный тернарный оператор ? : и switch для множественного выбора по целому значению. Главная особенность switch — обязательный break: без него выполнение проваливается в соседние ветки. Защита от ошибок — фигурные скобки везде, обязательный default и явные комментарии при намеренном проваливании.