第3章控制语句 使用高级语言编写的程序是由控制语句组成的。普通的语句都是顺序执行的,即按照先后顺序一条一条地执行。除此之外,C++还提供了两种结构的控制语句——选择结构和循环结构。 3.1选择结构 选择结构的语句是用于根据条件控制程序的执行流向,是程序中最常用的语句。C++的选择结构包含以下几种语句: ifelse选择语句、嵌套的ifelse语句、ifelse if语句和switch语句。 3.1.1ifelse选择语句 ifelse选择语句的语法结构为: if (表达式)语句1; else语句2; 执行顺序为: 首先求出表达式的值,如果表达式的值为true或为非零值,则执行语句1; 若表达式的值为false或0,则执行语句2。图3.1为ifelse语句的流程图。 图3.1ifelse语句流程图 ifelse语句中的语句1和语句2可以是一条语句,也可以是由花括号括住的多条语句。语句2可以为空,当语句2为空时,else可以省略。 例3.1输入两个数,判断是否相等,并输出判断结果。 #include<iostream> using namespace std; void main() { int i,j; cin>>i>>j; if(i==j) cout<<"i==j"<<endl; else cout<<"i!=j"<<endl; } 图3.2为例3.1程序的运行结果。 图3.2例3.1程序的运行结果 3.1.2嵌套的ifelse语句 如果在if或else后面的语句中又出现了ifelse语句,这种结构就是嵌套的ifelse语句。其语法形式为: if(表达式1) if(表达式2)语句1 else语句2 else if(表达式3)语句3 else语句4 其中的语句1、2、3、4可以是由花括号括住的多条语句。 嵌套的ifelse语句构成了一个梯级选择结构,可以完成复杂的逻辑判断,使用非常频繁。使用时需注意else和if的匹配问题 ,即确定else和哪个if属于同一个逻辑层次。匹配的原则是: else和它前面的最近一个没有被花括号括住的if相匹配。 例3.2输入两个整数,比较它们的大小并输出比较结果。 #include<iostream> using namespace std; void main() { int i,j; cin>>i>>j; if(i!=j) if(i>j) cout<<"i>j"<<endl; else cout<<"i<j"<<endl; else cout<<"i=j"<<endl; } 例3.2程序的运行结果如图3.3所示。 图3.3例3.2程序的运行结果 3.1.3ifelse if语句 ifelse if语句语法形式如下: if (表达式1) 语句1; else if (表达式2) 语句2; else if (表达式3) 语句3; ︙ else 语句n 这是一种常用的选择结构,它和如下梯级结构的嵌套ifelse语句是等价的,只是为了容易理解和书写格式清晰而使用的另一种写法。 if (表达式1) 语句1; else if (表达式2) 语句2; else if (表达式3) 语句3; ︙ else 语句n 例3.3用ifelse if语句编程实现例3.2的问题。 #include<iostream> using namespace std; void main() { int i,j; cin>>i>>j; if(i==j) cout<<"i=j"<<endl; else if(i<j)cout<<"i<j"<<endl; else cout<<"i>j"<<endl; } 3.1.4switch语句 对于深层嵌套的选择结构,如果所有的选择都依赖于同一个整型或字符型的变量或表达式的取值,则可以用switch语句来代替ifelse或者elseif的梯级结构。switch语句的语法形式如下: switch(变量名或表达式) { case 常量表达式1: 语句1; break; case 常量表达式2: 语句2; break; ︙ case 常量表达式n: 语句n; break; default: 语句n+1; } switch的执行顺序是: 首先求出变量或表达式的值,然后用该值分别和各case后的常量表达式的值相比较,若找到一个和该值相等的常量表达式,则执行其后的语句,语句执行完毕后,再由break语句直接退出由花括号括住的switch语句体; 如果没有找到相等的常量表达式,则执行default后的语句,语句执行完毕后退出switch语句体。图3.4为switch语句的流程图。 图3.4switch语句流程图 使用switch语句时,需注意以下几点。 (1) switch后的变量或表达式的类型必须是整型或字符型。 (2) 各case后的语句1、语句2、…、语句n和default后的语句n+1可以是一条语句也可以是多条语句; 如果是多条语句,也不使用大括号{}括住。 (3) 各个case后的常量表达式的值都不能相同。 (4) 每个case后面的break语句都可以没有。如果条件变量或表达式的值和某个case后的常量表达式的值相等,而且该case后面没有break语句,则以该case为入口点开始执行后面的语句,直到遇到第一个break语句跳出switch语句体,若其后的所有case都没有break语句,则一直执行到switch的结束点。 (5) 当多个case分支后的语句完全相同时,则可以把它们组合成一个case分支。 例3.4输入一个‘A’~‘D’的大写字符表示考试成绩的等级,并按照该等级输出对应的百分制的分数段。 #include<iostream> using namespace std; void main() { char grade; cout<<"请输入一个A到D的大写字母\n"; cin>>grade; switch(grade) { case 'A' :cout<<"85~100\n"; break; case 'B' :cout<<"70~84\n";break; case 'C' :cout<<"60~69\n";break; case 'D' :cout<<"60以下\n"; break; default : cout<<"输入的字母错误\n"; } } 例3.4程序的运行结果如图3.5所示。 图3.5例3.4程序的运行结果 3.2循环结构 循环结构的语句根据条件重复地执行程序中的某一条或某一段语句,也是程序中最常用的语句。C++包含以下几种循环结构的控制语句: while循环语句、dowhile循环语句和for循环语句。 3.2.1while循环语句 while是最常用的循环语句,其语法形式为: while(表达式) 循环体语句; 图3.6while语句流程图 其中,循环体语句部分可以是一条语句,也可以是由花括号括住的多条语句。 执行顺序如下。 (1) 先计算并判断表达式的值,若为0或false,则跳转到第(4)步。 (2) 若表达式的值非零或为true,则执行循环体中的语句。 (3) 返回第(1) 步。 (4) 退出循环体,接着执行循环体后的语句。 图3.6为while语句的流程图。 例3.5输入一个正整数n,求其阶乘n!(n!=1×2×3×…×(n-1)×n)。 #include<iostream> using namespace std; void main() { unsigned short n; int i=1; unsigned long result=1; cout<<"请输入一个不大于30的正整数\n"; cin>>n; while(i<=n) { result*=i; i++; } cout<<n<<"!="<<result<<endl; } 程序中先提示用户输入一个不大于30的正整数,这是因为阶乘值的增大速度非常快,虽然使用了无符号长整型(unsigned long)作为阶乘结果的数据类型,但是当n的值大于33后,n的阶乘值就将溢出。 变量result用来存放计算结果,其初始值为1。 循环的条件为i<=n,变量i的初值为1,每次循环中首先用i乘以result,并把乘积再赋值给result,然后执行i++。当最后退出循环时,result中的值就是n的阶乘。图3.7为例3.5程序的运行结果。 图3.7例3.5程序的运行结果 注意: 使用while语句实现循环时,在循环体中应该包含改变循环条件表达式值的语句。否则,会造成无限循环。 3.2.2dowhile循环语句 dowhile语句的语法形式如下: do 循环体语句; while(表达式); 其中,循环体语句可以是一条语句,也可以是由花括号括住的多条语句。while语句的后面一定要有分号。 语句的执行顺序如下。 (1) 先执行循环体中的语句。 (2) 计算并判断表达式的值。 (3) 若表达式的值非零或为true,则跳转到第(1) 步。否则退出循环,接着执行后面的语句。 图3.8dowhile语句流程图 图3.8是dowhile语句的流程图。 例3.6使用dowhile语句实现例3.5中求正整数阶乘的程序。 #include<iostream> using namespace std; void main() { unsigned short n; int i=1; unsigned long result=1; cout<<"请输入一个不大于30的正整数\n"; cin>>n; do { result*=i; i++; } while(i<=n); cout<<n<<"!="<<result<<endl; } while循环语句和dowhile循环语句的功能在多数情况下是等价的,然而它们也存在区别。while语句和dowhile语句的区别是: while语句是先判断循环条件,后执行循环体语句; 而dowhile语句是先执行循环体语句,后判断循环条件。如果循环条件表达式的初始值就为零或false,则while循环的循环体语句一次也不执行,而dowhile循环的循环体语句执行了一次。 3.2.3for循环语句 for循环语句的语法形式为: for(表达式1; 表达式2; 表达式3) 循环体语句; 其中,表达式1通常用来初始化循环控制变量的值,所以又叫循环控制变量初始化表达式; 表达式2用来判断是否满足循环条件,又叫循环条件表达式; 表达式3通常用来修改循环控制变量的值。循环体语句可以是一条语句也可以是由花括号括住的多条语句。 for语句的执行顺序如下。 (1) 计算表达式1的值。 (2) 计算并判断表达式2的值,若表达式2的值非零或为true,则接着执行第(3)步; 否则跳转到第(4)步。 (3) 执行循环体语句,计算表达式3的值。返回第(2)步。 (4) 退出循环,接着执行后面的语句。 图3.9是for语句的流程图。 图3.9for语句流程图 例3.7用for循环语句实现例3.5中求正整数阶乘的程序。 #include<iostream> using namespace std; void main() { unsigned short n; unsigned long result=1; cout<<"请输入一个不大于30的正整数\n"; cin>>n; for(int i=1;i<=n;i++) result*=i; cout<<n<<"!="<<result<<endl;} for语句通常用于已知循环次数的情况。 for语句的用法非常灵活,for后面的三个表达式哪个都可以被省略,也可以同时被省略。虽然表达式可以省略,但是不能省略用于分隔它们的分号。最简单的for语句如下所示: for(; ; ) {…} 这样的for循环语句和下面的while循环语句是等价的,它们都是无限循环(死循环)。 while(true) {…} 如果省略表达式1,则在程序中for循环语句的前面,应该有对循环控制变量或循环条件的初始化语句; 如果省略表达式3,则应该在循环体中包含修改循环控制变量和循环条件的语句,以防止出现死循环。 例3.8省略表达式1和3的for循环语句。 #include<iostream> using namespace std; void main() { int i=0; for(;i<=2;) { cout<<"Welcome to C++\n"; i++; } } 程序的功能是使用for循环语句输出三行字符串“Welcome to C++”。for语句中省略了表达式1和表达式3,在for语句的前面初始化循环控制变量i的值为1; 而循环体内部的语句i++在每次循环执行时,修改循环控制变量i的值。这样的for循环等价于一个类似的while循环。图3.10为例3.8程序的运行结果。 图3.10例3.8程序的运行结果 C++11新引入了一种基于范围的for循环语句,用这种for循环语句访问数组和集合中的元素时,比使用传统的for循环语句书写更加方便,程序更容易理解。本书将在第4章中结合数组介绍这种基于范围的for循环语句。 3.2.4嵌套的循环语句 如果在循环体语句中又出现了循环结构语句,就形成了嵌套的循环结构。通常把嵌套的循环语句称为多重循环语句。在嵌套的循环结构中,外部的循环叫外层循环; 而被包含在其他循环内部的循环叫内层循环。这里外层和内层都是相对而言的。 例3.9输出一个由星号*组成的三角形图案。 #include<iostream> using namespace std; void main() { for(int i=1;i<=5;i++) { for(int j=0;j<=10-i;j++) cout<<' '; for(int k=1;k<=(2*i-1);k++) cout<<'*'; cout<<endl; } } 图3.11为例3.9程序的运行结果。 图3.11例3.9程序的运行结果 程序中包含嵌套的循环结构。外层的for循环语句负责输出星号的行数。内层的第一个for循环语句负责输出每行中星号前面的空格字符; 内层的第二个for循环语句负责输出每行中的星号。 3.1.2节中介绍过选择结构if语句的嵌套,本节又介绍了循环语句的嵌套结构。选择结构和循环结构也可以相互嵌套。 C++11中新增了一种基于范围的for循环语句,这种循环语句常用于遍历数组或容器中的元素,在第4章中将详细介绍这种for循环语句。 3.3其他流控制语句 以上几节介绍了C++中实现选择和循环结构的语句。本节先介绍两个选择和循环结构中常用的有条件转移语句——break语句和continue语句; 然后介绍无条件转移语句——goto语句。 3.3.1break语句和continue语句 break语句在介绍switch语句时,已经见到过了。它用在switch语句和循环语句中,功能是: 立即从包含它的switch语句体或包含它的最内层的循环体中退出,开始顺序执行后面的语句。 continue语句用在循环语句中,功能是: 立即结束本次的循环执行,转到判断循环条件的语句判断是否进行下一次循环。 例3.10和例3.11揭示了break语句和continue语句用在循环语句中的区别。 例3.10在循环中使用break语句。 #include<iostream> using namespace std; void main() { int i=0; while(i<10) { if(i++==5) break; cout<<"欢迎学习C++\n"; } } 例3.11在循环中使用continue语句。 #include<iostream> using namespace std; void main() { int i=0; while(i<10) { if(i++==5) continue; cout<<"欢迎学习C++\n"; } } 以上两例的程序几乎完全相同,唯一的区别是: 例3.10程序的循环中使用了break语句,而例3.10程序的循环中使用了continue语句。 例3.10中,当i的值为5时,执行break语句,马上退出循环体,程序运行结束。结果是只输出了5行字符串。 例3.11中,当i的值为5时,执行continue语句,马上退出本次循环,循环体中后面的语句被跳过。但是,循环并没有终止,从i=6开始继续执行下一次循环。结果是输出了9行字符串。 break语句和continue语句只能使程序控制转到一个确定的地方,所以可以把它们叫作有条件的转移语句。 3.3.2goto语句 C++还有一个功能更加强大的转移语句——goto语句。它和语句标号相配合,可以使控制转移到程序中的任何地方,所以叫无条件转移语句。goto语句的使用会使程序的结构变得杂乱无章,违反了结构化程序设计的原理,所以应尽可能少用或不用goto语句。 小结 C++语言的控制语句形式简洁、功能强大,主要包括选择结构和循环结构两种类型。两种结构的控制语句可以相互嵌套,完成复杂的控制逻辑。 选择结构的语句用于根据条件控制程序的执行流向。C++的选择结构包含以下几种语句: ifelse选择语句、嵌套的ifelse语句、ifelse if语句和switch语句。 循环结构的语句根据条件重复地执行程序中的某一条或某一段语句。C++包含以下几种循环结构的控制语句: while循环语句、dowhile循环语句和for循环语句。 除了选择结构和循环结构的语句之外,C++还包括几个特殊的流控制语句,它们是break语句、continue语句和goto语句。 习题 3.1编写一段程序,提示用户输入一个英文字母,使用if语句判断用户输入的字母是大写 字母还是小写字母,然后输出相关信息。 3.2以下程序段输出若干行字符串“How are you!”,行数由用户输入的整数决定,如果用户输入0,则输出一行字符串“Hello!”,请找出下面程序中存在的语法错误。 int n; cout<<"请输入一个整数: "; cin>>n; if(n=0) cout<<"Hello!\n"; else for(int i=0;i<n;i++); cout<<"How are you!\n"; 3.3编写一段程序,连续输入若干个学生的考试成绩,根据成绩判断其所在的等级,并输出相关信息。判断成绩等级的规则如下: 等级= A级90≤分数≤100 B级80≤分数<90 C级70≤分数<80 D级60≤分数<70 E级分数<60 例如,如果第3个学生的成绩为82分,则应输出一行字符串“学生3的成绩为B等”。 要求使用while循环和switch选择语句。 3.4编写程序,输出右边的由星号组成的倒三角形。 ********* ******* ***** *** * 3.5请举例说明break语句和continue语句各自的用法和区别。