C++及Windows可视化程序设计第2章结构化编程基础.ppt
第2章 结构化编程基础,2.1 典型C+程序结构2.2 关系运算与逻辑运算2.3 结构化程序设计概述2.4 控制选择结构2.5 循环控制结构设计实验习题,无论采用何种编程技术,总离不开最基本的结构化程序设计思想。本章将首先结合实例简要介绍C+语言的对象在基于过程设计中的使用方法,然后结合使用对象简要介绍结构化程序的基本设计原理,既为基于过程的编程打下基础,也加深使用对象的概念。,本节将通过求圆面积的程序,介绍典型的C+程序结构,目的是结合例题复习上一章的内容,并为通过编程学习和掌握程序控制结构打下基础。【例2.1】编写一个程序,在主函数中输入圆的半径,调用函数求圆的面积。为了便于介绍,在注释中给程序语句编上号,空行是为了说明程序风格而设的。#include/1标准库头文件#include/2数学运算函数pow的头文件using namespace std;/3使用命名空间const double PI=3.14159;/4定义常量PI,2.1 典型C+程序结构,double area(double);/5函数area的原型声明void main()/6无返回值的主程序/7主函数开始double r(0),s=0;/8演示两种初始化方法coutr;/10将输入值赋给rs=area(r);/11调用area函数cout圆的面积是:sendl;/12输出结果/13主函数结束/本函数计算圆的面积 14double area(double r)/15定义area函数 returnPI*pow(r,2);/16函数体,调用pow求r的平方程序运行结果如下:请输入半径:10 圆的面积是:314.159,C+函数有库函数(标准函数)和自定义函数两类,本例求圆面积的函数area就是自定义函数。C+程序使用变量的基本规则是先声明,后使用;对函数调用也是如此。如果没有语句5,当编译主函数main扫描到语句 s=area(r);时,尚没有见到area函数,这时就会报错。所以在主函数之前使用语句5对area函数进行原型声明,即 double area(double);/函数area的原型声明,2.1.1 函数和函数原型,上面的语句声明了area的函数原型,即只列出参数的数据类型。它向编译系统声明,后面有一个area函数,该函数有一个double类型的参数,函数返回值类型也是double。编译系统记录下调用这个函数所需要的信息,然后根据函数原型对程序中调用函数的合法性进行全面的检查。因为是检查调用函数的类型是否和声明的一致,所以声明时不需要给出参数的变量名称。如果使用下述方式声明:double area(double r);因为编译系统不检查参数名,所以效果一样。为了全面严格检查调用函数是否匹配,应该养成使用函数原型声明的好习惯。,在C+中,每一个函数都有基本相同的形式:函数类型声明函数名(形式参数列表)变量声明 语句部分 函数可按任何顺序出现,且可出现在一个源程序文件或多个源程序文件中。函数定义中不可缺少的部分是:函数类型声明 函数名()其他部分根据需要来确定有无。分析函数的定义形式,可以把定义分为两部分:函数声明部分和函数体。,1.函数声明部分函数类型声明用来定义函数返回值的数据类型,可使用基本数据类型和自定义类型。C+编译系统要求必须指定类型,无返回值函数的类型为void。在C+程序里,子程序和函数是一个意思,都称为函数。函数名是识别函数的名字,可用英文字母(az,AZ)、数字及下划线(_)组成的字符序列构成,可使用长名字,而且下划线可作为名字的开始,例如_func()。在编写程序时,这些书写方法都会碰到,应该熟练地掌握它们。,形式参数列表在函数名后的圆括号“()”内,这里声明的参数是形式参数(例abs函数的int a),简称形参(亦称哑元)。当调用该函数时,形参将被实际参数(亦称实元)所替换,这种替换常叫做哑实结合。函数也可没有参数,但函数名后的圆括号“()”不能省略。2.函数体函数体是处理需要完成功能的部分,它从花括号“”开始,直到与此对应的花括号“”为止。变量说明通常接在“”的后面,接在变量说明后的是语句部分。函数体的最后是“”,表示该函数到此结束。C+中也常使用空的函数体函数。例如:void tmpc(),这里tmpc 是函数名。因为“”内没有任何可供执行的语句,所以该函数一旦被调用,就什么也不做而立即返回到调用它的函数里去,这就是C+程序的最小函数形式。这种函数有两种用途:第1种是用在程序开发时,为给将来要设置的函数事先安排一个位置,往往给函数起个暂时的名字,待以后再设计这个函数。当设计正确之后,再将它改为合适的名字。第2种是用在继承中,基类声明一个函数作为接口,由派生类根据需要去定义它的功能。,C+语言仍然可以使用宏定义。无参数的宏作为常量,而带参数的宏则可以提供比函数调用更高的效率。预处理只是进行简单的文本代替而不进行语法检查,所以会存在一些问题。例如:#define BUFSIZE 100这里的BUFSIZE 只是一个名字,不占用存储空间并且能被放在一个头文件中。在编译期间编译器将用“100”来代替所有的BUFSIZE。这种简单的置换常常会隐藏一些很难发现的错误,并且这种方法还存在类型问题。比如这个BUFSIZE 究竟是整数还是浮点数?而使用const,则把值代入编译过程即可,2.1.2 const修饰符和预处理程序,解决这些问题。和上面宏定义等效的语句如下:const int BUFSIZE=100;这样就可以在任何编译器需要知道这个值的地方使用BUFSIZE,并且编译器在编译过程中可以通过必要的计算,把一个复杂的常量表达式缩减成简单的。对于某些更复杂的情况,宏定义往往不如常量来得简洁清楚,用const 完全可以代替无参数的宏。用关键字const 修饰的标识符是一类特殊的常量,称为符号常量,或称之为const 变量。,const 修饰符的使用也很简单。事实上,对基本数据类型的变量,一旦加上const 修饰符,编译器就将其视为一个常量,不再为它分配内存,并且每当在程序中遇到它时,都用在说明时所给出的初始值取代它。使用const 可以使编译器对处理内容有更多的了解,从而对其进行类型检查,同时还能避免对常量的不必要的内存分配并可改善程序的可读性。因为被const 修饰的变量的值在程序中不能被改变,所以在声明符号常量时,必须对符号常量进行初始化,除非这个变量是用extern 修饰的外部变量。例如:,const int i=8;const int d;/错误!extern const int d;/可以const 的用处不仅仅是在常量表达式中代替宏定义。如果一个变量在生存期中的值不会改变,就应该用const 来修饰这个变量,以提高程序的安全性。,C+语言预处理程序不是C+编译程序的一部分,它负责分析处理几种特殊的语句,这些语句称为预处理语句。预处理程序对这几种特殊语句的分析处理是在编译程序的其他部分之前进行的。为了与一般的+程序语句相区别,所有预处理语句都以位于行首的符号“”开始。预处理语句有3种,它们分别是宏定义、文件包含和条件编译。C+预处理程序和有关语句能够帮助程序员编写易读、易改、易移植并便于调试的程序,对于模块化程序设计也提供了很大的帮助。例如语句 define PI 3.14159,是用名字PI来代替数字3.14159,又例如:define YES 1 define NO 0则定义 YES和NO分别是1和0。当然,在这些场合下,最好是使用const语句。预处理程序把所有出现的、被定义的名字全部替换成对应的“字符序列”。define中的名字与C+中标识符有相同的形式,为了区别,往往用大写字母来表示(标识符用小写字母)。这也适合const语句。【例2.1】中的语句1是文件包含语句,它指的是一个程序把另一个指定文件的内容包含进来。书写时,可以使用引号也可以用尖括号。例如:include filename或者 include,都是在程序中把文件filename的内容(引号或尖括号是一定要的)包含进来。另外还要注意,文件名是用双引号还是尖括号括起来,其含义并不一样。使用尖括号时,C+编译系统将首先在C+语言系统设定的目录中寻找包含文件,如果没有找到,就到指定的目录中去寻找,这是引用系统提供的包含文件所采用的方法。自己定义的包含文件一般都放在自己指定的目录中,所以在引用它们时,就采用双引号,以通知C+编译器在用户当前目录下或指定目录下寻找包含文件。指定的目录不必在同一个逻辑盘中。例如自己定义的包含文件myfile.h在E盘的prog目录中,则引用形式为 include e:progmyfile.h,在程序设计中,文件包含语句是非常有用的。一般C+系统中带有大量的.h文件,用户可根据不同的需要将相应的.h 文件包含起来。在【例2.1】中,因为要用到C+语言提供的幂运算函数pow,pow声明在数学运算库头文件math.h中,所以要用 include 语句。标准输入输出是定义在标准库 iostream.h 中的,所以要同时用到如下两条语句:include using namespace std;一般的C+程序都离不开这两条语句,初学C+语言的读者也最容易遗漏这两条语句。,一个好的程序设计者应该在程序中正确使用注释来说明整个程序的功能、注意事项及有关算法等。有人认为,注释愈多,程序的可读性和可维护性愈好,其实不然,仅需在必要的地方进行注释即可。也就是说,应该加的是程序的注释,不是对程序的说明。行的注释形式是“/”,也可使用C语言的注释方式“/*/”,但一定要配对使用。,2.1.3 程序注释,C+语言的语句是用来向计算机系统发出操作指令的。一条语句经过编译后生成若干条机器指令。一个为实现特定目的的程序应包含若干条语句,即一个C+程序可以由若干个源程序文件(分别编译的文件模块)组成,一个源文件可以由若干个函数和预编译命令组成,一个函数又由数据定义和执行语句两部分组成。一条完整的语句必须以分号“;”结束。可以把程序语句分成如下几类。,2.1.4 程序语句,1.声明语句用来声明对象的类型和初值。【例 2.1】中的第 8 条语句是把对象r和s声明为双精度的浮点对象,并赋初值为零。最好养成在声明对象的同时进行初始化。人们已经习惯于称这些对象为变量,所以在面向对象设计时,仍然喜欢称其为变量。从现实世界来看,它们确实映射着一个确定的对象。对这些简单而基本的对象,虽然习惯地称其为“变量”,但为了尽快养成使用对象思考问题的习惯,建议改称对象。,2.表达式语句由一个表达式构成一个语句,用以描述算术运算、逻辑运算或产生某种特定动作。最典型的用法是由赋值表达式构成一个赋值语句。例如:“a=3”是一个赋值表达式,而“a=3;”就是一条赋值语句。从中可以看到,在一个表达式的最后加一个分号就构成了一条语句。一条语句最后必须出现分号,分号是语句中不可缺少的一部分。例如:i=i+1/是表达式,不是语句 i=i+1;/是语句,作用是使i的值加1由此可见,任何表达式都可以加上分号而成为语句。,例如:x+y;也是一条语句,作用是完成x+y的操作,它是合法的,但没有实际意义。【例 2.1】中的语句 s=area(r);也是表达式语句。,3.程序控制语句程序控制语句是用来描述语句的执行条件与执行顺序的语句。C+语言的控制语句有if()else 条件语句for()循环语句while()循环语句 dowhile()循环语句Continue 结束本次循环语句break 中止循环或switch语句Switch 多分支选择语句 goto 转移语句Return 从函数返回语句,以上9种语句中的括号()表示其中是一个条件,表示内嵌的语句。例如一条if()else的具体语句可写成:if(xy)z=x;else z=y;详细的使用方法在后续章节叙述。4.复合语句C+语句又可分为简单语句和复合语句两种。在C+语言中,诸如表达式 x=1 和 coutx等,其后加上分号,即变成 x=1;和 coutx;这就构成了简单语句,分号是语句的终结符。,花括号“”和“”把一些语句组合在一起,使它们在语法上等价于一条简单语句,称其为复合语句(或称分程序)。例如,在下面的语句中 if(a=0)/1/2 Cout输入为:aendl;/3 return a;/4/5 else/6/7 cout输入为:aendl;/8 return(-a);/9/10,当a=0的条件成立时,执行if后的复合语句,否则执行else之后的复合语句。结束一个复合语句的右花括号之后不能带分号(语句5和10),否则有时可能会导致错误;不能遗漏在复合语句的最后一条语句与右花括号之间的分号(语句4和9)。复合语句可由若干语句组成,这些语句可以是简单语句,还可以是复合语句,这样C+语言的语句就形成了一种层次结构,原则上可以不断地扩大这种层次。复合语句在程序中是一种十分重要的结构。,5.函数调用语句这是由一次函数调用加一个分号而构成的一条语句。例如:area(r);6.空语句“;”是一条空语句。它只有一个分号,所以什么也不做。,C+语言中严格区分大小写字母,如变量 B 和 b 是完全不同的两个变量。C+语言惯用小写字母,而且以下划线“_”字符开头的标识符一般由系统内部使用,最好不要用它作为标识符的第1个字符。习惯上把使用宏定义的标识符用大写字母表示,例如将圆周率定义为 PI。,2.1.5 大小写字母的使用,C+语言的格式很自由,一行可以写几条语句。不过,使用适当的格式对于充分理解这种语言非常重要。一个适当格式的程序和一个不适当格式的程序就像一封打得很漂亮的信和一封写得非常凌乱的信,给人的印象是大不一样的。应该使源代码易于理解,特别是容易被输入这些程序的程序员所理解,这有助于复杂程序的调试及修改以前输入的代码。上面的程序就是按此原则书写的。由此可见,应使用缩进格式和必要的空行的书写风格,并使源代码具有层次性和逻辑性,以增加程序的可读性和可操作性。,2.1.6 程序的书写格式,一般来讲,每次缩进 5 个字符的位置,按程序特性设置空行。在本书中,为了节省篇幅,有意识地减少空行。读者在输入程序时,不要模仿,应注意养成良好的书写风格。在书写程序语句时,一般应注意如下规则:括号紧跟在函数名的后面,但在for和while后面,应用一个空格与左括号隔开以增加可读性。数学运算符的左右各留一个空格,以与表达式区别。在表示参数时,逗号后面留一个空格。在for、dowhile和while语句中,合理使用缩进、一对花括号和空行。,C+的cout和cin流能自动识别数据类型,根据数据类型进行读写操作,完全不需要用户设置,使用非常方便。不过,有时对输入输出仍有一定的要求,尤其是输出格式。C+提供了两种格式控制方式,一种是使用iso 类提供的接口,另一种是使用操纵符的特殊函数,它的特点是可以直接包含在输入和输出表达式中,因此更为方便。注意,不带形式参数的操纵符定义在iostream.h中,带形式参数的操纵符定义在iomanip.h中。使用它们时,一是要正确包含相应的头部文件,二是只有与符号“”连接时才起作用,三是无参数的操纵符函数不能带有“()”号。,2.1.7 数据的简单输入输出格式,这些操纵符的含义如下:名称 含 义 输入/输出Dec 设置转换基数为十进制 输入/输出Oct 设置转换基数为八进制 输入/输出hex 设置转换基数为十六进制 输入/输出showbase(int base)输出 设置base为数制的基(0,8,10,16),默认为0ws 设置跳过输入中的前导空白字符 输入ends 插入一个空字符0以结束字符串 输出endl 输出一个换行符并刷新流 输出flush 强制刷新流 输出,名称 含 义 输入/输出resetiosflags(long flag)清除flag指定的标志位 输出setiosflags(long flag)设置flag指定的标志位 输出setfill(char ch)设置ch为填充字符 输出setprecision(int n)设置浮点数输出精度n 输出setw(int width)设置输出数据字段 宽度width 输出需要说明的是resetiosflags 和setiosflags操纵符,它们的参数flag是引用C+的类ios里定义的枚举常量,所以要使用限定符。,下面是几个常用常量的含义:常量名 含 义iosleft 输出数据按输出域左边对齐输出iosright 输出数据按输出域右边对齐输出iosshowbase 输出带有一个表示制式的字符iosshowpoint 浮点输出时必须带有一个小数点iosshowpos 在正数前添加一个+号iosscientific 使用科学计数法表示浮点数iosfixed 使用定点形式表示浮点数注意:flag可以是多个常量相“与”,例如setiosflags(iosshowpoint|iosfixed)。,【例2.2】使用setw设置输出宽度的例子。#include#includeusing namespace std;void main()int a=29,b=1001;coutasetw(6)bendl;coutabendl;程序的输出为:29 1001 291001setw(6)使b按域宽为6 输出,即相当于在a 和b 之间加入了2个空格。setw(6)只对紧接着的那个元素有效。,【例2.3】在下面的程序中,当要求输入时,均输入100,给出程序的输出结果。#include#includeusing namespace std;const double PI=3.141592;void main()coutPIendl setprecision(0)PIendl setprecision(1)PIendl setprecision(2)PIendl setprecision(3)PIendl setprecision(7)PIendl;,int b=100;coutb;coutb;cout bendl;cout resetiosflags(iosshowpos);cout bendl;,输出结果如下:3.141593.1415933.13.143.141592Dec:100Hex:64Oct:144144144Input b=100144,+100Input b=100+100100setprecision(int n)是设定显示小数位数(小数点也占1位),1代表显示整数数字,2才显示小数点后面的一位数。0等于不设,由系统决定。系统只输出5位小数,为了将它全部输出,必须设置7位。由此可写出前5行输出。程序执行cout oct命令后,将保持八进制格式输出,输入100,但输出仍然按八进制,使用 cout dec命令将它恢复为十进制方式。下面语句,coutdec setiosflags(iosshowpos)b endl;还将输出设置为在正的数字前面显示“+”号。这个设置保持到使用语句 cout resetiosflags(iosshowpos);清除该设置标志为止。如果单独使用语句 resetiosflags(iosshowpos);则不起作用。,【例2.4】分析下面程序的输出。#include#includeusing namespace std;void main()coutsetfill(*)setw(0)15endl setw(1)15endl setw(2)15endl setw(3)15endl setw(4)15endl;coutsetw(16)setfill(*)endl;coutsetiosflags(iosright),setw(5)1 setw(5)2 setw(5)3endl;coutresetiosflags(iosright);coutsetiosflags(iosleft)setw(5)1 setw(5)2 setw(5)3endl;域宽n比显示位数少时,则不起作用,即不影响显示。使用填充字符时,n比显示位数大1,才发生填充作用。,如程序所示,要显示15个“*”号,必须取n=16。setfill后面使用“”才能全部填充为设定字符“*”,否则将全部填充为空格。程序中使用15个“*”填充,就是用这种方法实现的。清除设置标志之后,才能进行新的设置。程序输出如下。151515*15*15*1*2*31*2*3*,【例2.5】演示使用转义字符的例子。#includeusing namespace std;void main()coutatbn;假定系统设置制表符的一个“输出区”占8列,用代表空格,则输出为ab,程序一般是按语句的编写顺序依次执行的。但是,如果用程序来模拟现实世界,则必须控制程序执行的走向。例如问一个人吃饭没有,如果没吃饭,就给他饭吃,否则给他一杯茶水。这就是根据是否吃饭的条件决定的。为了方便理解,可以把控制流程的运算方法分为两类,即关系运算和逻辑运算。其实,关系运算是逻辑运算的简单形式。,2.2 关系运算与逻辑运算,1.关系运算符及其优先顺序关系运算又称做“比较运算”。将两个值进行比较,判断比较的结果是否符合给定的条件。条件满足为真,否则为假。例如 x5.0 是一个关系运算式,即关系表达式。若x的值是6,那么此表达式的值为真。表2.1是C+语言提供的6种关系运算符及其含义。(见书59页)4种关系运算符(,=)的优先级别相同,后2种的级别也相同。但前4种的级别高于后2种。另外,算术运算符的优先级高于关系运算符,关系运算符的优先级高于赋值运算符。,表2.1 C+语言提供6种关系运算符及其含义,2.关系表达式用关系运算符将两个表达式(可以是算术表达式或关系表达式、逻辑表达式、赋值表达式、字符表达式)连接起来的式子,称为关系表达式。例如:ab a+b=(y=7)d!=c(ab)(bc)都是关系表达式。关系表达式的值是个逻辑值,即“true”和“fasle”。C+语言有逻辑(bool)型数据类型,即ture为1,false为0。为兼容C,1代表“真”,0代表“假”。语句“bool stop=false;”的含义是“stop的逻辑值为0”。,假设a=4,b=3,c=2,对于如下的表达式,则有ab的值为“true”,表达式的值为 1。(ab)=c-1的值为“true”(因为ab值为1,等于c-1的值),表达式的值为1。a-bc,d的值为1。e=abc,e的值为0,因为“”运算符是自左至右运算,所以先算“ab”的值为1,再执行关系运算:“1c”,得值0赋给 e。,3.逻辑运算符及其优先顺序用逻辑运算符将关系表达式或逻辑量(即“true”或“false”)连接起来的式子就是逻辑表达式。C+语言提供如下3种逻辑运算符:&逻辑与(相当于其他语言中的AND)|逻辑或(相当于其他语言中的OR)!逻辑非(相当于其他语言中的NOT)和|是双目运算符;!是单目运算符。符号“|”就是键盘第1排右边的“|”号,它是上档键,而“”号是下档键。书上因为排版的字体问题,变成了一条线“|”,编程时请注意。,例如,对于a和b而言,在下面的表达式中:ab 若a、b都为真(即a、b值均不为0),则 ab为真,否则为假。ab 如a、b都为假,则ab为假,否则为真。!a 若a为真,则!a为假;若a为假,则!a为真。在一个逻辑表达式中如果包含多个逻辑运算符,应按以下的优先次序进行运算:!(非)(与)(或),!级别为最高;综合运算时为!(非)算术运算符关系运算符和赋值运算符。,4.逻辑表达式如前所述,逻辑表达式的值应该是一个逻辑量“true”或“false”。以数值1代表“true”,以0代表“false”,但判断一个量是否为“true”时,以0代表“false”,以非零代表“true”。即把一个非0数值认为“true”。例如:若a=2,则!a 的值为0。a为非0被认为“true”,对它进行非运算,得“false”,以0代表。若a=3,b=5,则 ab 的值为1。a、b为非0(即“true”),因此 ab 为true。若 a=3,b=5,则 ab 的值为1。,事实上,逻辑运算符两侧的运算对象不但可以是数值0和1,或者是0和非0的整数,也可以是任何类型的数据,可以是字符型、实型或对象等。不过要牢记,系统最终以 0 和非 0 来判定它们是属于“true”还是“false”。例如:ab的值为1(因为字母a和字母b的ASC码值都不为0,都按“true”处理)。在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。,1966年,Bohm和Jacopini首次证明了只要3种控制结构就能表达用一个入口和一个出口的框图(流程图)所能表达的任何程序逻辑。这3种控制结构是顺序结构、选择结构和循环结构。1968年Dijkstra建议:GOTO语句太容易把程序弄乱,应从一切高级语言中去掉;只用3种基本控制结构就可以写各种程序,而这样的程序可以自顶向下阅读而不会返回。这促进一种新的程序设计思想、方法和风格的形成,以期显著提高软件生产效率和降低软件维护的代价。,2.3 结构化程序设计概述,1972年,Mills进一步提出程序只应有一个入口和出口,进而填补了结构化程序设计的原则。结构化程序设计的概念和方法,以及支持这些方法的一整套软件工具,就构成了所谓的“结构化革命”。这是存储程序计算机问世以来对计算机界影响最大的一个软件概念。顺序结构是最简单而基本的结构,它是顺序执行各个语句,所以不再赘述。C+语言的结构化程序设计的语句称为程序控制结构,又可分为控制循环和控制选择(选择结构)。,1.if语句if语句在C+语言里的基本形式有两种,即 if(表达式)语句1;if(表达式)语句1;else 语句2;这两种语句形式均可用来设计选择结构程序。图2.1是if语句流程图,图2.2是if else语句流程图。,2.4 控制选择结构2.4.1 用if语句实现选择结构设计,图2.1 if语句流程图,图2.2 ifelse语句流程图,无论哪种形式的if语句,都需要首先判断括号“()”内的表达式的值。对第1种形式而言,若该值不为0,条件判断的值为true,则执行“()”后的语句1;若为0,条件判断的值为false,if语句执行终止。它的目的是根据需要执行语句1,然后继续执行其他语句。对第2种形式而言,根据条件判断的值执行不同的语句。条件为true,执行语句1,否则执行语句2。在所有控制语句中,人们习惯把“()”内的表达式叫做条件表达式。if语句就是根据条件表达式是否为0,来选择执行相应语句的。在C+语言里,凡是能用简单语句的地方都可以使用复合语句。因此,if语句(其他控制语句也如此)中的语句1和语句2都可以是复合语句。,【例2.6】使用if else语句,编写比较a、b两个数的大小,且把大者赋给变量x,小者赋给y的程序。#includeusing namespace std;void main()int a=2,b=3,x=0,y=0;if(ab)x=a;y=b;/使用复合语句 else x=b;y=a;/使用复合语句coutb不成立,其值为0,于是执行else后的复合语句x=b;y=a;。if语句执行完毕后,x里存有b的值,y里存有a的值。,2.if语句的嵌套可以在第1个if语句中的else后,放上第2个if语句;在第 2个if语句的else后又放上第3个if语句;以此类推,构成如图2.3的嵌套形式,即 if(表达式1)语句1;else if(表达式2)语句2;else if(表达式n)语句n;else 语句n+1;,这是经常使用的一种形式。在这种嵌套形式里,若表达式1的值不为0,则执行语句1;若为0,则判断表达式2,其结果不为0,执行语句2;若为0,则判断下一个if语句。若任何一个表达式都为0,则执行语句n+1,即if语句里的第n个else部分。,图2.3 if语句嵌套形式流程图,【例2.7】使用if语句嵌套形式的例子。这个程序使用嵌套形式的if语句,该程序根据学生的考分,来划分成绩的优、良、及格、不及格。现在分别用5、4、3、2来表示,且按如下规定划分,即 分数 等级 10095 5 9480 4 7960 3 590 2假定考分变量为score,则其程序如下所示:,#includeusing namespace std;void main()int score=0;char grade;cout94)grade=5;else if(score79)grade=4;else if(score59)grade=3;else grade=2;coutgrade=gradeendl;假定学生考分为81分,待程序执行后,从键盘上敲入“81”并按“Enter”键,则屏幕上就会显示出该程序的运行结果为4,表示该学生的成绩为良。,注意如下两种嵌套形式的if语句是不同的。if(ab)if(bb)if(bc)c=a;else c=b;如果a=5,b=4,c=3,则的c=3,而的c=4。,3.条件运算符对于下面形式的if语句 if(ab)max=a;else max=b;可以用条件运算符来实现。即 max=(ab)?a:b;其中“(ab)?a:b”是一个“条件表达式”,它的执行过程如下:如果(ab)条件为true,则条件表达式取a值,否则取b值。,条件运算符要求有3个操作对象,称做三目运算符。条件表达式一般形式为 表达式1?表达式2:表达式3它们的流程图如图2.4所示。,图2.4 三目条件运算符执行示意图,条件运算符的使用说明如下:条件运算符的执行顺序。先求解表达式1,若值为非0(真)则求解表达式2,表达式2的值就作为整个条件表达式的值。若表达式1的值为0(假),则求解表达式3,此时表达式3的值就是整个表达式的值。条件运算符优先于赋值运算符。例如,max=(ab)?a:b,就是先求解条件表达式,再将它的值赋给max。条件运算符的优先级别比关系运算符和算术运算符都低。,因此 max=(ab)?a:b中的括号可以不要,即可以写成:max=ab?a:b如果有ab?a:b+1,就相当于ab?a:(b+1),而不相当于(ab?a:b)+1。条件运算符的结合方向为“自右向左”。如果有以下条件表达式:ab?a:cd?c:d它相当于 ab?a:(cd)?c:d如果a=1,b=2,c=3,d=4,则条件表达式的值等于4。,条件表达式中,表达式1的类型可以与表达式2和表达式3的类型不同。如 x?a:bx是整型变量,若x=0,则条件表达式的值为b。表达式2和表达式3的类型也可以不同,此时条件表达式的值的类型为二者中较高的类型。如 xy?1:1.5如果xy,则条件表达式的值为1.5;若xy,值应为1.0。由于1.5是实型,比整型高,因此将1转换成实型值1.0。,switch语句是多分支选择语句,称为开关语句或者选择语句。if语句只有两个分支可供选择,而实际上又常常需要用到多分支的选择。switch语句可用来设计多路分支结构程序。例如,学生成绩分类(90分以上为“优”,8089分为“良”,7079分为“中”等);工资统计分类;文化程度分类等。这些都可以用嵌套的if语句来处理,但分支较多时容易出错,可读性也较差。,2.4.2 用switch语句实现选择结构设计,switch语句的使用形式为switch(表达式)case 常量表达式1:语句1;break;case 常量表达式n:语句n;break;default:语句n+1;break;,使用switch语句的例子见下一节的【例2.8】,但必须注意以下几点:每个case中的break语句使switch语句只执行一个case中的语句,执行到break语句即从switch语句中跳出。若没有break语句时,将继续执行下面各case部分的执行语句。当不存在与表达式的值一致的常量表达式时,则执行default后面的语句;当default部分省略时,则什么也不执行就跳出switch语句。表达式的类型和常量表达式的类型必须一致。若表达式的值与某case后的常量表达式的值相等,则执行该case后的语句。,当若干个case所执行的内容可用一条语句(当然也可以是复合语句)表示时,允许这些case共用一条语句。所有常量表达式的值必须互不相同,而case部分与default部分的顺序可以自由书写。如果default部分位于程序最后,default部分的break语句便可以省略;否则break语句也是必不可少的。,在许多实际问题中,都需要用到循环控制的方法,应该注意比较各种循环控制结构的用法及其特点。,2.5 循环控制结构设计,while语句可用来设计循环结构程序,它的形式为 while(表达式)语句;/注意别漏掉分号其功能是首先判断()内最初的表达式的值,其值不为0,执行()后的语句;一旦执行,接着再次判断表达式的值,进行与上述相同的处理,即若不为 0时执行()后的语句,为0时则跳出while循环。要特别注意,while后面的()里是表达式而不是语句,表达式是没有分号的(初学者常多加一个分号,而在括号后面的语句中又漏掉分号)。一般是在while后面使用复合语句,即把其放入一对花括号中,然后在复合语句内使用控制语句,以满足表达式的结束条件。,2.5.1 while 语句,【例2.8】从键盘接收输入,用Ctrl+Z键结束循环。#includeusing namespace std;void main()char ch;while(cin.get(ch)coutch;这种形式的while语句是由表达式取值完成结束条件的。从键盘输入一串字符,cin的get成员函数可以读一行(包括空格符),按“Enter”键将显示读入的内容,但并不结束循环,继续等待输入。可用Ctrl+Z键使表达式的值为0,退出循环。,下面是演示输入的过程。We are here!/输入可以有空格We are here!/按“Enter”键显示读取的内容Where are you?/继续输入Where are you?/输出,【例2.9】演示使用while和switch语句的例子。#includeusing namespace std;void main()int i=0,j=0,k=0;char c;while(cin.get(c)/Exit with Ctrl+Z switch(c)case0:case1:case2:case3:case4:case6:case7:case8:case9:i+;break;,case5:k+;break;default:j+;break;/结束switch选择/结束while循环 coutnn数字出现i+k次n;cout数字5出现k次n;cout字母出现j-1次n;本程序假定输入一串字符,计算这些输入中数字和字符各自出现的次数以及数字5单独出现的次数。使用Ctrl+Z退出程序,但不要使用“Enter”键,否则字母计数将多记一次。使用while(1)或while(true)将造成无限循环。,dowhile语句的形式为 do语句while(表达式);在dowhile语句里,首先要执行一次的是do后面的语句,之后才判断条件表达式。其值不为 0,则再次执行do后的语句;若为0,则do语句执行终止。,2.5.2 dowhile语句,dowhile语句和while语句的惟一区别就是:dowhile语句不管表达式的值如何,首先执行一次要循环执行的语句。就是说,即使第1次判断表达式时,其值为0,也要执行一次循环语句。而while语句是首先判断条件表达式,如果第1次判断时,其值为0,则不执行循环语句,而执行循环体下面的语句。有些问题的循环次数未知,且又要至少执行一次循环体,这时就适合使用dowhile语句。注意不要遗忘dowhile语句中表达式右括号外面的分号。下面两个例子演示了两者的区别。,【例2.10】演示使用while语句求两个非0整数之和。#includeusing namespace std;void main()int a,b,x;cinab;while(a!