С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 35
Текст из файла (страница 35)
В данном случае каждая меткаcasecasecasecase'a':'e':'i':'o':представляет одну из гласных латинского алфавита:case 'u':•последовательности инструкций, соотносимых с метками case. В нашемпримере с каждой меткой будет сопоставлена инструкция, увеличивающаязначение соответствующего счетчика;•необязательной метки default, которая является аналогом части elseинструкции if-else.
Инструкции, соответствующие этой метке, выполняются,если условие не отвечает ни одной из меток case. Например, мы можемподсчитать суммарное количество встретившихся символов, не являющихсяdefault: // любой символ, не являющийся гласнойгласными буквами:++non_vowe1_cnt;Константное выражение в метке case должно принадлежать к целому типу, поэтому// неверные значения метокcase 3.14: // не целоеследующие строки ошибочны:case ival: // не константаКроме того, две разные метки не могут иметь одинаковое значение.Выражение условия в инструкции switch может быть сколь угодно сложным, в томчисле включать вызовы функций.
Результат вычисления условия сравнивается с меткамиcase, пока не будет найдено равное значение или не выяснится, что такого значения нет.Если метка обнаружена, выполнение будет продолжено с первой инструкции после нее,если же нет, то с первой инструкции после метки default (при ее наличии) или послевсей составной инструкции switch.198С++ для начинающих199В отличие от if-else инструкции, следующие за найденной меткой, выполняются другза другом, проходя все нижестоящие метки case и метку default.
Об этом частозабывают. Например, данная реализация нашей программы выполняется совершенно не#include <iostream>int main(){char ch;int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0;while ( cin >> ch )// Внимание! неверная реализация!switch ( ch ) {case 'a':++aCnt;case 'e':++eCnt;case 'i':++iCnt;case 'o':++oCnt;case 'u':++uCnt;}cout <<<<<<<<<<"Встретилась"Встретилась"Встретилась"Встретилась"Встретиласьa:e:i:o:u:\t"\t"\t"\t"\t"<<<<<<<<<<aCnteCntiCntoCntuCnt<<<<<<<<<<'\n''\n''\n''\n''\n';так, как хотелось бы:}Если значение ch равно i, выполнение начинается с инструкции после case 'i' и iCntвозрастет на 1. Однако следующие ниже инструкции, ++oCnt и ++uCnt, такжевыполняются, увеличивая значения и этих переменных.
Если же переменная ch равна a,изменятся все пять счетчиков.Программист должен явно дать указание компьютеру прервать последовательноевыполнение инструкций в определенном месте switch, вставив break. В абсолютномбольшинстве случаев за каждой метке case должен следовать соответствующий break.break прерывает выполнение switch и передает управление инструкции, следующей зазакрывающей фигурной скобкой, – в данном случае производится вывод. Вот как этодолжно выглядеть:С++ для начинающихswitch ( ch ) {case 'a':++aCnt;break;case 'e':++eCnt;break;case 'i':++iCnt;break;case 'o':++oCnt;break;case 'u':++uCnt;break;}Если почему-либо нужно, чтобы одна из секций не заканчивалась инструкцией break, тожелательно написать в этом месте разумный комментарий. Программа создается нетолько для машин, но и для людей, и необходимо сделать ее как можно более понятнойдля читателя. Программист, изучающий чужой текст, не должен сомневаться, было линестандартное использование языка намеренным или ошибочным.При каком условии программист может отказаться от инструкции break и позволитьпрограмме провалиться сквозь несколько меток case? Одним из таких случаев являетсянеобходимость выполнить одни и те же действия для двух или более меток.
Это можетпонадобиться потому, что с case всегда связано только одно значение. Предположим, мыне хотим подсчитывать, сколько раз встретилась каждая гласная в отдельности, насинтересует только суммарное количество всех встретившихся гласных. Это можноint vowelCnt = 0;// ...switch ( ch ){// любой из символов a,e,1,o,u// увеличит значение vowelCntcase 'a':case 'e':case 'i':case 'o':case 'u':++vowe1Cnt;break;сделать так:}Некоторые программисты подчеркивают осознанность своих действий тем, чтопредпочитают в таком случае писать метки на одной строке:200С++ для начинающих201switch ( ch ){// допустимый синтаксисcase 'a': case 'e':case 'i': case 'o': case 'u':++vowe1Cnt;break;}В данной реализации все еще осталась одна проблема: как будут восприняты слова типаUNIXНаша программа не понимает заглавных букв, поэтому заглавные U и I не будутswitch ( ch ) {case 'a': case++aCnt;break;case 'e': case++eCnt;break;case 'i': case++iCnt;break;case 'o': case++oCnt;break;case 'u': case++uCnt;break;'A':'E':'I':'O':'U':отнесены к гласным.
Исправить ситуацию можно следующим образом:}Метка default является аналогом части else инструкции if-else. Инструкции,соответствующие default, выполняются, если условие не отвечает ни одной из метокcase. Например, добавим к нашей программе подсчет суммарного количества согласных:С++ для начинающих202#include <iostream>#include <ctype.h>int main(){char ch;int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0,consonantCount=0;while ( cin >> ch )switch ( ch ) {case 'a': case 'A':++aCnt;break;case 'e': case 'E':++eCnt;break;case 'i': case 'I':++iCnt;break;case 'o': case 'O':++oCnt;break;case 'u': case 'U':++uCnt;break;default:if ( isa1pha( ch ) )++consonantCnt;break;}cout <<<<<<<<<<<<<<"Встретилась"Встретилась"Встретилась"Встретилась"Встретилась"Встретилось'\n';a: \t" << aCnte: \t" << eCnti: \t" << iCnto: \t" << oCntu: \t" << uCntсогласных: \t"<<<<<<<<<<<<'\n''\n''\n''\n''\n'consonantCnt}isalpha() – функция стандартной библиотеки С; она возвращает true, если ее аргументявляется буквой.
isalpha() объявлена в заголовочном файле ctype.h. (Функции изctype.h мы будем рассматривать в главе 6.)Хотя оператор break функционально не нужен после последней метки в инструкцииswitch, лучше его все-таки ставить. Причина проста: если мы впоследствии захотимдобавить еще одну метку после case, то с большой вероятностью забудем вписатьнедостающий break.Условная часть инструкции switch может содержать объявление, как в следующемпримере:switch( int ival = get_response() )ival инициализируется значением, получаемым от get_response(), и это значениесравнивается со значениями меток case.
Переменная ival видна внутри блока switch,но не вне его.С++ для начинающихПомещать же инструкцию объявления внутри тела блока switch не разрешается. Данныйcase illegal_definition:// ошибка: объявление не может// употребляться в этом местеstring file_name = get_file_name();// ...фрагмент кода не будет пропущен компилятором:break;Если бы разрешалось объявлять переменную таким образом, то ее было бы видно во всемблоке switch, однако инициализируется она только в том случае, если выполнениепрошло через данную метку case.Мы можем употребить в этом месте составную инструкцию, тогда объявлениепеременной file_name будет синтаксически правильным. Использование блокагарантирует, что объявленная переменная видна только внутри него, а в этом контекстеcase ok:{// окstring file_name = get_file_name();// ...она заведомо инициализирована. Вот как выглядит правильный текст:break;}Упражнение 5.5Модифицируйте программу из данного раздела так, чтобы она подсчитывала не толькобуквы, но и встретившиеся пробелы, символы табуляции и новой строки.Упражнение 5.6Модифицируйте программу из данного раздела так, чтобы она подсчитывала такжеколичество встретившихся двухсимвольных последовательностей ff, fl и fi.Упражнение 5.7Найдите и исправьте ошибки в следующих примерах:switch ( ival ) {case 'a': aCnt++;case 'e': eCnt++;default: iouCnt++;(a)}(b)203С++ для начинающихswitch ( ival ) {case 1:int ix = get_value();ivec[ ix ] = ival;break;default:ix = ivec.sizeQ-1;ivec[ ix ] = ival;}switch ( ival ) {case 1, 3, 5, 7, 9:oddcnt++;break;case 2, 4, 6, 8, 10:evencnt++;break;(c)}int iva1=512 jva1=1024, kva1=4096;int bufsize;// ...switch( swt ) {case ival:bufsize = ival * sizeof( int );break;case jval:bufsize = jval * sizeof( int );break;case kval:bufsize = kval * sizeof( int );break;(d)}enum { illustrator = 1, photoshop, photostyler = 2 };switch ( ival ) {case illustrator:--i11us_1icense;break;case photoshop:--pshop_1icense;break;case photostyler:--psty1er_license;(e)break;204С++ для начинающих205}5.5.