Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР6-С++-27 марта-2012.doc
Скачиваний:
17
Добавлен:
28.08.2019
Размер:
6.55 Mб
Скачать

1.12. Оператор множественного выбора switch

Оператор if может передать управление только на две ветви. Для организации множественного ветвления необходимо использовать вложенные операторы if- else. Глубоко вложенные конструкции if . . .else могут часто быть вполне коррект­ны синтаксически, однако неправильно отражать логику программы. Дело в том, что заметить логическую ошибку в разветвленном наборе операторов if. . .else до­вольно сложно. Добавление новых условий и логических операторов, а также внесе­ние других изменений, тоже вполне может стать источником проблем. Но, в С++ есть более удобный способ реализации множественного ветвления, – оператор переключатель switch.

Общая форма оператора выбора (рис. 6.18):

switch (выражение_выбора E)

{

case k1: оператор S1; break;

case k2: оператор S2; break;

…………………………… ……

case kn: оператор Sn; break;

default: оператор Sn+1;

}

Здесь выражение_выбора E – любое выражение, дающее целое значение (в том числе – символьное), чаще всего переменная целого типа;

k1, k2, …, kn – константы или константные выражения – возможные значения выражения_выбора E (например, i, 5, 2*g, 'a'-'b', '1") – записываются после слова case;

оператор S1, оператор S2, …, оператор Sn, оператор S n+1 – простые или составные операторы языка.

Выражение

k1

k2

kn

иначе

оператор S1

оператор S2

………

оператор Sn

оператор Sn+1

Рис. 6.7. Структура команды выбора, соответствующая оператору switch

с оператором break после каждого case

Схема выполнения оператора switch следующая:

1. Вычисляется значение выражения_выбора E в круглых скобках. Результат этого выражения должен быть целым числом.

2. Вычисленное значение последовательно сравниваются с константными выражениями k1, k2, …, kn, следующими за меткой case;

3. При совпадении значения выражения_выбора Е с одним из константных выражений ki выполняется оператор opi. Затем управление передается оператору, стоящему после следующего case, если после opi нет оператора break. Если после оператора opi есть оператор break, то управление передается на оператор, следующий после оператора switch.

4. Если выражение_выбора Е не совпало ни с одним константным выражением k1, k2, …, kn, то управление передается на метку default и выполняется оператор opn+1, стоящий после default, а затем оператор, следующий после оператора switch. При отсутствии метки default выполняется следующий после switch оператор.

Помните:

  • отметим, что в теле оператора switch можно использовать вложенные операторы switch, при этом в ключевых словах case можно использовать одинаковые константные выражения;

  • конструкция со словом default может быть не последней в теле оператора switch;

  • ключевые слова case и default в теле оператора switch существенны только при начальной проверке, когда определяется начальная точка выполнения тела оператора switch;

  • все операторы, между начальным оператором и концом тела, выполняются вне зависимости от ключевых слов, если только какой-то из операторов не передаст управления из тела оператора switch;

  • необходимо позаботится о выходе из case, если это необходимо. Чаще всего для этого используется оператор break;

  • для того, чтобы выполнить одни и те же действия для различных значений выражения, можно пометить один и тот же оператор несколькими ключевыми словами case.

Внимание: обратите внимание, что оператор break и метка default в конструкции оператора switch могут отсутствовать, и в этом случае поведение оператора switch будет оличаться от классического.

Порядок выполнения внутри оператора switch

Очень важно понять, как именно осуществляется передача управления внутри оператора switch.

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

Иногда такое поведение действительно оправданно. Например, необходимо выпол­нять код, начиная с определенной метки и до конца, включая код следующих меток. Однако чаще всего следует выполнять только тот участок кода, который относится к данной метке. Чтобы исключить выполнение кода последующих меток case, необ­ходимо при помощи оператора break указать явно, что на этом выполнение пре­кращается. Поэтому в большинстве случаев последним оператором метки case яв­ляется оператор break.

Для выяснения механизма действия оператора break рекомендуется рассмотреть два примера из данной работы (6.35 и пример из задания см. 2.4.3.3). Практически схожие программы дают совершенно разные результаты благодаря наличию или отсутствию оператора break.

Оператор break

Оператор break завершает выполнение ближайшего из вложенных операторов while, do. . .while, for или switch. Выполнение возобновляется с оператора, расположенного непосредственно после завершенного оператора.

Оператор break может располагаться только внутри цикла или оператора switch. Внутри оператора if оператор break может присутствовать только тогда, когда оператор if находится внутри оператора switch или цикла. Оператор break вне цикла или оператора switch приводит к ошибке во время компиляции. Когда оператор break встречается внутри вложенного оператора switch или цикла, он воздействует только на внутренний цикл или оператор switch, не затрагивая внешний.

Операторы break нужны не всегда

Существует одна стандартная ситуация, когда оператор break после метки case не нужен, а программа должна выполнять код нескольких меток. Речь идет о случае, когда та же последовательность действий должна выполняться для нескольких воз­можных значений. С меткой case может быть связано только одно значение. Чтобы указать диапазон значений, метки case располагают последовательно, одна после другой. Смотрите пример 6.35.

Ситуация, когда оператор break преднамеренно пропускают для того, чтобы по­следовательно выполнять код нескольких разделов case, начиная с текущего случая, встречается крайне редко.

Рекомендация: Случаи, когда оператор break пропускают преднамеренно, довольно редки, поэтому их следует обязательно комментировать, объясняя логику действий.

Метка default

Метка default является эквивалентом директивы else. Если ни одна из меток case не соответствует значению выражения оператора switch, выполняются опе­раторы, расположенные после метки default.

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

Метка не может быть автономный; она должна предшествовать оператору. Если оператор switch заканчивается разделом default, в котором не осуществляется никаких действий, за меткой default должен следовать пустой оператор.

Выражение выбора switch и метки case

Выражение выбора оператора switch может иметь любую сложность. В частности, здесь можно определить и инициализировать переменную.

switch (int ival = get__response () )

В данном случае создается целочисленная переменная ival, которая инициали­зируется результатом обращения к функции get__response (). Именно это значе­ние и будет сравниваться со значением каждой метки case. Переменная ival суще­ствует на протяжении всего оператора switch, но не вне его.

Метки case должны содержать целочисленные выражения. Например, примеры следующих меток приводят к ошибкам во время компиляции.

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

case 3.14: // не целое число

case ival: // не константа

Ошибкой будет также случай, когда две метки case содержат одинаковое значение.

Рассмотрим примеры решения задач с использованием оператора выбора.

Пример 6.32

Фрагмент, приведенной ниже программы, иллюстрирует использование вложенных операторов if для выбора выражения в соответствии со знаком арифметической операции:

char ZNAC;

int x,y,z;

if (ZNAC == '-') x = y - z;

else if (ZNAC == '+') x = y + z;

else if (ZNAC == '*') x = y * z;

else if (ZNAC == '/') x = y / z;

else ...

Реализуем эти же действия с помощью оператора switch:

char ZNAC;

int x,y,z;

switch (ZNAC)

{

case '+': x = y + z; break;

case '-': x = y - z; break;

case '*': x = y * z; break;

case '/': x = u / z; break;

default : ;

}

Отметим, что во втором случае структура программы стала более понятной и однозначной для восприятия.

Пример 6.33

Следующая программа LR6-33.cpp использует оператор switch для вывода сообщения, основываясь на текущей оценке студента/

/* Пример 6.33*/

#include <iostream.h>

int main()

{    char grade = 'В';

  switch (grade)

      {           case 'A': cout << "Поздравляем, вы получили А" << endl; break;

        case 'В': cout << "Хорошо, у вас В" << endl; break;

        case 'С': cout << "У вас всего лишь С" << endl; break;

        case 'D': cout << "Плохо, у вас D" << endl; break;

default: cout << "Ужасно! Учите лучше!" << endl; break;

    }

getch();

return();

}

Найдите время для эксперимента с этой программой, изменяя оценку и наблюдая поведение программы. Если же ни один из указанных вариантов не соответствует условию, то выполняется вариант default.

Обратите внимание на использование оператора break в каждом варианте предыдущей программы. Оказывается, если C++ встречает вариант, соответствующий условию оператора switch, то он подразумевает, что все последующие варианты тоже соответствуют условию. Оператор break указывает C++ завершить текущий оператор switch и продолжить выполнение программы с первого оператора, следующего за оператором switch. Если вы удалите операторы break из предыдущей программы, то программа выведет не только требуемое сообщение, но и сообщение для всех последующих вариантов (потому что если один вариант является истинным, то и все последующие варианты в C++ рассматриваются как истинные).

Пример 6.34

Покажем, как можно использовать оператор switch для управления алгоритмом с консоли, например, при организации меню пользователя. Значение кода нажатой пользователем клавиши управляет выбором ветви алгоритма. Код клавиши возвращает функция getch(). Если нажата одна из функциональных (управляющих) клавиш, то функция возвращает 0 (0хЕ0). Ее повторный вызов получает расширенный код клавиши.

// Пример 6.34

int main ()

{int key;

do

{

printf ("Выберите действие\n");

key = getch();

if ( key = = 0 ) // Нажата управляющая клавиша.

{

key = getch(); // Ввод не повторяется, символ получен из буфера ввода.

switch key // Значение key управляет ветвлением.

{

case 77: {printf ("Стрелка вправо\n"; break;)}

case 75: {printf ("Стрелка влево\n"; break;)}

case 72: {printf ("Стрелка вверх\n"; break;)}

case 80: {printf ("Стрелка вниз\n"; break;)}

case 27: {printf ("Esc\n"; break;)}

default: {printf ("Не стрелка\n";

}

}

}

} while (key != 27); // Выход из цикла по нажатию Esc.

} // End of main

Пример 6.35.

Задан номер текущего дня недели. Вывести названия дней, оставшихся до конца недели, включая текущий день.

Решение. Возможные значения номера дней недели (обозначим их через n) – это числа 1-7. При вводе числа 1 программа должна выводить названия "Понедельник ", "Вторник ", …, "Воскресенье", при вводе числа 2 – названия "Вторник ", …, "Воскресенье". И т.д. При вводе числа 7 – только название "Воскресенье". При вводе любого другого числа – сообщение "Неправильно введен номер дня недели". Реализация выбора из такого множества вариантов может быть осуществлена с помощью оператора switch (k). Ниже приведен текст программы с оператором switch(k), в котором только после последнего case есть оператор break;, по которому и происходит выход из switch и переход на следующий оператор программы (fflush(stdin);) для k=1-7. Если k1-7, то выполнится оператор puts ("Неправильно введен номер дня недели");, стоящий после default, затем следующий оператор программы (fflush(stdin);).

/* Программа задачи 6.35 */

#include <stdio.h>

#include <math.h>

main()

{

int k; // Номер дня недели

puts("Введите номер дня недели");

scanf("%d",&k);

printf("До конца недели:\n");

switch (k)

{

case 1: puts("Понедельник ");

case 2: puts ("Вторник ");

case 3: puts ("Среда ");

case 4: puts ("Четверг ");

case 5: puts ("Пятница ");

case 6: puts ("Суббота ");

case 7: puts ("Воскресенье \n");

break;

default: puts ("Неправильно введен номер дня недели");

}

fflush(stdin); getchar();

return(0);

}

Пример 6.36.

Ввести символ и определить, является ли он цифрой.

Данный пример показывает, что после case ki : может не быть оператора.

Решение. Пусть k – вводимый символ. В программе использованы операторы ввода-вывода в стиле Си.

/*Программа примера 6.36

#include <stdio.h>

main() {

char k;

puts("Введите символ");

k=getchar();

switch (k)

{

case '1':

case '2':

case '3':

case '4':

case '5':

case '6':

case '7':

case '8':

case '9':

case '0':printf("Это число %c\n",k);

break;

default: printf("%c-не число\n",k);

}

fflush(stdin);

getchar();

return(0);

}

Пример 6.37.

Дано целое число в диапазоне 1 – 5. Вывести строку — словесное описание соответствующей оценки (1 — "плохо", 2 — "неудовлетворительно", 3 — "удовлетворительно", 4 — "хорошо", 5 — "отлично").

В примере используется оператор выбора с оператором break после каждого case ki :

Решение. В программе N- число, которое вводится, а затем анализируется. Если ввести, например 4, то программа выведет слово "Хорошо", а если ввести 7, то программа выведет строку "Нет оценки" и т.д. В программе использованы операторы ввода-вывода в стиле Си++.

/*Программа примера 6.37

#include <stdio.h>

#include <iostream.h>

main()

{

int N;

cout << "\nВведите число ";

cin >> N;

switch (N)

{

case 1: cout << "\nПлохо";

break;

case 2: cout << "\nНеуд.";

break;

case 3: cout << "\nУдовл.";

break;

case 4: cout << "\nХорошо";

break;

case 5: cout << "\nОтлично";

break;

default: cout << "\nНет оценки ";

}

fflush(stdin);

getchar();

return(0);

}