2.16 switch 多项选择结构
前面介绍了if单项选择结构和if/else双项选择结构。有时算法中包含一系列判断,用一个变量或表达式测试每个可能的常量值,并相应采取不同操作。C++提供的switch多项选择结构可以进行这种判断。
switch结构包括一系列case标记和一个可选default情况。图2.22中的程序用switch计算学生考试的每一级人数。
// Fig. 2.22:fig02 22.cpp // Counting letter grades #include int main(){ int grade, // one grade aCount = 0, // number of A's bCount = 0, // number of B's cCount = O, // number of C's dCount = 0, // number of D's fCount = 0; // number of F's cout << "Enter the letter grades." << endl << "Enter the EOF character to end input." << endl; while ( ( grade = cin.get() ) != EOF ) { switch ( grade ) { // switch nested in while case 'A': // grade was uppercase a case 'a': // or lowercase a ++aCount; break; // necessary to exit switch case 'B': // grade was uppercase B case 'b': // or lowercase b ++bCount; break; case 'C': // grade was uppercase C case 'c': // or lowercase c ++cCount; break; case 'D': // grade was uppercase D case 'd': // or lowercase d ++dCount; break; case 'F': // grade was uppercase F case 'f': // or lowercase f ++fCount; break; case '\n': // ignore newlines, case '\t': // tabs, case ' ': // and spaces in input break; default: // catch all other characters cout << "Incorrect letter grade entered." << "Enter a new grade." << endl; break; // optional } } cout << "\n\nTotals for each letter grade are:" "\nA: "<< aCount << "\nB: " << bCount << "\nC: "<< cCount << "\nD: "<< dCount << "\nF: "<< fCount << endl; return 0; }
输出结果:
Enter the letter grades. Enter the EOF character to end input. A B C C A D F C E Incorrect letter grade entered. Enter a new grade. D A B Totals for each letter grade are: A: 3 B: 2 C: 3 D: 2 F: 1
图 2.22 使用switch举例
程序中,用户输入一个班代表成绩的字母。在while首部中:
while( (grade=cin.get()) !=EOF)
首先执行参数化赋值(grade=cin.get())。cin.get()函数从键盘读取一个字符,并将这个字符存放在整型变量grade中。cin.get()中使用的圆点符号将在第6章中介绍。字符通常存放在char类型的变量中,但是,C++的一个重要特性是可以用任何整数数据类型存放字符,因为它们在计算机中表示为1个字节的整数。这样,我们根据使用情况,可以把把字符当作整数或字符。例如,下列语句:
cout << "The character(" <<'a' << ") has the value " << static_cast <int> ('a') << endl;
打印字符a及其整数值如下所示:
The character (a) has the value 97
整数97是计算机中该字符的数字表示。如今许多计算机都使用ASCII(American Standard Code for lnformation Interehange,美国标准信息交换码)字符集(character set),其中97表示小写字母“a”。附录中列出了ASCII字符及其十进制值的列表。
赋值语句的整个值为等号左边变量指定的值。这样,赋值语句grade=cin.get()的值等于cin.get()返回的值,赋给变量grade。
赋值语句可以用于同时初始化多个变量。例如:
a = b = c = 0
首先进行赋值c=o(因为:运算符从右向左结合),然后将c=0的值赋给变量b(为0),最后将b=(c=0)的值赋给变量a(也是0)。程序中,赋值语句grade=cin.get()的值与EOF值(表示文件结束的符号)比较。我们用EOF(通常取值为-1)作为标记值。用户输入一个系统识别的组合键,表示文件结束,没有更多要输入的数据。EOF是<iostream.h>头文件中定义的符号化整型常量。如果grade的取值为EOF,则程序终止。我们选择将这个程序中的字符表示为int,因为EOF取整数值(通常取值为-1)。
可移植性提示2.2
表示文件结束的组合键与系统有关。
可移植性提示2.3
测试符号化常量EOF而不是测试-1能使程序更容易移植。ANSI标准要求EOF取负整数值,但不一定是-1。这样,EOF在不同系统中可能取不同的值。
在UNIX和许多其他系统中.表示文件结束的输入如下:
<ctrl-d>
即同时按ctrl键和d键。而在DEC公司的VAX VMS或Microsoft公司的MS-DOS等系统中,表示文件结束的输人如下:
<ctrl-z>
用户通过键盘输入成绩。按Enter(或Return)键时,cin.get()函数一次读取一个字符。如果输入的字符不是文件结束符,则进入switch结构。关键字switch后面是括号中的变量名grade,称为控制表达式(controlling expression)。控制表达式的值与每个case标记比较。假设用户输入成绩c,则c自动与switch中的每个case比较。如果找到匹配的(case'C:'),则执行该case语句。对于字母C的case语句中.cCount加1,并用break语句立即退出switch结构。注意,与其他控制结构不同的是,有多个语句的case不必放在花括号中。
break语句使程序控制转到switch结构后面的第一条语句。break语句使switch结构中的其他case不会一起运行。如果switch结构中不用break语句,则每次结构中发现匹配时,执行所有余下case中的语句(这个特性在几个case要完成相同操作时有用,见图2.22的程序)。如果找不到匹配,则执行default case并打印一个错误消息。
每个case有一个或几个操作。switch结构与其他结构不同,多个语句的case不必放在花括号中。图2.23显示了一般的swish多项选择结构(每个case用一个break语句)的流程图。
从流程图中可以看出,case末尾的每个break语句使控制立即退出switch结构。注意,流程图(除了小圆框和流程之外)也只能包含矩形框和菱形框。这是我们强调的操作/判断编程模型。程序员的任务就是根据算法需要用堆栈和嵌套两种方法组合其他几种控制结构,然后填入算法所要的操作和判断,从而生成程序。嵌套控制结构很常见,但程序中很少出现嵌套swilch结构。
常见编程错误2.19
switch结构中需要break语句时而忘记使用break语句是十逻辑措误。
常见编程错误2.20
省略switch结构中case字样与测试值之间的空格可能造成逻辑错误。例如,写成case3:而不是写成case 3:只会生成一个无用标号(详见第18章)。这样,switch结构的控制表达式取值为3时,switch结构不会进行相应操作。
编程技巧2.26
应在switch结构中提供default case。switch语句中没有显式测试的case在没有default case时自动忽略。而包括default case则可以提醒程序员需要处理异常条件,但有时也不需要default处理。
编程技巧2.27
尽管swish结构中的case语句和default case语句可以按任何顺序出现,但比较好的编程习惯是把default case放在最后。
编程技巧2.18
把default case放在switch结构中的最后不需要break语句。有些程序更加上这个break以使程序更清晰,并和其他case对称。
在图2.22中的switch结构中,第46到第49行:
case '\n': case '\t': case ' ' : break;
使程序跳过换行符、制表符和空白字符。一次读取一个字符可能造成一些问题。要让程序读取字符,就要按键盘上的Enter键将字符发送到计算机中,在要处理的字符后面输入换行符。这个换行符通常需要特殊处理,才能使程序正确工作。通过在switch结构中包含case语句,可以防止在每次输入中遇到换行符、制表符或空格时default case打印错误消息。
常见编程错误2.21
一次读取一个字符时不处理输入中遇到的换行符和其他空白字符可能造成逻辑错误。
注意几个标号列在一起时(如图2.22中的case'D':case 'd':)表示每case发生一组相同的操作。
使用switch结构时,记住它只用于测试常量整型表达式(constant integral expression),即求值为一个常量整数值的字符常量和整型常量的组合。字符常量表示为单引号中的特定字符(如,'A'),而整型常量表示为整数值。
本书介绍面向对象编程时,会介绍实现switch逻辑的更精彩方法。我们使用多态方法生成比使用switch逻辑的程序更清晰、更简洁、更易维护和扩展的程序。
C++之类可移植语言应有更灵活的数据类型长度,不同应用可能需要不同长度的整数。C++提供了几种表示整数的数据类型。每种类型的整数值范围取决于特定的计算机硬件。除了类型int和char外,C++还提供short(short int的缩写)和long(long int的缩写)类型。short整数的取值范围是±32767。
对于大多数整数计算,使用long类型的整数已经足够。long整数的取值范围是±2147483647。在大多数系统中,int等价于short或long。int的取值范围在short和long的取值范围之间。char数据类型可以表示计算机字符集中的任何字符,char数据类型也可以表示小整数。
可移植性提示 2.4
由于int的长度随系统不同而不同,因此如果要处理超过±32767的数值,应使用long整数,以便在几个不同计算机系统中运行。
性能提示2.7
在内存有限或要求执行速度的面向性能的情况中,可以考虑用较小的整数长度。
性能提示 2.8
如果操作程序的机器指令不如自然长度整数那么有效(例如要进行符号扩展),则用较小的整数长度会使程序减慢。
常见编程错误2.22
在switch结构中提供相同的case标号是个语法错误。