Оператор switch case в языке C: синтаксис, break и default

Оператор switch case в языке C: синтаксис, break и default Полезное

Оператор switch case в языке C — это конструкция выбора, которая сравнивает значение одного целочисленного выражения с набором констант и выполняет ту ветку case, чья константа совпала. Он заменяет длинную цепочку if / else if, когда решение зависит от одного значения: номера пункта меню, кода дня недели, символа-оценки.

Ниже — синтаксис switch, роль ключевого слова break, что такое проваливание (fallthrough) без break, зачем нужна ветка default и какие типы данных допустимы. Все примеры — полные программы на C, которые можно скомпилировать и запустить; вывод в тексте сверен с реальным.

Синтаксис оператора switch case

Общий вид конструкции такой:

switch (выражение) {
    case константа_1:
        операторы;
        break;
    case константа_2:
        операторы;
        break;
    default:
        операторы;
}

Работает это так: вычисляется выражение в скобках, затем его значение по очереди сравнивается с константами в case. При первом совпадении управление переходит внутрь этого case, и операторы выполняются до break. Ветка default срабатывает, если не совпал ни один case.

Вот минимальная полная программа — вывод названия дня недели по его номеру:

#include <stdio.h>

int main(void) {
    int day = 3;
    switch (day) {
        case 1:
            printf("Понедельник\n");
            break;
        case 2:
            printf("Вторник\n");
            break;
        case 3:
            printf("Среда\n");
            break;
        default:
            printf("Такого дня недели нет\n");
    }
    return 0;
}

Для day = 3 совпадает третий case, и в консоли появится:

Среда

Чтобы читать значение с клавиатуры, замените присваивание на ввод: scanf("%d", &day); (символ & обязателен — scanf нужен адрес переменной).

Оператор break и проваливание (fallthrough)

break выходит из switch сразу после выполненной ветки. Если его убрать, начинается проваливание (fallthrough): выполнение не останавливается на границе case, а продолжается в следующий case и дальше — до break или до конца switch. Метки case тут работают только как точки входа, а не как отдельные блоки.

Это частый источник ошибок. Возьмем ту же программу, но уберем все break:

#include <stdio.h>

int main(void) {
    int day = 2;
    switch (day) {
        case 1:
            printf("Понедельник\n");
        case 2:
            printf("Вторник\n");
        case 3:
            printf("Среда\n");
        default:
            printf("Такого дня недели нет\n");
    }
    return 0;
}

Ожидался бы один «Вторник», но фактический вывод для day = 2 такой:

Вторник
Среда
Такого дня недели нет

Управление вошло в case 2 и, не встретив break, провалилось в case 3 и default. Исправление — вернуть break в конце каждой ветки:

#include <stdio.h>

int main(void) {
    int day = 2;
    switch (day) {
        case 1:
            printf("Понедельник\n");
            break;
        case 2:
            printf("Вторник\n");
            break;
        case 3:
            printf("Среда\n");
            break;
        default:
            printf("Такого дня недели нет\n");
    }
    return 0;
}

Теперь вывод ровно один:

Вторник

Правило простое: если ветки не должны сливаться, каждая заканчивается break (последнюю ветку тоже стоит закрывать break — чтобы при добавлении нового case ниже ничего не провалилось).

Осознанное проваливание: несколько case на одно тело

У проваливания есть и полезное применение. Если несколько значений должны привести к одному действию, метки case ставят подряд, без операторов и без break между ними — тело пишут после последней метки группы:

#include <stdio.h>

int main(void) {
    char grade = 'B';
    switch (grade) {
        case 'A':
        case 'B':
        case 'C':
            printf("Зачет сдан\n");
            break;
        case 'D':
        case 'F':
            printf("Нужна пересдача\n");
            break;
        default:
            printf("Неизвестная оценка\n");
    }
    return 0;
}

Символ 'B' попадает в группу A/B/C, поэтому вывод:

Зачет сдан

Здесь switch работает по символу: в C тип char — это целое число (код символа), поэтому в case можно писать символьные константы вроде 'A'. Это допустимая и распространенная форма, а не обход правил.

Ветка default: когда совпадений нет

default — это ветка «во всех остальных случаях». Она не обязательна: если ее нет и ни один case не совпал, switch просто ничего не делает. Но для надежного кода default полезен — он ловит неучтенные значения.

#include <stdio.h>

int main(void) {
    int choice = 9;
    switch (choice) {
        case 1:
            printf("Открыть файл\n");
            break;
        case 2:
            printf("Сохранить файл\n");
            break;
        default:
            printf("Нет такого пункта меню\n");
    }
    return 0;
}

Значение 9 не совпало ни с одним case, сработала ветка по умолчанию:

Нет такого пункта меню

Формально default можно разместить не только в конце, но и между case — на порядок проверки это не влияет (сравнение всегда идет по case, а default рассматривается последним). Но по договоренности его пишут в конце: так код читается привычнее.

Какие типы и значения допустимы

На switch в C есть жесткие ограничения — о них стоит знать заранее, иначе программа не скомпилируется.

  • Выражение в switch должно быть целочисленного типа: int, char, enum, другие целые. Дробные float и double недопустимы.
  • Метки case — только константные целочисленные выражения (число, символьная константа, элемент enum). Переменную или диапазон вида case 1..5 в стандартном C поставить нельзя.
  • Константы всех case в одном switch должны быть уникальны.

Например, switch по double не соберется:

double x = 2.0;
switch (x) {   // так нельзя: тип double недопустим
    case 2:
        printf("два\n");
        break;
}

Компилятор остановится с ошибкой. Точный текст зависит от инструментов: Apple clang сообщает statement requires expression of integer type ('double' invalid), GCC — switch quantity not an integer. Смысл один: в switch нужно целое.

Такая же ошибка компиляции будет при двух одинаковых case (например, два case 1 подряд): clang пишет duplicate case value, GCC — похоже. Это удобно — опечатка ловится сразу, а не в рантайме.

switch или if…else: что выбрать

switch и цепочка if / else if решают одну задачу — ветвление, но подходят под разные ситуации.

Задача Что взять Почему
Сравнить одну переменную с набором конкретных значений switch читается как таблица вариантов, компактнее длинной цепочки else if
Диапазоны и неравенства (x > 100, 0 < x < 10) if…else switch сравнивает только на равенство с константами
Дробные числа (double, float) if…else switch не принимает нецелые типы
Сравнение строк if…else со strcmp switch не умеет сравнивать строки в C
Много веток по одному целому значению switch нагляднее и обычно быстрее читается

Проще говоря: один целый ключ и точные значения — switch; диапазоны, дроби, строки или сложные условия — if...else.

Выводы

  • switch case в языке C выбирает ветку по значению одного целочисленного выражения и заменяет длинную цепочку if / else if, когда решение зависит от одного значения.
  • break завершает switch; без него начинается проваливание — выполнение продолжается в следующие case (в примере выше day = 2 без break дал три строки вместо одной).
  • Проваливание можно применять осознанно: несколько меток case подряд без break направляют разные значения в одно тело.
  • default срабатывает, когда не совпал ни один case; ветка не обязательна, но защищает от неучтенных значений.
  • В switch допустимы только целые типы (int, char, enum), метки case — уникальные целочисленные константы; double, диапазоны и строки — это территория if...else.

Где применяется на практике

Оператор switch case — базовый инструмент управления потоком в C и близких языках: разбор пунктов меню, обработка кодов команд и состояний, диспетчеризация по типу события, интерпретаторы и конечные автоматы. Умение видеть, где switch читается лучше цепочки условий, — часть культуры чистого кода на C.

Освойте тему на практике

Освоить синтаксис C системно, с практикой и обратной связью от преподавателей, помогает курс Программирование на C++ с нуля: C и C++ разделяют общее процедурное ядро, включая switch case, break и default, с которого начинают оба языка.

Освойте тему на практике

Посмотреть, как разбирают такие конструкции вживую, и задать вопросы можно на открытых вебинарах Otus — они бесплатные и проходят регулярно.

Смежные темы: Переменные в языке C, Оператор return в C, Циклы в программировании.

FAQ

Обязательно ли ставить break в последней ветке switch? Программа отработает и без него, но break (или break после default) стоит ставить всегда: как только ниже добавят новый case, забытый break приведет к незаметному проваливанию.

Можно ли в case указать диапазон значений, например от 1 до 10? В стандартном C — нет, метка case принимает только одну константу. Для диапазона перечислите значения отдельными метками case подряд или используйте if...else.

Что быстрее — switch или if…else? Для сравнения одного целого с набором констант компилятор часто превращает switch в таблицу переходов, и он может быть быстрее длинной цепочки if. Но разница обычно несущественна; выбирают по читаемости, а не по скорости.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)