Оператор switch множественного выбора. Ключевое слово break

Практический курс по C/C++: https://stepik.org/course/193691

В языке Си имеется еще один оператор ветвления switch, который позволяет реализовывать в программах множественный выбор.

Вначале я приведу синтаксис этого оператора, а затем, мы подробно посмотрим на примеры его работы. Общее определение можно записать следующим образом:

switch(<выражение>) {
case <константа 1> :
        [операторы]
case <константа 2> :
        [операторы]
...
[default : операторы]
}

Здесь выражение – это любая конструкция языка Си, которая возвращает целочисленное значение (включая значение типа char). Соответственно, константы после ключевых слов case также должны быть целочисленными. Причем, вычисляемыми на этапе компиляции (например, целочисленные переменные использовать нельзя, а вот числовые литералы можно). После константы ставится двоеточие и могут быть прописаны операторы, которые выполняются по указанной метке. Обратите внимание, операторы здесь могут отсутствовать и далее в примерах мы увидим, когда это может быть полезно. Наконец, последнее необязательное ключевое слово default позволяет задавать набор операторов, которые выполняются, если не сработала ни одна из меток.

Работу оператора switch проще понять на конкретных примерах. Давайте предположим, что нам нужно делать выбор одного из пунктов меню:

1. Learning C language
2. Learning Python language
3. Learning Java language
4. Learning C++ language
5. Exit

Программа будет следующей:

#include <stdio.h>
 
int main(void)
{
    int item;
 
    printf("1. Learning C language\n"
           "2. Learning Python language\n"
           "3. Learning Java language\n"
           "4. Learning C++ language\n"
           "5. Exit\n");
 
    if(scanf("%d", &item) != 1) {
        printf("Error input");
        return 0;
    }
 
    switch(item) {
    case 1:
        printf("Learning C language\n");
    case 2:
        printf("Learning Python language\n");
    case 3:
        printf("Learning Java language\n");
    case 4:
        printf("Learning C++ language\n");
    case 5:
        printf("Exit\n");
    }
 
    return 0;
}

Здесь после case прописаны целочисленные числовые литералы от 1 до 5. Конечно, в реальной практике программирование этого следует избегать и не прописывать конкретные числа в программном коде. Но, так как мы с вами еще не проходили определение констант, то эти числа следует воспринимать исключительно, как учебный вариант.

Итак, когда выполнение программы доходит до оператора switch, то в нем берется значение из целочисленной переменной item и, затем, оно последовательно (сверху-вниз) сравнивается на равенство с константами (метками), записанными после ключевого слова case.

Давайте запустим программу и введем с клавиатуры число 3. В результате увидим вывод следующих строк:

Learning Java language
Learning C++ language
Exit

И этот результат часто удивляет начинающих программистов. Они ожидают здесь увидеть только выполнение одной функции printf(), связанной с меткой 3, а выполняются три функции printf(), начиная с метки 3. Именно так работает оператор switch. Как только срабатывает какая-либо метка, то далее выполняются все операторы, которые записаны после этой метки, включая операторы в других нижестоящих метках. Причем, речь идет именно о нижестоящих метках. Например, если ключевое слово case со значением 3 прописать в самом начале:

    switch(item) {
    case 3:
        printf("Learning Java language\n");
    case 1:
        printf("Learning C language\n");
    case 2:
        printf("Learning Python language\n");
    case 4:
        printf("Learning C++ language\n");
    case 5:
        printf("Exit\n");
    }

И снова выполнить программу, ввести значение 3, то увидим все выводы строк:

Learning Java language
Learning C language
Learning Python language
Learning C++ language
Exit

Прерывание выполнения оператора switch. Ключевое слово break

Может для вас такое поведение оператора switch кажется несколько неожиданным, но он работает именно так. Тогда, спрашивается, как нам можно реализовать множественный выбор так, чтобы выполнялись операторы только по одной метке, а не по всем нижестоящим? Для этого можно воспользоваться оператором break, который прерывает работу оператора switch. Например, если прописать break после каждого вызова функции printf():

    switch(item) {
    case 3:
        printf("Learning Java language\n");
        break;
    case 1:
        printf("Learning C language\n");
        break;
    case 2:
        printf("Learning Python language\n");
        break;
    case 4:
        printf("Learning C++ language\n");
        break;
    case 5:
        printf("Exit\n");
        break;
    }

То, как только он встречается, управление переходит к следующему оператору после switch. В результате, все операторы в нижестоящих метках пропускаются.

Однако часто оператор switch выносят в отдельную функцию и тогда прервать его работу можно также и с помощью оператора return. В нашем примере тоже так можно сделать, если вместо break прописать «return 0;» следующим образом:

    switch(item) {
    case 3:
        printf("Learning Java language\n");
        return 0;
    case 1:
        printf("Learning C language\n");
        return 0;
    case 2:
        printf("Learning Python language\n");
        return 0;
    case 4:
        printf("Learning C++ language\n");
        return 0;
    case 5:
        printf("Exit\n");
        return 0;
    }

Кстати, оператор return чаще применяется в практике программирования для прерывания работы оператора switch.

Конечно, как только встречается «return 0;», то функция main() завершает свою работу и все операторы, стоящие после switch выполняться уже не будут. В нашем конкретном случае, это не критично, т.к. там нет никакого значимого программного кода. Однако, если программу нужно продолжить после оператора switch, прервав его работу, то следует использовать оператор break. В этом главное отличие между «return 0» и break.

Ключевое слово default

Давайте для примера рассмотрим еще один вариант использования оператора switch. Мы с клавиатуры будем вводить символ буквы (малой или большой) и выводить соответствующее сообщение на экран:

#include <stdio.h>
 
int main(void)
{
    char item;
 
    if(scanf("%c", &item) != 1) {
        printf("Error input");
        return 0;
    }
 
    switch(item) {
    case 'a':
    case 'A':
        printf("Symbol A\n");
        break;
    case 'b':
    case 'B':
        printf("Symbol B\n");
        break;
    case 'c':
    case 'C':
        printf("Symbol C\n");
        break;
    }
 
    return 0;
}

Обратите внимание на два момента. Первый, метки для малой и заглавной букв следуют друг за другом, причем, блок операторов записан только у второй метки, а первая идет без операторов. Благодаря этому мы можем и для малой и для большой буквы выполнять одни и те же операторы, что довольно удобно. И второй момент. В качестве меток используются символы. В действительности, как мы с вами уже говорили, символы при трансляции программы в машинный код, преобразуются в целые числа и, по сути, представляют собой целочисленные константы. Именно поэтому символы можно прописывать наряду с целыми числами после ключевого слова case.

Если мы запустим эту программу и введем символ, который не указан в метках, например, буквы d, то на экран ничего выведено не будет. Оператор switch просто завершит свою работу, а, затем, завершится и вся программа. Давайте сделаем так, чтобы при вводе не указанного символа на экран выводилась строка «Incorrect symbol». Сделать это очень просто, используя ключевое слово default, следующим образом:

    switch(item) {
    case 'a':
    case 'A':
        printf("Symbol A\n");
        break;
    case 'b':
    case 'B':
        printf("Symbol B\n");
        break;
    case 'c':
    case 'C':
        printf("Symbol C\n");
        break;
    default:
        printf("Incorrect symbol\n");
    }

То есть, операторы по метке default отрабатывают в том случае, когда не сработала ни одна из меток case. Причем определение default может быть записано в любом месте оператора switch, но, как правило, его пишут в самом конце.

Рекомендации по использованию оператора switch

Вы могли заметить, что запись оператора switch занимает немало строк, даже в самых простых задачах. В реальной практике он нередко разрастается до больших размеров и затрудняет восприятие текста программы. Поэтому есть несколько рекомендаций, которых следует придерживаться при использовании оператора switch:

  • оператор switch лучше выносить в отдельную функцию и прерывать его работы с помощью оператора return;
  • программу следует организовывать так, чтобы после каждой метки case прописывался вызов некоторой функции вместо набора операторов;
  • никогда в программах не используйте вложенные операторы switch.

Практический курс по C/C++: https://stepik.org/course/193691

Видео по теме