资源描述
Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,第,5,章 函数与程序结构,哈尔滨工业大学计算机科学与技术学院,苏小红,sxh,C,语言大学实用教程,第1页,内容提要,函数定义、函数调用、函数原型、函数返回值,难点:函数参数传递与返回值,全局变量、自动变量、静态变量、存放器变量,难点:变量作用域与存放类型,程序调试,结构设计与模块化,代码格调问题,Moe,Curly,Larry,第2页,程序设计艺术,三国演义,中有这么一段描写:,懿问曰:“孔明寝食及事之烦简若何?”使者曰:“丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,日不过数升。”懿顾谓诸将曰:“孔明食少事烦,其能久乎?”,此话音落很快,诸葛亮果然病故于五丈原。,“事无巨细”,“事必躬亲”,管理学观点是极其排斥这种做法,认为工作必须分工,各司其职,其中思想,在程序设计里也适用,第3页,程序设计艺术,C,语言为程序结构提供了两样武器,函数和模块,函数,(,function,)是结构设计最基本单位,“一个程序应该是轻灵自由,它,子过程,就象串在一根线上珍珠。”,Geoffrey James,编程之道,第4页,数学函数,(1),自变量,因变量,函数名,第5页,数学函数,(2),一个自变量,一个因变量,两个,自变量,一个因变量,第6页,数学函数,(3),自变量,因变量,第7页,数学函数,(4),一个变量,二个变量,N,个变量,一个变量,二个变量,N,个变量,自变量与,因变量关系,第8页,数学函数,(5),集合,A,关系,集合,B,第9页,程序设计中函数,程序设计中函数不局限于计算,计算类,如打印阶乘表程序,判断推理类,如排序、查找,第10页,用函数处理问题关键点,分而治之,函数把较大任务分解成若干个较小任务,并提炼出公用任务,复用,程序员能够在其它函数基础上结构程序,而不需要从头做起,信息隐藏,设计得当函数能够把详细操作细节对程序中不需要知道它们那些部分隐藏掉,从而使整个程序结构清楚,Moe,Curly,Larry,第11页,C,中函数,(Function),说明,:,一个源程序文件由一个或多个函数组成。,一个,C,程序由一个或多个源程序文件组成。,C,程序执行从,main,函数开始,调用其它函数后流程回到,main,函数,在,main,函数中结束整个程序运行。,全部函数都是平行,即函数定义时是相互独立,一个函数并不隶属于另一个函数。,第12页,函数分类,标准函数,即库函数,当前为止,我们所学习,printf(),、,scanf(),等都是,ANSI C,标准定义库函数。任意符合,ANSI C,编译器,不论它支持什么平台,都必须提供这些函数供用户使用。,用户自定义函数,用户按自己意愿编写自己函数,完成人员功效。,第13页,函数定义,变量必须先定义,后使用。函数也一样。,函数定义语法以下:,返回值类型,函数名,(,类型,参数,1,类型,参数,2,),函数体,return,表示式,;,返回值类型与,return,语句配合,当函数执行到,return,语句时,就中止函数执行,,返回到调用它地方,函数名命名规则和变量名命名规则一致。,函数返回值是经过函数中,return,语句取得。,第14页,函数定义(,definition,),假如,没有参数,,则应该用,void,注明,其形如:,假如,不需要返回值,,则应该用,void,定义返回值类型,其形如:,函数内部能够定义只能由该函数自己使用变量,称,内部变量,。,参数表里变量也是内部变量,int Func(void),void Func(int i,float f),第15页,函数参数,函数参数,:,形参,(,形式参数,):,在定义函数时,定义函数名后面括号中变量名,实参,(,实际参数,):,在主调函数中调用一个函数,调用函数名后面括号中参数,(,或表示式,),int Average(int x,int y),int result;,result=(x+y)/2;,return result;,main(),int a=12;,int b=24;,int ave;,ave=Average(a,b);,printf();,数据传递,执行次序,实参,形参,第16页,函数调用(,call,),从实参到形参是,单向值传递,调用时会把实参值分别,复制,给形参,这个过程就是值传递。,调用函数时,,必须提供全部参数,(且必须是已赋值),提供参数个数、类型、次序应与定义时相同,形式参数,实际参数,第17页,例,5.1a,计算两个整数平均数,/*,函数功效:计算平均数,函数入口参数:整型,x,,存放第一个运算数,整型,y,,存放第二个运算数,函数返回值:平均数,*,/,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,第18页,例,5.1b,使用了,Average,函数,main(),main,(),int,a=12;,int,b=24;,int,ave;,ave=Average(a,b);,printf,(,Average of%d and%d is%d.n,a,b,ave);,int Average(int x,int y),int result;,result=(x+y)/2;,return result;,main(),int a=12;,int b=24;,int ave;,ave=Average(a,b);,printf();,数据传递,执行次序,第19页,函数调用(,call,),有返回值时,函数调用能够放到一个数值表示式中,如,c=max(a,b);,也可作为另一个函数调用参数,如,c=max(max(a,b),c);,printf(,%dn,max(a,b);,无返回值时,函数调用可直接作为表示式,如,display(a,b);,返回值,=,函数名,(,实参表列,);,函数名,(,实参表列,);,第20页,函数原型(,prototype,),调用一个函数之前,先要对其,返回值类型,、,函数名,和,参数,进行申明(,declare,),有利于编译器进行类型检验,申明时不要省略参数以及返回值类型,第21页,例,5.1,#,include,/*,函数功效:计算平均数,函数入口参数:整型,x,,存放第一个运算数,整型,y,,存放第二个运算数,函数返回值:平均数,*,/,main,(),int,a=12;,int,b=24;,int,ave=,Average(a,b),;,printf,(Average of%d and%d is%d.n,a,b,ave);,当返回值为整型或者函数定义在函数调用前面时,能够省略原型,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,第22页,例,5.1,#,include,/*,申明,Average(),函数*,/,main,(),int,a=12;,int,b=24;,int,ave=Average(a,b);,printf,(Average of%d and%d is%d.n,a,b,ave);,/*,函数功效:计算平均数,函数入口参数:整型,x,,存放第一个运算数,整型,y,,存放第二个运算数,函数返回值:平均数,*,/,int,Average(,int,x,int,y),int,result;,result=(x+y)/2;,return,result;,int,Average,(,int,x,int,y);,第23页,main(),a();,a,函数,b();,return;,b,函数,return;,在被调函数中,又调用了函数,-,嵌套调用,函数嵌套调用,第24页,循序渐进式编程,试验,4,:小学生加法考试题,经过输入两个加数给学生出一道加法运算题,输入答案正确,:right,错误,:,Not correct!Try again!,第25页,只答,1,次,直到做对为止,最多给,3,次机会,随机出题,连续做,10,道题,统计分数,循序渐进式编程,试验,4,:小学生加法考试题,第26页,void Print(int flag),if(flag),printf(Right!n);,else,printf(Not correct!n);,试验,4,:小学生加法考试题,/*,函数功效:计算两整型数之和,假如与用户输入答案相同,则返回,1,,不然返回,0,函数参数:整型变量,a,和,b,,分别代表被加数和加数,函数返回值:当,a,加,b,结果与用户输入答案相同时,返回,1,,不然返回,0,*/,int,AddTest(,int,a,int,b),int,answer;,printf(%d+%d=,a,b);,scanf(%d,if,(a+b=answer),return,1;,else,return,0;,只答,1,次,第27页,main(),int a,b,answer;,printf(,Input a,b:,);,scanf(,%d,%d,answer=AddTest(a,b);,Print(answer);,do,while,(answer=0);,试验,4,:小学生加法考试题,直到做对为止,第28页,main(),answer=AddTest(a,b);,Print(answer,chance);,chance=0;,do,chance+;,while,(answer=0,&chance 3,);,试验,4,:小学生加法考试题,最多给,3,次机会,第29页,srand(time(NULL);,error=0;,score=0;,for,(i=0;i10;i+),a=rand()%10+1;,b=rand()%10+1;,answer=AddTest(a,b);,Print(answer);,if,(answer=1),score=score+10;,else,error+;,试验,4,:小学生加法考试题,随机出题,连续做,10,道题,统计分数,第30页,作业,P180,,习题,5.35.4,第31页,函数与类型,C,语言要求:,返回表示式类型必须能转换到函数定义头部返回值类型。执行返回语句时,表示式求出值先转换到函数头部要求类型,以转换结果作为实际返回值。举例来说,在下面函数定义里,,return,语句求出表示式值之后就需要做类型转换:,int fun(int m),return 3.14159*m;,第32页,函数与类型,要求每个实参值应该能转换到函数参数表里要求类型。假如某个实参类型与函数要求不一致,首先转换该实参求出值,而后将得到结果送给函数。,比如,对上面函数,fun,,下面调用中也要做类型转换:,x=fun(3.09);,第33页,int f(int n,float m),return(m+n)/4;,int main(),float y=3;,printf(%dn,f(y,y+1);,return 0;,下面程序在执行时,哪些地方将发生类型转换?程序打印值是什么?,第34页,命名规则,在,Linux/Unix,平台,习惯用,function_name,本书采取,Windows,格调函数名命名,用大写字母开头、大小写混排单词组合而成,FunctionName,变量名形式,“,名词,”或者“,形容词,+,名词,”,如变量名,oldValue,与,newValue,等,函数名形式,“,动词,”或者“,动词,+,名词,”(动宾词组),如函数名,GetMax(),等,第35页,对函数接口加以注释说明,/*,函数功效:实现,功效,函数参数:参数,1,,表示,参数,2,,表示,函数返回值:,*,/,返回值类型,函数名,(,参数表,),函数体,return,表示式,;,第36页,主函数,main,main,返回值要求为,int,。这个返回值在程序结束时送给外部。程序外部(如操作系统)可用这个值,普通用,返回,0,表示程序正常结束,其它值表示犯错,main,以外,函数只有被调用时才会执行,不允许调用,main,int main()/*,普通写法*,/,.,return 0;,第37页,变量作用域,指在源程序中定义变量位置及其能被读写访问范围,分为,局部变量(,Local Variable,),全局变量,(Global Variable),演示变量作用域规则,例,5.4,第38页,局部变量,局部变量,在语句块内定义变量,形参也是局部变量,特点,定义时不会自动初始化,除非程序员指定初值,进入语句块时取得内存,仅能由语句块内语句访问,退出语句块时释放内存,不再有效,并列语句块各自定义同名变量互不干扰,第39页,全局变量,全局变量,在全部函数之外定义变量,特点,在程序中定义它位置以后都有效,在定义点之前或在其它文件中引用,应该进行以下申明:,extern,类型名 变量名,;,从程序运行起即占据内存,程序运行过程中可随时访问,程序退出时释放内存,使函数之间数据交换更轻易,也更高效,不过并不推荐使用,尽可能少用,因为谁都能够改写全局变量,所以极难确定是谁改写了它,第40页,例,5.7,#,include,int global;/*,定义全局变量,*,/,void,GlobalPlusPlus(,void,);,main(),global=1;,printf,(Before GlobalPlusPlus(),it is%dn,global);,GlobalPlusPlus();,printf,(After GlobalPlusPlus(),it is%dn,global);,/*,函数功效:对,全局变量,global,加,1,,并打印加,1,之前与之后值,函数入口参数:无,函数返回值:无,*,/,void,GlobalPlusPlus(,void,),printf,(Before+,it is%dn,global);,global+;,printf,(After+,it is%dn,global);,Before GlobalPlusPlus(),it is 1,Before+,it is 1,After+,it is 2,After GlobalPlusPlus(),it is 2,全局变量在程序员不指定初值情况下自动初始化为零,在此初始化为,0,第41页,例,5.8,#,include,void,GlobalPlusPlus(,void,);,main(),int global=1;,printf,(Before GlobalPlusPlus(),it is%dn,global);,GlobalPlusPlus();,printf,(After GlobalPlusPlus(),it is%dn,global);,/*,函数功效:对,局部变量,global,加,1,,并打印加,1,之前与之后值,函数入口参数:无,函数返回值:无,*,/,void,GlobalPlusPlus(,void,),int global=1;,printf,(Before+,it is%dn,global);,global+;,printf,(After+,it is%dn,global);,Before GlobalPlusPlus(),it is 1,Before+,it is 1,After+,it is 2,After GlobalPlusPlus(),it is 1,第42页,变量存放类型,指数据在内存中存放方式,即编译器为变量分配内存方式,它决定变量生存期,动态存放,依据需要暂时分配存放空间,离开即释放,静态存放,在程序运行期间分配固定存放空间不释放,程序区,静态存放区,动态存放区,形参、自动变量、函数调用现场等,全局变量、,静态变量,第43页,自动变量(,auto,),“自动”表达在,进入语句块时自动申请内存,退出时自动释放内存,标准定义格式,auto,类型名 变量名,;,动态局部变量,缺省存放类型,不初始化时,值是随机不确定,第44页,静态变量(,static,),普通内部变量,在函数退出后失效,再次进入函数,变量值重新初始化,静态变量,在变量类型前面用,static,修饰,static int i;,变量值能够保留到下次进入函数,使函数含有记忆功效,第45页,例,5.9,#,include,void,Func(,void,);,main(),int,i;,for,(i=0;i10;i+),Func();,/*,函数功效,:,打印被调用次数,函数入口参数:无,函数返回值:无,*,/,void,Func(,void,),int,times=1;,/*,自动,变量,*,/,printf,(Func()was called%d time(s).n,times+);,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,Func()was called 1 time(s).,第46页,例,5.9,#,include,void,Func(,void,);,main(),int,i;,for,(i=0;i10;i+),Func();,/*,函数功效,:,打印被调用次数,函数入口参数:无,函数返回值:无,*,/,void,Func(,void,),static,int,times=1;,/*,静态局部变量,*,/,printf,(Func()was called%d time(s).n,times+);,Func()was called 1 time(s).,Func()was called 2 time(s).,Func()was called 3 time(s).,Func()was called 4 time(s).,Func()was called 5 time(s).,Func()was called 6 time(s).,Func()was called 7 time(s).,Func()was called 8 time(s).,Func()was called 9 time(s).,Func()was called 10 time(s).,第47页,静态变量,静态变量和全局变量都是静态存放类型,自动初始化为,0,从静态存放区分配,生存期为整个程序运行期间,但作用域不一样,程序区,静态存放区,动态存放区,形参、自动变量、函数调用现场等,全局变量、,静态变量,第48页,存放器变量(,register,),存放器,CPU,内部容量很有限、但速度极快存放器,使用频率比较高变量申明为,register,,能够使程序更小、执行速度更加快,register,类型名 变量名,;,register int i;,当代编译器有能力自动把普通变量优化为存放器变量,而且能够忽略用户指定,所以普通无需尤其申明变量为,register,第49页,5.5,预处理,C,程序编译过程细分,可分为三步:预处理,编译,连接,。,第50页,预处理程序,是,C,系统一部分,处理源程序,预处理命令行,,产生修改后源程序。,“预处理”在编译之前进行,,依据源代码中预处理指令,在,后台调整源代码,。编译器编译都是经过预处理代码。,第一个非空白字符是,#,行就是预处理命令行。,预处理程序,包含以下几个:,1,、文件包含命令,2,、宏定义与宏替换,3,、条件保留命令,第51页,1,、文件包含命令,把指定文件内容包含到当前源文件,#include,形式,1,#include,文件名,形式,2,形式,1,用于包含,系统头文件,,预处理程序到指定目录找文件(通常指定几个系统文件目录)。这通常就是一个叫“,include,”目录。,形式,2,用于包含,自己文件,。预处理程序先在源文件所在目录里找,找不到时再到指定目录中去找。,第52页,处理过程,:,在文件系统中查找指定文件,假如找到,就用找到,文件内容替换该命令行,。被包含文件里如有预处理行也会处理。,前面实例都用包含命令,引进标准头文件(,.h,扩展名),它们在系统子目录里(目录名为,include,或,h,),内容是标准函数原型、系统使用符号常量定义等。,注意:,写程序时一定要包含必要系统头文件,。,包含这种文件相当于在源文件中写这些函数原型,使编译程序能正确完成对标准库函数调用处理。,第53页,2,、宏定义与宏替换,#define,开始,两种形式:,1,)简单宏定义;,2,)带参数宏定义;,简单宏定义,,形式:,作用,:,为,宏名字,定义替换,由整个,替换正文,组成。,替换正文,能够是任意正文序列,到换行为止。,#define,宏名字 替换正文,第54页,预处理程序统计,宏名字,及其,替换,。在源程序中碰到,宏名字,标识符时,就用,替换正文,替换。,宏展开,/,宏替换,。,替换正文里宏名字还继续展开。,字符串不做宏替换,。,第55页,人们也用这种方式定义符号常量。,#define,NUM 30,替换正文能够写任何东西。,若定义:,#define,SLD static long double,程序中:,SLD x=2.4,y=9.16;,替换后变成:,static long double x=2.4,y=9.16;,#define,NOSTOP while(1),预处理程序做正文替换,,替换正文,能够是任何东西。,第56页,带参数宏定义,,,形式:,说明:,宏名字与括号间不能有空格,,逗号分隔标识符看作参数。替换正文为任意正文序列。,使用形式与函数调用类似(,但本质不一样,),以类似参数形式给出宏参数替换段,用逗号分隔,称为,宏调用,。,举例:,#define min(A,B)(A)(B)?(A):(B),z=min(x+y,x*y);,#define,宏名字,(,参数列表,),替换正文,第57页,宏调用替换分两步展开:,先用各实参替换宏定义,替换正文,里参数;再将代换结果代入宏调用位置。,#define min(A,B)(A)(B)?(A):(B),z=min(x+y,x*y);,预处理中将被展开为:,z=(x+y)(x*y)?(x+y):(x*y);,比如书P179页展开式,第58页,注意,:,宏展开可能引发参数屡次计算。如:,z=min(n+,m+);,展开后形式是:,z=(n+)(m+)?(n+):(m+),替换正文各参数和整段应括起,防止犯错。例:,#define square(x)x*x,在特定环境下可能出问题,比如:,z=square(x+y);,使用,带参宏,与,调用函数,意义不一样。程序加工中在“,当地,”展开。程序执行中并没有调用动作,,宏定义,/,调用中没有类型问题。一个宏能否使用,/,使用中发生什么,/,能否得到预期效果,完全看展开后情况。,第59页,使用宏定义应注意:,带参宏展开可防止函数调用开销,但使程序变长。,复杂宏定义展开后犯错极难定位。,应慎重使用(尽可能少使用)宏,。,写宏定义常见错误是在定义行最终写分号。该分号 将被代入程序,有可能引发语法错误。,宏定义从定义处起作用直到文件结束。,一个文件里不允许对同一宏名字重复定义。,#undef,取消已经有定义:,#undef,宏名字,第60页,3,、条件保留命令,预处理命令还有剪裁代码能力,使一些代码仅在特定条件成立时才会被编译进可执行文件,可由以下命令组合实现,。,#if#else#elif#endif,#if,/,#elif,要求一个静态整型表示式,另两个单独成行,作用是划出源程序中一些片段:,条件成立时保留,不然丢掉,依据条件成立是否从两段中取一段,依据多个条件决定从多段中取一段,第61页,条件应该是整数表示式,,0,表示条件不成立,不然条件成立。惯用,=,、,!=,做判断。,例子:,#if TEST,printf(.);,#endif,例,5.5.3.1,第62页,谓词,defined,。使用形式:,defined,标识符,或,defined(,标识符,),当,标识符,是有定义宏名字时,,defined(,标识符,),得到,1,,不然得,0,#ifdef,标识符,相当于,#if defined(,标识符,),#ifndef,标识符,相当于,#if!defined(,标识符,),例,5.5.3.2,第63页,条件编译是,C,语言中一个非常主要功效,几乎全部大型软件都会用到。比如轻松修改几个宏定义,就让编译后代码含有或者不含有一些功效,以防止无须要浪费。,提供,文件包含命令,、,宏定义与宏替换,、,条件保留命令,,以及很多我们还未谋面指令这些预处理命令都是为了我们编程方便。,第64页,模块化程序设计方法,什么时候需要模块化?,某一功效,假如重复实现,3,遍以上,即应考虑模块化,将它写成通用函数,并向小组组员公布,要尽可能,复用,其它人现成模块。,第65页,习题,5.5,计算,复用,Factorial,函数代码,unsigned long,Factorial(,unsigned,int,number);,main(),unsigned int,m,k;,unsigned long,p;,printf(Please input m,k:);,scanf(%u,%u,p=Factorial(k)/Factorial(m-k);,printf(p=%lun,p);,第66页,用函数完成此题,先由计算机“想”一个,1,到,100,之间数请人猜。,假如猜对了,显示“正确!”,并赞美一番;不然显示“错误!”,并提醒所猜数是大了还是小了。,最多能够猜,7,次。如,7,次仍未猜中,则停顿此次猜数,并通知游戏者。,每次运行程序能够重复猜多个数,直到游戏者想停顿时才结束。,第67页,程序框架流程,开始,结束,初始化,退出处理,主功效,为程序运行所作准备工作,程序主体功效,在退出前要做事情,如打印结果资源释放,第68页,主功效 猜数字,开始,结束,生成数字,猜数字,是否继续?,N,Y,开始,结束,猜得对吗?,N,Y,提醒大小,次数,7,?,输入数字,N,Y,第69页,模块化程序设计方法,功效分解,自顶向下、逐步求精过程,模块分解标准,确保模块相对独立性,高聚合、低耦合,模块实现细节对外不可见,外部:关心做什么,内部:关心怎么做,设计好模块接口,接口是指罗列出一个模块全部与外部打交道变量等,定义好后不要轻易改动,在模块开头(文件开头)进行函数申明,第70页,函数设计标准,函数功效要单一,不要设计多用途函数,函数规模要小,尽可能控制在,50,行代码以内,1986,年,IBM,在,OS/360,研究结果:大多数有错误函数都大于,500,行,1991,年对,148,000,行代码研究表明:小于,143,行函数比更长函数更轻易维护,参数和返回值规则,参数要书写完整,不要省略,对函数入口参数进行有效性检验,没有参数和返回值时,用,void,填充,每个函数只有一个入口和一个出口,尽可能不使用,全局变量,尽可能少用,静态局部变量,,以防止使函数含有“记忆”功效,第71页,模块和链接,将一个程序分解成若干个模块,分别放在几个源文件中,形成一个项目文件(,.prj,),(,Project,),然后,对每一个源文件(,.c,),分别单独进行编译,再将它们目标代码(,.obj,),连同标准函数库中函数链接在一起,形成可执行文件(,.exe,)。,模块之间经过相互调用函数联络起来,头文件(,.h,)是联络纽带,第72页,模块和链接,例,5.10,能够不看,将习题,5.5,修改成,1,个,.h,头文件(,X5-5-1.h,),2,个,.c,源文件(,X5-5-1.c,,,X5-5.c,),1,个,.prj,项目文件(,X5-5.prj,),由全部源程序文件组成,X5-5-1.C,X5-5.C,参见试验指导书第,133,页,第73页,模块和链接,优点:,当一个文件代码被修改后,无须对全部程序重新编译,从而节约了程序编译时间。,使程序更宜于维护,给多个程序员共同编制一个大型项目标代码提供了方便伎俩。,第74页,软件测试,测试,经过运行测试用例找出软件中,Bug,测试目标,发觉更多,Bug,测试人员主要任务,站在使用者角度,经过不停使用和攻击,尽可能多找出,Bug,怎样提升可测试性,(,tesability,),一条语句写一行才轻易测试,第75页,软件测试,测试只能证实程序有错,不能证实程序无错,E.W.Dijkstra,测试主要性,测试人员水平越高,找到,Bug,时间就越早,软件就越轻易修复,产品发行就越稳定,越大型软件开发,测试人员占整个软件产品团体总人数比重就越大,甚至二分之一以上,成功测试在于发觉迄今为止还未发觉,Bug,第76页,软件测试方法分类,从代码和用户使用角度分类,覆盖性测试,从代码特征角度(即内部)出发测试,单元测试,功效测试,提交测试,基本验证测试,回归测试,使用测试,从用户角度(即外部)出发测试,配置测试,兼容性测试,性能测试,,Alpha,和,Beta,测试,强力测试,文档和帮助文件测试,第77页,软件测试方法分类,第,2,种分类方法,白盒测试(结构测试),在完全了解程序结构和处理过程情况下,按照程序内部逻辑测试程序,检验程序中每条通路是否都能按预定要求正确工作,黑盒测试(功效测试),不考虑程序内部结构和处理过程,第78页,软件测试方法分类,第,3,种分类方法,手工测试,依靠人力来查找,Bug,自动测试,编写一些测试工具,让他们自动运行来查找,Bug,优点:快,广泛,缺点:只能检验一些最主要问题,如内存泄漏、死机等,无法发觉普通性日常错误,而且编写测试工具工作量很大,第79页,程序中常见犯错原因,编译错误,指在编译过程中发觉错误,通常属于语法错误,即,编写语句不符合,C,语言语法规则。,Undefined symbol xxx,标识符,xxx,未定义,Expression syntax error,表示式语法错误,Too few parameter in call,函数调用时实参少于函数形参,第80页,程序中常见犯错原因,运行错误,指在程序运行时发生错误,往往是,因为语义上错误造成,,即语句即使合乎语法,但要求计算机去做不该做或做不到事情。,比如当用,0,做除数时,运行后将显示,“,Division by zero”,错误提醒信息,并马上返回编辑屏幕。查看运行结果时,可在,User screen,(用户屏幕)上看到给出错误提醒信息。,第81页,程序中常见犯错原因,逻辑错误,程序中有逻辑错时,不影响程序运行并得到运行结果,只是运行结果不正确。比较隐蔽,犯错后不易查找。,累加求和运算时,累加和变量忘记了赋初值;,累乘运算时,累乘变量初值赋值为,0,;,函数申明时返回值数据类型与实际返回数据类型不一致,造成自动类型转换,数组下标越界(即超出了定义范围);,程序中存在死循环;,第82页,调试基本方法,“粗分细找”,定位大致范围:归纳、推理、二分、排除,缩减输入数据,设法找到能造成失败最小输入,采取注释方法切掉一些代码,降低相关代码区域,调试无误后再将它们打开注释,即采取分而治之策略将问题局部化,利用调试工具,逐条语句跟踪,插入打印语句,观看屏幕输出结果,第83页,关于代码格调问题,缩进,(indent),确保代码整齐、层次清楚主要伎俩,int isprime(int n),int k,i;,k=sqrt(double)n);,for(i=2;i=k;i+),if(n%i=0)return 0;,return 1;,#include,main(),int i;,for(i=2;i100;i+),if(isprime(i),printf(%dt,i);,第84页,关于代码格调问题,良好格调程序应严格采取梯形层次对应好各层次,int,IsPrime(,int,n),int,k,i;,k=sqrt(,double,)n);,for,(i=2;i=k;i+),if,(n%i=0),return,0;,return,1;,#,include,main(),int,i;,for,(i=2;i100;i+),if,(IsPrime(i),printf(%dt,i);,第85页,程序版式,现在许多开发环境、编辑软件都支持“自动缩进”,依据用户代码输入,智能判断应该缩进还是反缩进,替用户完成调整缩进工作,VC,中有自动整理格式功效,只要选取需要代码,按,ALT+F8,就能自动整理成微软,cpp,文件格式,Cpp1.cpp,第86页,这一章我们学习了,函数定义、调用,变量作用域、存放类,自动变量(,auto,),外部变量(,extern,),静态变量(,static,),存放器变量(,register,),程序调试方法,第87页,作业,P180,,习题,5.55.6,第88页,
展开阅读全文