第四章 分支结构_第1页
第四章 分支结构_第2页
第四章 分支结构_第3页
第四章 分支结构_第4页
第四章 分支结构_第5页
已阅读5页,还剩67页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第四章分支结构4.1概述

4.1.1函数任何一部机器都是用部件组装而成的。计算机程序和机器一样,也是由一些部件构建起来的。C语言程序部件是函数。也就是说,设计C语言程序就是设计它的构成函数。下面举例说明C语言程序中的函数是什么样的。4.1概述

4.1.1函数/*文件名:ex010101.c*/#include<stdio.h>intmain(void){ printf("Programmingisfun.");//输出一串字符 return0;/*向操作系统返回一个数字0*/}这是一个非常简单的C语言程序,它的执行结果是显示一行字符:

Programmingisfun.4.1概述

说明:(1)这里intmain(void){ …}是一个函数。这个函数的名字为“main”。这个名字是专用的,表示这个函数是“主函数”。所谓主函数,就是执行这个程序时,由操作系统直接调用的函数。每一个C语言程序必须也只能有一个主函数。

4.1概述

说明:(2)函数名后面的圆括号用于表示参数。一般说来,用函数进行计算,需要给定参数。但是广义的计算也可以没有参数而只执行一个过程。在C语言程序中,参数部分写为“void”,表示该函数没有参数,只执行一个过程。“void”可以省写,如程序第一行可写为:intmain()在许多教材和程序中,可以常常见到这种形式的主函数首行。但是,C标准建议写上void,使含义清晰。4.1概述

说明:(3)再后面的一对花括号中的部分称为函数体,用来表明该函数的功能是如何实现的。通常,函数体用一些语句表述。C语言规定语句必须用分号结束。先分析下面的语句:printf(″Programmingisfun.″); 它的功能是调用编译系统提供的函数库中的一个函数printf(),来输出后面的一串字符。4.1概述

说明:(4)函数名前面的“int”表明函数的返回值是一个整数。有的操作系统要求在执行一个程序后应向系统返回一个整数值,如程序正常执行和结束,应返回0,否则返回一个非0值。因此,需要将main函数指定为int(整型),同时在函数体的最后写一返回语句:return0;

4.1概述

它的功能是向调用者(操作系统)返回0值,表示主函数正常结束(也就是程序正常结束)。此语句必须写在函数体的后一行才有意义,因为只要执行到这条语句,就表达程序正常结束,向操作系统返回一个0,如果程序未执行到这个返回语句就非正常结束了,就不会向操作系统返回0。操作系统会据此作出相应的处理。4.1概述

说明:(5)程序最前面的

#include<stdio.h>是一种在程序编译之前要处理的内容,称为编译预处理命令。编译预处理命令还有一些,它们都用“#”开头,并且不用分号结束,所以不是C语言的语句。这里的编译预处理命令称为文件包含命令,它的作用是在编译之前把程序中需要使用关于系统定义的函数printf()的一些信息文件stdio.h包含进来。用“.h”作为后缀的文件称为头文件。

4.1概述

说明:

(6)“/*…*/”中的文字用于做一些说明——注释,让读程序的人容易读懂。例如,注释/*文件名:ex1_01.c*/是告诉读程序的人,这个程序的源代码用文件ex1_01保存。而其他两个注释是对其左面两条语句功能的说明。

4.1概述

4.1.2语句在C语言程序中,函数下面的组成单位是语句。基本的语句有表达式语句、流程控制语句和块语句。1.表达式语句C语言程序的具体计算过程是由表达式完成的。表达式是由运算符(如上述+,=等)、变量和常量等组成。4.1概述

4.1.2语句2.流程控制语句一般说来,程序中的语句是按照书写顺序执行的。但是,有些情况下,需要改变默认的执行顺序,例如像图(a)那样要从两个或多个语句中挑选一个语句执行,或者像图(b)那样要重复执行某一个语句或语句块。前者称为选择控制,后者称为重复控制。4.1概述

2.流程控制语句

(a)选择结构(b)重复结构

两种基本的流程控制结构4.1概述

4.1.2语句3.块语句 块语句也称为复合语句,就是用一对花括号将一组语句括起来。4.1概述

4.1.3数学函数如何用C语言求开方?余弦?……如果每次运算都要编写这些代码太麻烦了!有没有简单的方法?C语言已经帮你想到了!#include<math.h>对照教材63页的表格。4.1概述

4.1.4预处理编译预处理是以“#”开头的一些命令,它通知编译系统:在进行正式编译前应当先进行一些前期工作(即编译预处理)。目前,C语言的编译预处理功能主要有如下一些:(1)文件包含,使用命令:#include。(2)宏定义,使用命令:#define、#undef。(3)条件编译,使用命令:#if、#ifdef、#ifndef、#else、#endif、#elif、defind。(4)提供行号信息,使用命令:#line。(5)编译杂注,使用命令:#progma。(6)错误信息,使用命令:#error。

4.1概述

4.1.4预处理1.#include注意:后面什么时候跟<>,什么时候跟””.4.1概述

4.1.4预处理2.#define在这些编译预处理中,应用最多的就是对宏的处理。它允许程序员使用#define定义并应用宏名字书写C语言程序,同时也指示编译器在正式编译前通过宏替换,使程序能按照C语言的语法进行编译。4.1概述

#define命令最简单的应用是将一个字符串定义为一个宏名,格式为: #define宏名字符串 编译预处理时,预处理程序将把程序文件中在该宏定义之后的所有宏名,用#define命令中定义的字符串(称为宏体)替换,这个过程称为宏替换。符号常数的定义就是这种宏定义的一种应用。例如 #definePI3.14159265 #defineRADIUS2.04.1.4预处理

(1)在#define命令中,宏名字与字符串(宏体)之间用一个或多个空格分隔。(2)宏名字的使用:宏名字不能用引号括起来。如:#define“YES” 1…printf(““YES””);将不进行宏定义。 宏名中不能含有空格。例如想用“ANAME”定义“SMISS”,而写成:4.1.4预处理

#defineANAMESMISS则实际进行的宏定义是A为宏名字,宏体是“NAMESMISS”。例子:#definePI 3.1415926#defineR 1.0#defineCIRCUM 2.0*PI*R/*使用了前面定义的R和PI*/#defineAREA PI*R*Rintmain(void){printf("Thecircumis%fandareais%f\n",CIRCUM,AREA);}4.1.4预处理

#include<stdio.h>#definePI3.14159265#defineRADIUS1.0#defineCIRCUMreturn(2.0*PI*RADIUS);/*最后的分号是return语句的一部分*/#defineAREAreturn(PI*RADIUS*RADIUS);doublecircum(){CIRCUM}doublearea(){AREA}intmain(void){ printf("Thecircumis%fandareais%f\n",circum(),area());}4.1.4预处理

(4)不能进行的宏替换:不可以替换作为用户标识符中的成分。例如,,不可以用“R”替换“CIRCUM”中的“R”。不能替换字符串常量中的成分。(5)

一行中写不下的宏定义,应在前一行结尾使用一个续行符“\”,并且在下一行开始不使用空格。4.1.4预处理

(6)宏定义可以写在源程序中的任何地方,但一定要写在程序中引用该宏之前,通常写在一个文件之首。对多个文件可以共用的宏定义,可以集中起来构成一个单独的头文件。撤销已定义的宏

用命令#undef可以撤销已定义的宏。如:…#defineOK1…#undefOK…在#undef命令行之后的范围,OK不再代表1。

带参宏定义的格式为: #define标识符(形参表)宏体 应当注意,这时的宏体是一个表达式,正确的书写宏体的方法是将宏体及其各个形参应该用圆括号括起来。

#defineSQUARE(x)x*x /*(a)*/ #defineSQUARE(x)(x*x) /*(b)*/ #defineSQUARE(x)(x)*(x) /*(c)*/ #defineSQUARE(x)((x)*(x)) /*(d)*/到底哪个对呢?下面用几个表达式进行测试:

宏与函数都可以作为程序模块应用于模块化程序设计之中,但它们各有特色。(1)时空效率不相同。宏定义时要用宏体去替换宏名,往往使程序体积膨胀,加大了系统的存储开销。但是它不像函数调用要进行参数传递、保存现场、返回等操作,所以时间效率比函数高。所以,通常对简短的表达式,以及调用频繁、要求快速响应的场合(如实时系统中),采用宏比采用函数合适。

(2)宏虽然可以带有参数,但宏定义过程中不像函数那样要进行参数值的计算、传递及结果返回等操作;宏定义只是简单的字符替换,不进行计算。因而一些过程是不能用宏代替函数的,如递归调用。同时,也可能不适合某些计算,产生函数调用所没有的副作用。4.1.5条件编译#if#else#ifdef开发操作系统经常使用。Minix《操作系统设计与实现》4.2判断4.2.1命题的“真”、“假”与C语言中的逻辑值不论是选择结构,还是循环结构,流程的改变都是由判断决定的。即需要根据判断决定选择,根据判断决定是否循环以及循环的结束。通常,判断是针对命题的“真”、“假”进行的。例如,下面是一些命题:

●(行驶中)前面的交通信号灯是红色的。●今天下雨。●a≥b。●a≥b≥c,即a≥b且b≥c。●a≥b或c≥b。●如果a不能被b整除。这些命题的值都只能是一个逻辑(布尔)值:“真”或“假”ABBAA(a)逻辑“与”

(b)逻辑“或”

(c)逻辑“非”

4.2.2关系运算与关系表达式

关系表达式和逻辑表达式是C语言中描述命题的两种基本形式。1.C语言的关系运算符关系运算是指对两个表达式值的大小比较。C语言中提供有如下6个关系运算符:

>(大于) >=(大于或等于) <(小于)<=(小于或等于) ==(等于) !=(不等于)后两个(==和!=)的优先级小于前4个,但它们都低于纯算术类,高于赋值类,并且它们结合方式都是从左向右的。例如:a+b<c+d应理解为(a+b)<(c+d)2.关系运算符的值关系表达式的值只有两个:关系表达式成立,即为“真”(通常为1);关系表达式不成立,即为“假”(0)。例如对于声明:

intx=2,y=3,z;表达式x==y的值为0。而表达式x<y的值为1。那末表达式z=3-1>=x+1<=y+2的值呢?在这个表达式中有赋值、关系、算术三种运算。其中“赋值”的优先级最低,其次为“关系”,“算术”的优先级最高。因此,先进行算术运算得z=2>=3<=5然后计算2>=3,其值为0(假),得z=0<=5再计算0<=5,值为1(真),故有z的值为1。(1)表达式5>2>7>8在数学上是不允许的,而在C中是允许的。按自左而右的结合求解:①5>2值为1;②1>7值为0;③0>8的值为0。即整个关系表达式的值为0。(2)由于关系表达式的值是整型数0或1,故也可以将其看成是一种整型表达式。例如,若有:inti=1,j=7,a;a=i+(j%4!=0);由于j%4的值为3,而3!=0的值为1(真),故a的值为2。但这种表达式的含义不易被理解,初学时不宜多用。(3)在判定两个浮点数是否相等时,由于存储上的误差,会得出错误的结果。例如:1.0/3.0*3.0==1.0在数学上显然应该是一个恒等式,但由于1.0/3.0得到的值的有效位数是有限的,并不等于0.3333333333333┅,因此上面关系表达式的值为0(假),并不为1(真)。所以应避免对两个实数表达式作“相等”或“不相等”的判别。上式可改写为:fabs(1.0/3.0*3.0-1.0)<1e-5fabs是求绝对值函数。只要1.0/3.0与1.0之间的差小于10-5(或一个其它的很小的数),就认为1.0/3.0*3.0与1.0相等。

(4)要表示x在区间[a,b]中,在数学中使用表达式a≤x≤b。但在C语言中使用表达式“a<=x<=b”会与原来的意义不同。假设a=0;b=0.5。若x=0.3,则执行a<=x<=b时先求出“a<=x”的值得1(真),再计算“1<=b”得0(假)。因此,为了判别x是否在[a,b]范围内,应写成:a<=x&&x<=b“&&”是下面将要介绍的逻辑运算符“与”。a<=x的值为1(真)且x<=b的值亦为1(真),则整个表达式的值为1(真)。2逻辑运算与逻辑表达式1)逻辑运算的基本概念C语言有三个逻辑运算符,它们是:&&(逻辑与) ||(逻辑或)!(逻辑非)2)常用的逻辑运算规律

逻辑运算中有很多有趣的规律。例如:(1)在一个&&表达式中,若&&的一端为0,则不必再计算另一端,该表达式的值肯定为0(在C语言中由于&&是从左向右结合的,所以只考虑左端,即当&&号的左端为0时,不再计算其右端),可以把它记为:0&&a=0(2)在一个||表达式中,若||的一端为1,则不必计算另一端,该||表达式的值必为1。现把它记为:1||a=1诸如此类关于表达式的值的规律有如下一些:0||a==a 1&&a==a 1||a==1 0&&a==0a||!a==10&&!a==04.2.3选择型程序设计

选择型程序描述了求解规则:在不同的条件下所应进行的相应操作。下面分别介绍C语言中用来实现选择结构的三种语句。

if…else结构的应用if(表达式) 语句1else 语句2if…else构造了一种二路分支选择结构,它具有如下格式:if(表达式) 语句1 else 语句2

这里,语句1和语句2就是两路分支。执行这个结构,首先对表达式进行判断,若为“真”(非零),就执行if分结构(语句1);否则(值为0),就执行else分结构(语句2)。例求一个数的绝对值。设有任意数x,它的绝对值为判断内容:x<0是否成立。两路分支:①|x|=x(当x≥0),②|x|=-x(当x<0)

C函数如下:/******文件名:ex030301.c******//******求绝对值******/doubleabstr(doublex){if(x<0.0)x=-x;elsex=x;return(x);}下面是函数abstr被调用执行的情况:#include<stdio.h>intmain(void){doublea,abstr(doublea);printf("Enterrealnumberaplease:");scanf("%lf",&a);printf("abstr(%lf)=%lf\n",a,abstr(a));return0;}C语言还允许使用缺省else分结构的if…else结构。其形式为:

if(表达式) 语句

如上述abstr()函数可以改写为:doubleabstr(doublex){if(x<0.0)x=-x;return(x);}

这种结构称为不平衡if结构。它不如平衡的if结构容易理解和清晰。

例三数中取大数。intmain(void){floata,b,c,m;printf("Enter3realnumbersa,b,c:\n");scanf("%f,%f,%f",&a,&b,&c);m=max3(a,b,c);printf("Themaxis%f\n",m);return0;}floatmax3(floatx,floaty,floatz){floatmax=x;if(z>y)if(z>x)max=z;elseif(y>x)max=y;return(max);}

通过这个例子可以看到:(1)不平衡的if…else结构会增加阅读和理解程序的困难(2)正确的缩进格式(即锯齿形书写格式)可以帮助人们理解程序,但错误的缩进格式反而会使人迷惑。(3)不要太相信自己的判断,要严格按语法关系检查程序。在不易弄清的地方可以加花括号来保证自己构思的逻辑关系的正确性。floatmax3(floatx,floaty,floatz){floatmax=x;if(z>y){if(z>x)max=z;}else{if(y>x)max=y;}return(max);}if-elseif结构的应用if(表达式1)

if(表达式1)语句1elseif(表达式2)语句2┇elseif(表达式n)语句nelse 语句n+1真假┇表达式1表达式2表达式n语句n+1语句n语句2语句1…真真假假例根据百分制分数决定成绩的等级:·80分以上为A级;·70分及以上,80分以下,B级;·60分及以上,70分以下,C级;·60分以下,D级。真假score>=80score>=70等级A真假输入scorescore>=60等级B等级D等级C/******按成绩分等******/#include<stdio.h>intmain(void){floatscore;printf("Inputascre:");scanf("%f",&score);if(score>=80)printf("%fisA\n",score);elseif(score>=70)printf("%fisB\n",score);elseif(score>=60)printf("%fisC\n",score);elseprintf("%fisD\n",score);return0;}

可以看到,if-elseif是通过一连串的判断,来寻找问题的解。它排列了一系列操作,每一种操作都是在相应的条件下才能执行的。该结构开始执行后,便依次去对各个条件进行判断测试,符合某一条件,则转去执行该条件下的操作,其它部分将被跳过;如无一条件为真,就执行最后一个else所指定的操作。这个else可以看作“其它”。若最后一个else不存在,并且所有条件的测试均不成功,则该elseif结构将不执行任何操作。switch结构的应用

switch是一种多分支选择结构,其形式如右。switch结构也称标号分支结构,它用花括号括起了一系列case子结构。每个case子结构都以一个常量表达式作为标志的标号,并按照下面的规则匹配:计算switch的判断表达式,并以此值去依次找与之相等的case标号值,找到后就将流程转到该标号处,执行后面各语句switch(表达式){case常量表达式1:语句序列1case常量表达式2:语句序列2

┇case常量表达式n:语句序列ndefault:语句序列n+1}switch结构的应用如果找不到符合的case子结构,就只执行default子结构中的语句序列。default子结构对于switch结构不是必须的。当没有default子结构,并且没有相符合的case时,该switch结构就不被执行。switch(表达式){case常量表达式1:语句序列1case常量表达式2:语句序列2

┇case常量表达式n:语句序列ndefault:语句序列n+1}请注意∶如果switch的判断表达式的值与case常量表达式I的值相等(称为匹配),在执行后面的语句序列i之后,并不立即退出switch结构,而是继续执行语句序列i+1,语句序列i+2,┅.语句序列n.语句序列n+1.这种流程往往不是编程者所希望的。表达式语句序列1常量表达式1:语句序列2常量表达式2:语句序列i常量表达式i:语句序列n常量表达式n:语句序列n+1default┇┇

编程者希望在执行匹配的常量表达式后面的语句序列i之后,应立即退出switch结构。为了解决这一问题,可以在各语句序列后面加一条break语句,使流程脱离switch结构。表达式语句序列1常量表达式1:语句序列2常量表达式2:语句序列i常量表达式i:语句序列n常量表达式n:语句序列n+1default┇┇switch(表达式){case常量表达式1:语句序列1break;case常量表达式2:语句序列2break;┇case常量表达式n:语句序列nbreak;default:语句序列n+1break;}表达式语句序列1常量表达式1:语句序列2常量表达式2:语句序列i常量表达式i:语句序列n常量表达式n:语句序列n+1default┇┇break;break;break;break;break;这里,break语句的作用是中断该switch结构,即将流程转出switch结构。所以,执行switch结构的就相当于只执行与判断表达式相匹配的一个case子结构中的语句。其实,可以将break看作为语句序列中必要的成分(位置在语句序列中的最后)。voidMonthName(intmonth){switch(month){case1:printf("January\n");break;case2:printf("February\n");break;case3:printf("March\n");break;case4:printf("April\n");break;case5:printf("May\n");break;case6:printf("June\n");break;case7:printf("Jauly\n");break;case8:printf("August\n");break;case9:printf("September\n");break;case10:printf("October\n");break;case11:printf("November\n");break;case12:printf("December\n");break;default:p

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论