/94练习:main(){inti=1;staticinta=10;registerintb=5;printf (“i=%d,a=%d,b=%d\n”,i,a,b);other();printf(“i=%d,a=%d,b=%d\n”,i ,a,b);}other(){inti;staticinta ;i=6;a=100;printf(“i=%d,a=%d\n”, i,a);}/94变量存储类型静态动态存储方式程序整个运行期间函数调用开始至结束生存期编译时赋初值,只赋一次 每次函数调用时赋初值自动赋初值0或空字符不确定未赋初值静态存储区动态区存储区寄存器局部变量外部变量作用域定 义变量的函数或复合语句内本文件其它文件局部变量默认为auto型register型变量个数受限,且不能为long,doub le,float型局部static变量具有全局寿命和局部可见性局部static变量具有可继承性extern不是变量定义,可 扩展外部变量作用域register局部staticauto外部static外部存储类别/94例7-25文件 file1.cinta;main(){…….…….f2; …….f1;…….}f1(){autointb;……… f2;……..}f2(){staticintc;………}C作用域 b作用域a作用域mainf2f1mainf1f2maina生存期:b生存期:c生存期:/94例7-2 6auto变量的作用域main(){intx=1;voidprt(void);{ intx=3;prt();printf(“2ndx=%d\n”,x); }printf(“1stx=%d\n”,x);}voidprt(void){intx= 5;printf(“3thx=%d\n”,x);}运行结果:3thx=52ndx=31st x=1x=1作用域x=1作用域x=3作用域x=5作用域/94main(){voidincrement( void);increment();increment();increment();}vo idincrement(void){intx=0;x++;printf(“%d\n”,x); }例7-27局部静态变量值具有可继承性运行结果:11 1main(){voidincrement(void);increment(); increment();increment();}voidincrement(void){sta ticintx=0;x++;printf(“%d\n”,x);}运行结果:1 23/94例7-28变量的寿命与可见性#include inti=1;main(){staticinta;registerintb=-1 0;intc=0;printf("-----MAIN------\n");printf("i:%d a:%d\b:%dc:%d\n",i,a,b,c);c=c+8;other(); printf("-----MAIN------\n");printf("i:%da:%d\ b:%dc:%d\n",i,a,b,c);i=i+10;other();}other(){s taticinta=2;staticintb;intc=10;a=a+2;i=i+ 32;c=c+5;printf("-----OTHER------\n");printf("i:%da: %d\b:%dc:%d\n",i,a,b,c);b=a;}-------Main---- --i:1a:0b:-10c:0------Other------i:33a:4b:0c:15 -------Main-----i:33a:0b:-10c:8-------Other-------i:75 a:6b:4c:15全局i1main:a0b:-10registermain:c0静态存储区动态 存储区other:a2other:b0other:c10843315443other:c10 675156/94main(){voidgx(),gy();externintx,y; printf(“1:x=%d\ty=%d\n”,x,y);y=246;gx();gy();} voidgx(){externintx,y;x=135;printf(“2:x=% d\ty=%d\n”,x,y);}intx,y;voidgy(){printf(“3:x=%d\ty=%d\ n”,x,y);}例7-29用extern扩展外部变量作用域运行结果:1:x=0y=02: x=135y=2463:x=135y=246/94例7-30引用其它文件中的外部变量intg lobal;externfloatx;main(){intlocal; . . .}externin tglobal;staticintnumber;func2(){ . . .}floatx;static intnumber;func3(){externintglobal; . . .}file1.cfile 2.cfile3.c/94例7-31引用其它文件中的变量,输出a?b和a的m次方inta;main(){i ntpower(intn);intb=3,c,d,m;printf("Enterthenumbera anditspower:\n");scanf("%d,%d",&a,&m);c=ab;printf ("%d%d=%d\n",a,b,c);d=power(m);printf("%d%d=%d",a,m,d) ;}externinta;intpower(intn){inti,y=1;for(i =1;i<=n;i++) y=a;return(y);}/947.5编译预处理“编译预处理”是C语言编 译系统的一个组成部分。编译预处理是在编译前由编译系统中的预处理程序对源程序的预处理命令进行加工。源程序中的预处理命令均以“#” 开头,结束不加分号,以区别源程序中的语句,它们可以写在程序中的任何位置,作用域是自出现点到源程序的末尾。预处理命令包括执行宏定义 (宏替换)、包含文件和条件编译。/947.5.1宏定义1简单宏定义定义形式: #define宏名串( 宏体)如:#definePI3.14159宏定义的作用宏定义后,该程序中宏名就代表了该字符串。说明#und ef终止宏定义的作用域: #undefPI定义位置:任意(一般在函数外面)作用域:从定义命令到文件结束宏体可缺省,表 示宏名定义过或取消宏体/94宏定义的嵌套使用#defineR3.0#definePI3.1415926 #defineL2PIR/宏体是表达式/#defineSPIRRmain( ){printf("L=%f\nS=%f\n",L,S);}程序运行结果如下:L=18.849556 S=28.274333双引号内的与宏同名的字母不作宏展开。(见上例)/94 如if(x==YES)printf(“correct!\n”); elseif(x==NO)printf(“error!\n”);展开后:if(x==1 )printf(“correct!\n”);elseif(x==0) printf(“error!\n”);宏展开:预编译时,用宏体替换宏名---不作语法检查如#define YES1#defineNO0#definePI 3.1415926#defineOUTprintf(“Hello,World”);例# defineYES1main(){……..}#un defYES#defineYES0max(){…….. }YES原作用域YES新作用域宏定义可嵌套,不能递归例#defineMAXMAX+10 (?)例#definePI3.14159printf(“2PI= %f\n”,PI2);宏展开:printf(“2PI=%f\n”,3.141592);宏定义中使用必要的括号()例 #defineWIDTH80#defineLENGTHWIDTH+40var= LENGTH2;宏展开:var=80+402;()() 例#defineWIDTH80#defineLENGTHWIDTH+40v ar=LENGTH2;宏展开:var=80+402;/942、带参数的宏定义带参数的宏定义的一般形式: #define宏名(参数表)字符串如:#defineS(a,b)ab #definePR(x)printf("s=%f\n”,x)带实参的宏名展开时,宏名被宏体替换,宏体中的形参 按从左到右的顺序被实参替换。例如:area=S(3,2);PR(area);赋值语句展开为: area=32;PR(area)展开的结果是:printf("s=%f\n”,area);不能加空格/94例 #defineS(r)PIrr相当于定义了不带参宏S,代表字符串“(r)PIrr”宏 展开:形参用实参换,其它字符保留宏体及各形参外一般应加括号()例#defineS(a,b)ab ………..area=S(3,2);宏展开:area=32;例#define POWER(x)xxx=4;y=6;z=POWER(x+y);宏展开:z=x +yx+y;一般写成:#definePOWER(x)((x)(x))宏展开:z=((x+y)(x +y));/94宏定义与函数的区别带参宏函数处理过程不分配内存简单的字符置换分配内存先求实参值,再代入形参处 理时间编译时程序运行时参数类型无类型问题定义实参,形参类型程序长度变长不变运行速度不占运行时间调用和返回占时 间/94宏替换的形参无类型。实参为表达式: 函数调用是先计算出实参的值,再将值传递给形参;宏的引用是用表达式替换形参 。例如:定义:#defineS(a,b)ab引用:S(a+c,b+c)展开: a+cb+c/94#defineMAX(x,y)(x)>(y)?(x):(y)…….main(){ inta,b,c,d,t;…….t=MAX(a+b,c+d);……}宏展开:t=(a +b)>(c+d)?(a+b):(c+d);intmax(intx,inty){return(x>y?x:y); }main(){inta,b,c,d,t;…….t=max(a+b,c+d); ………}例用宏定义和函数实现同样的功能/943、文件包含文件包含#include: 一个源文件可以将 另一个源文件的全部内容包含进来。#include命令有两种格式。(1)#include<文件名>(2)#include “文件名”/94功能:一个源文件可将另一个源文件的内容全部包含进来一般形式:#include“文件名” 或#include<文件名>#include“file2.c”file1.c file2.cfile1.cfile2.cABA处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包含”后 的文件作一个源文件编译<>直接按标准目录搜索“”先在当前目录搜索,再搜索标准目录可指定路径/94被包含文件内容 源文件(.c)头文件(.h)宏定义数据结构定义函数说明等文件包含可嵌套#include“file2.c”f ile1.cAfile3.cC#include“file3.c”file2.cBfile1.cAfile3 .cfile2.c/94例文件包含举例/powers.h/#definesqr(x)(( x)(x))#definecube(x)((x)(x)(x))#definequad(x)((x) (x)(x)(x))#include#include"d:\fengyi\bkc\powers.h" #defineMAX_POWER10voidmain(){intn;printf("number\t exp2\texp3\texp4\n");printf("----\t----\t-----\t------\n") ;for(n=1;n<=MAX_POWER;n++)printf("%2d\t%3d\t%4d\t%5d \n",n,sqr(n),cube(n),quad(n));}/94(1)#include voidsstring(){charch;ch=getchar(); putchar(ch); if(ch!=‘.’)sstring();}例1当输入 abcdefg.时,下列每一个函数的输出是什么?(2)#includevoidsstri ng(){charch;ch=getchar();if(ch!= ‘.’)sstring();putchar(ch);}/94(3)#incl udevoidsstring(){charch;ch =getchar(); if(ch!=‘.’){putchar(ch); ss tring();}}(4)#includevoidsst ring(){charch;ch=getchar();if(ch !=‘.’){sstring();putchar(ch); } }/94(5)#includevoidstring() {charch;ch=getchar();if(ch!=‘.’) string();elseputchar(ch);}/94(1)sub(i ntx){inty=0;staticintz=0;y+=x++,z++; printf(“%d,%d,%d,”,x,y,z);returny;}例2写出下列程序的运 行结果main(){inti;for(i=0;i<3;i++)printf(“%d\n ”,sub(i));}/94(2)intx=1,y=2;sub(inty){x++ ;y++;}main(){intx=2;sub(x)printf(“x+y =%d\n”,x+y);}/94#includevoidgenerate(x,y) charx,y;{if(x==y)putchar(y);else{putchar(x); generate(x+1,y);putchar(x); }}main(){chari,j;for(i=‘1’;i<‘6’;i++){for( j=1;j<60-i;j++)putchar(‘‘);generate(‘1’,i);putc har(‘\n’);}}(3)/94例3写出下列程序的运行结果#define SUB(x,y)(x)ymain(){inta=3,b=4,c;c=SUB(a++,b++);p rintf("%d,%d,%d\n",a,b,c);}(1)/94#definey1main(){i ntx=1;printf(“x=y:%d,x==y:%d,’x’==‘y’:%d\n“,x =y,x==y,’x’==‘y’);}(2)/94#defineN2#defineMN+1 #defineNUM(M+1)M/2main(){inti,n=0;for(i=1;i<=N UM;i++){n++;printf(“%d\n”,n);}}(3)/94711x:y:调用前:调用 结束:711x:y:例7-10交换两个数#includemain(){intx= 7,y=11;printf("x=%d,\ty=%d\n",x,y);printf("swapped:\n") ;swap(x,y);printf("x=%d,\ty=%d\n",x,y);}swap(inta,in tb){inttemp;temp=a;a=b;b=temp;}调用:711a:b:711 x:y:swap:711x:y:117a:b:temp/94地址传递方式:函数调用时,将数据的存储 地址作为参数传递给形参特点:形参与实参占用同样的存储单元“双向”传递实参和形参必须是地址常量或变量/94/ch9_ 3.c/swap(p1,p2)intp1,p2;{intp;p=p1;p1=p 2;p2=p;}main(){inta,b;scanf("%d,%d",&a,&b); printf(“a=%d,b=%d\n”,a,b);printf(“swapped:\n”);swap(& a,&b);printf(”a=%d,b=%d\n",a,b);}例7-11交换两个数a59b调前: a59b调swap:p1&a&bp2a95b交换:p1&a&bp2a95b返回:/ 94#includelongsum(inta,intb);longfactoria l(intn);main(){intn1,n2;longa;scanf ("%d,%d",&n1,&n2);a=sum(n1,n2);printf("a=%1d",a );}longsum(inta,intb){longc1,c2;c1=facto rial(a);c2=factorial(b);return(c1+c2);}longfact orial(intn){longrtn=1;inti;for(i=1;i< =n;i++)rtn=i;return(rtn);}longsum( inta,intb);longfactorial(intn);文件包含编译预处理命令函数类型说明函数定义 函数调用函数调用函数返回值形参实参/944.函数的嵌套调用调用一个函数的过程中又调用了另一个函数,这种调用称 为函数的嵌套调用。函数1函数2 函数3{……①②{…….③④{ …...⑤调用函数2调用函数3 }……⑨⑧…….⑦ ⑥}}C规定:函数定义不可 嵌套,但可以嵌套调用函数/94【例7-12】求方程ax2+bx+c=0(a?0)的根。#include>#includevoidmain(){floata,b,c,x1,x2;intdict(f loat,float,float);floatroot(float,float,float,int);printf( "Inputa,b,c:");scanf("%f,%f,%f",&a,&b,&c);if(dict(a,b,c)) {x1=root(a,b,c,1);/调用函数root/x2=root(a,b,c,0);pri ntf("实根x1=%f,x2=%f\n",x1,x2);}elseprintf("无实根!\n");}/9 4dict()和root()intdict(floata,floatb,floatc){intf;if(bb -4ac>=0)f=1;elsef=0returnf;}floatroot(floata,floatb ,floatc,intflag){floatd,x;d=dict(a,b,c);/调用函数dict/if (d)x=flag?(-b+sqrt(d))/(2a):(-b-sqrt(d))/(2a);returnx;} /94嵌套过程voidmain(){...x1=root(a,b,c,1)x2=root(a,b,c,0). ..}root(a,b,c,flag)...{...d=dict(a,b,c)...returnx;}d ict(a,b,c)...{...returnf;}图6-3嵌套调用过程调用返回返回调用 /94第7章数组作为函数参数的函数调用形式7.4数组作为函数参数/946.3函数的递归调用函数调 用函数本身,称为函数的递归调用。递归调用形式如下:1)直接递归voida(){...…a( );...…}2)间接递归voida(){...…b(); ...…}voidb(){.....a();......}说明C编译 系统对递归函数的自调用次数没有限制每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引 起堆栈溢出/94用递归算法计算n!讨论: 采用递归的方法计算。n!的递归定义形式的:编程:if(初始条件) 表 达式;else递推表达式;1n=0;n=n( n-1)!n>0/94例7-14程序:#includelongfac(unsignedn) {longf;if(n==0)f=1;/递归结束条件/elsef=nfac(n- 1);returnf;}main(){longy;intn;scanf(“%d”,&n );y=fac(n);printf(“%d!=%ld\n”,n,y);}/94分析:当程序输入3时y =fac(3)⑧① 3fac(2)⑦② 2fac(1)⑥③ 1fac(0)⑤④ 1/94例:有以下程序 int fun(intn) {if(n==1)return1; elsereturn(n+fun(n- 1));}main(){ intx; scanf(“%d”,&x);x=fu n(x); printf(“%d\n”,x);}执行程序时,给变量x输入10,程序的 输出结果是 A)55 B)54C)65D)45/94[例7.15] 汉诺塔游戏汉诺塔(TowerofHanoi)游戏。底座上有三根针,第一根针上放着从大到小64个金片。游戏的目标是把所有 金片从第一根针通过第二根针移到第三根针上。移动过程中大的金片不能压在小的金片上。把n(n>1)个金片从第一根针a上移到第三根针c 的问题分解成如下步骤:(1)将n-1个金片从a经过c移动到b。(2)将第n个金片移动到c。(3)再将n-1个盘子从b 经过a移动到c。/94voidhanoi(intn,inta,intb,intc){if(n==0) return;/0个金片不处理/if(n==1)printf("%d->%d\n",a,c); /n=1时,直接将金片从a移动到c/else{hanoi(n-1,a,c,b);/ 先将n-1个金片从a经过c移动到b/printf("%d->%d\n",a,c);/将第n个金 片从a移动到c/hanoi(n-1,b,a,c);}/再将n-1个金片从b经过a移动到c/} 主函数如下:#includemain(){intn;printf ("Inputn:");scanf("%d",&n);hanoi(n,1,2,3);/n个金片从第一根针经过 第二根针移动到第三根针上/}/947.4变量的作用域及存储特性[例6-16]voidf1(){in tt=2;a=t;b/=t;printf(“a=%d,b=%d\n”,a,b);)}main(){in ta,b;printf(“Entera,b:”);scanf(“%d,%d”,&a,&b);f1( );/调用函数f1()/ printf(“a=%d,b=%d”,a,b);}编译程序会提示出错:Undefinedsymbol‘ a’和Undefinedsymbol‘b’。为什么?/94全局变量(外部变量)局部变量(内部变量)定义位 置函数体外函数体内作用域从定义处到文件结束从定义处到本函数结束举例所有在函数体外定义的变量(1)所有在函数体内 定义的变量(2)形式参数注意与局部变量同名的处理不同函数中同名局部变量互不干扰1.变量按作用域:分为全局变量和局部变量 2.区别:/94#includeinta,b;/a,b为全局变量/voidf1() {intt1,t2;t1=a2;t2=b 3;b=100;printf(“t1=%d,t2=%d\n”,t1,t2);}main() {a=2;b=4;f1();printf(“a=%d,b=%d”,a,b);}程序输出 结果为:t1=4,t2=12a=2,b=1007.4.1变量的作用域[例6-17]/94将程序改为 :#includeinta=2,b=4;/a,b为全局变量/voidf1(){int t1,t2;t1=a2;t2=b3; b=100;printf(“t1=%d,t2=%d\n”,t1,t2);}main(){intb=4 ;f1();printf(“a=%d,b=%d”,a,b);}程序输出结果为:t 1=4,t2=12a=2,b=4结论:全局变量与局部变量同名时,局部变量的作用域屏蔽全局变量[例6- 18]/94floatf1(inta){intb,c;…….}charf2(intx, inty){inti,j;……}main(){intm,n;…….}a,b,c有效 x,y,i,j有效m,n有效例不同函数中同名变量main(){inta,b;a=3;b=4 ;printf("main:a=%d,b=%d\n",a,b);sub();printf("main :a=%d,b=%d\n",a,b);}sub(){inta,b;a=6;b=7;pr intf("sub:a=%d,b=%d\n",a,b);}例复合语句中变量#defineN5main(){ inti;inta[N]={1,2,3,4,5};for(i=0;iinttemp; temp=a[i]; a[i]=a[N-i-1]; a[N-i-1]=temp;}for (i=0;i合语句中变量#defineN5main(){inti;inta[N]={1,2,3,4,5}; for(i=0;i1]; a[N-i-1]=temp;}for(i=0;ia[i]);}例不同函数中同名变量main(){inta,b;a=3;b=4;pr intf("main:a=%d,b=%d\n",a,b);sub();printf("main:a=%d,b= %d\n",a,b);}sub(){inta,b;a=6;b=7;printf("su b:a=%d,b=%d\n",a,b);}运行结果:main:a=3,b=4sub:a=6,b=7main:a=3,b= 4[例7-19]/94应尽量少使用全局变量,因为:全局变量在程序全部执行过程中占用存储单元降低了函数的通用性 、可靠性,可移植性降低程序清晰性,容易出错/94intp=1,q=5;floatf1(inta){ intb,c;…….}intf3(){…..}charc1,c2;charf2(intx,i nty){inti,j;……}main(){intm,n;…….}c1,c2的作用范 围p,q的作用范围externcharc1,c2;externcharc1,c2;c1,c2的作用范围扩展 后c1,c2的作用范围扩展后[例7-20]/94例7-21外部变量定义与说明intmax(intx,i nty){intz;z=x>y?x:y;return(z);}main(){externin ta,b;printf("max=%d",max(a,b));}inta=13,b=-8;运行结果:max=13 externinta,b;intmax(){intz;z=a>b?a:b;return(z); }main(){printf("max=%d",max());}inta=13,b=-8;/94/ch7_1 7.c/inta=3,b=5;max(inta,intb){intc;c=a>b?a:b; return(c);}main(){inta=8;printf("max=%d",max(a,b)) ;}例7-22外部变量与局部变量运行结果:max=8/94inti;main(){voidprt ();for(i=0;i<5;i++)prt();}voidprt(){for( i=0;i<5;i++)printf(“%c”,’’);printf(“\n”);}例 7-23外部变量副作用运行结果:/947.4.2变量的存储特性1.变量按存在时间分:静态变量,动态变量 静态存储变量:生存期为程序执行的整个过程,在该过程中占有固定的存储空间,也称永久存储。动态存储变量:只生存在某一段时间内。例如 :函数的形参、函数体或分程序中定义的变量,只有当程序进入该函数或分程序时才分配存储空间,函数/分程序执行完后,变量的存储空间又被释 放。2.变量属性:数据类型,存储特性完整的变量定义:[存储特性][数据类型]变量名;/943.变量的存储 特性1)auto型有形式参数、函数内变量、分程序变量。进入程序自动分配内存,不长期占用内存。2)static型① 局部静态变量②全局静态变量长期占用内存自动型auto静态型static寄存器型register 外部型extern/94动态变量与静态变量存储方式静态存储:程序运行期间分配固定存储空间动态存储:程序运 行期间根据需要动态分配存储空间内存用户区程序区静态存储区动态存储区全局变量、局部静态变量形参变量局部动态变量(aut oregister)函数调用现场保护和返回地址等生存期静态变量:从程序开始执行到程序结束动态变量:从包含该变量定义的 函数开始执行至函数执行结束/94[例7-24]f(inta){intb=0;staticintc=3; b++;c++;printf(“%5d%5d%5d”,a,b,c);return(a+b+c);}main(){i nta=2,k;for(k=0;k<3;k++)printf(“%5d\n”,f(a));}/943) register型将使用频率高的变量定义为register型,可以提高运行速度。寄存器变量只限于整型、字符型、指针型的局部变 量。寄存器变量是动态变量,仅允许说明两个寄存器变量。例如:registerintd;regist ercharc;数据内存运算器 运算器结果控制器 数据寄存器/944)extern型引用:extern类型变量名; 如果某个模块文件中要用到另一个模块文件中的全局变量,要用extern说明。例如:程序模块file1.c中定义了全局变量 ints;另一程序file2.c的函数fun1()需要使用这个变量s。在file2.c的fun1()对s 进行外部变量说明:fun1(){externints;/表明变量s是在其他文件定义的/....... }定义时分配内存,其他文件引用时不再分配内存。/94第7章函数与编译预处理7.1.模块化程序设计与函数7.2.函 数的定义与调用7.3.函数的递归调用7.4.变量的作用域与存储方式7.5.编译预处理7.6.函数设计举例/94 7.1模块化程序设计与函数7.1.1模块与函数1.功能模块求解较小问题的算法和程序称作“功能模块”,各功能模块可以 先单独设计,然后将求解所有子问题的模块组合成求解原问题的程序。“自顶向下”的模块化程序设计方法: 将一个大问题分解成多个解决 小问题的模块的设计思想。/942.由功能模块组成程序的结构图:主控模块模块1_1模块1_n模块2_1模块2_n模 块n_1模块n_n模块1模块2模块n3.功能模块可以用C语言的函数来实现4.函数:完成相对独立功能的程序/9 4【例7-1】求:可定义两个函数:主函数用于求n项之和被调函数用于求n !#includemain(){inti;doubles;doublejs(in tn);for(i=1;i<=20;i++)s+=js(i);printf(“%lf\n”,s);} doublejs(intn){inti;doubles=1;for(i=1;i<=n;i+ +)s=i;returns;}/94【例7-2】输入年月日,计算出该日为该年的第几天。主控 模块判断闰年求某月的天数输出输入求总天数图6-2程序结构图/94程序实现:(1)判断闰年。intle ap(intyear){intlp;lp=(year%4==0&&year%100!=0||year%400==0)?1 :0;returnlp;}/94(2)求某月的天数。intmonth_days(intyear,intmo nth){intds,d;switch(month){case1:case3:case5: case7:case8:case10:case12:d=31;break;case 2:d=leap(year)?29:28;break;default:d=30;}returnd;} /94(3)求天数和: intdays(intyear,intmonth,intday) {inti,d s=0; for(i=1;i,i); ds=ds+day; returnds; }/94(4)在主函数中分别调用三个函数。 voidmain(){intyear,month,day,t_day;printf("Inputyear-mont h-day:\n");scanf("%d-%d-%d",&year,&month,&day);t_day=days(y ear,month,day);printf("%d-%d-%dis%dthdayoftheyear!\n",ye ar,month,day,t_day);}注意: 在完整的程序中,前三个函数应放在main()函数之前。/947 .1.2模块设计三个原则模块独立。每个模块完成一个功能独立的子功能模块之间的关系力求简单使用独立变量模块规模适当分解 模块要注意层次对问题抽象化设计时细化/94C是模块化程序设计语言C是函数式语言必须有且只能有一个名为main的主函数 C程序的执行总是从main函数开始,在main中结束函数不能嵌套定义,但可以嵌套调用C程序结构源程序文件1预编译命令说 明部分执行部分函数1函数n源程序文件i源程序文件nC程序/947.2函数的定义与调用7.2.1标准库 函数定义在不同的头文件中用户使用时,必须用#include“头文件”把相应的头文件包含到程序中来。#includeth.h>/包含math.h头文件/#include/包含stdio. h头文件/main(){doublea,b;scanf(“%f“,&a);/调用输入函数, 输入变量a的值/b=sin(a);/调用sin函数,求sin(a)的值/ printf(“%6.4f”,b);}/调用输出函数,输出变量b的值/使用库函数应注意:1、函数功能2、函数参数 的数目和顺序,及各参数意义和类型3、函数返回值意义和类型4、需要使用的包含文件/947.2.2用户自定义函 数函数类型无参函数 函数的定义无参数说明有参函数 定义的参数有一个或一个以上的参数空函数 当定义的函数既无参数 也无执行语句。 空函数被调用时,什么也不做立即返回其调用函数。例无参函数printstar(){pr intf(“\n”);}或printstar(void){printf(“ \n”);}例空函数dummy(){}函数体为空/942.函数定义方式1函 数返回值类型名函数名(参数列表)参数类型说明{局部变量说明;语句序列;}方式2函数返回 值类型名函数名(参数类型说明及参数列表){局部变量说明;语句序列;}如:intmax(a,b) inta,b;如:intmax(inta,intb)函数返回值类型缺省int型无返回值v oid合法标识符函数体例有参函数(现代风格)intmax(intx,y){intz; z=x>y?x:y;return(z);}例有参函数(现代风格)intmax(int x,inty){intz;z=x>y?x:y;return(z);}/94 【例7-3】定义符号函数sign。intsign(x) /函数返回值类型未说明,默 认为int,建议给出函数类型说明/intx; /形式参数说明/{inty; /函数体局部变量/y=x>0 ?1:(x==0?0:-1);returny; /返回函数值/}注意:C语言函数分为两大部分:函数的说明部 分函数体部分。/94函数各部分作用1)函数的说明部分 函数说明部分说明函数的类型,函数名,参数表及参数类型。( 1)函数的类型说明 函数的类型即函数的返回值类型。若函数不提供返回值(即无return语句),则可定义其类型为:void。 例如:voidputdata(inta)(2)函数名函数名又称函数标识符。命名遵循C语语言标识符 的规定;函数名要反映函数完成的功能。/94(3)参数表 参数表写在函数名后的()内,由一个或多个变量标识符及类型标识符组 成。参数表中的变量称为形式参数,简称形参。若函数没有形参,则称为无参函数,其后“()”不能省略。参数必须指定类型。形参的 类型说明有两种:方法1:intmax(a,b)inta,b;方法2:intmax(i nta,intb)省略函数类型名时,C语言默认其为int型。/942)函数体 函数体包括变量定义和执行语句序列。函 数所完成的工作由函数体中一段程序实现。函数的返回值用返回语句return返回,形式:return(表达式);或r eturn表达式;函数中可有多个return语句若无return语句,遇}时,自动返回调用函数如果函数的类型与return 语句的表达式的类型不一致时,则以函数的类型为准。返回时自动进行数据转换。(见下页例题)/94【例7-4】定义函数power (x,n),求x的n次方。函数定义如下:floatpower(floatx,intn){inti;fl oatt=1;for(i=1;i<=n;i++)t=tx;/1xx…x 共乘n次/returnt;}/返回t的值//94printstar() {printf("");}main(){inta;a=printstar(); printf("%d",a);}例7-5函数带回不确定值输出:10voidprintstar(){ printf("");}main(){inta;a=printstar(); printf("%d",a);}编译错误!/947.2.3自定义函数的调用一、函数调用与声明1.函数的调用 有参数函数的调用形式:函数名(参数)无参数函数的调用形式:函数名()注意:①实参与形参个数相等,类型一致,按顺序一 一对应②实参表求值顺序,因系统而定(TurboC自右向左)③当实际参数的个数、次序、类型与对应形式 参数的个数、次序、类型不一致时,系统并不提示错误,后果却难以预测。/94函数调用形式 函数语句调用、函数表达式调用和函数参数调用voidmax(inta,intb,intc){inty;y= (a>b)?a:b;y=y>c?y:c;printf("max=%d\n",y);}voidmain( ){intx,y,z,m;scanf("%d,%d,%d",&x,&y,&z);max(x,y,z) ;}/采用函数语句形式调用函数max//94函数调用形式 intmax(inta,intb){inty;y=(a>b)?a:b;returny;}void main() {intx,y,z,m;scanf("%d,%d,%d",&x,&y,&z);m=max(x, y);m=max(m,z);printf(“max=%d\n”,m);/表达式调用形式/m=max(x, y);printf("max=%d\n",max(m,z));/函数参数调用形式/}/94main(){ inti=2,p;p=f(i,++i);printf("%d",p);}intf(int a,intb){intc;if(a>b)c=1;elseif(a==b)c=0; elsec=-1;return(c);}例7-6参数求值顺序main(){inti=2,p; p=f(i,i++);printf("%d",p);}intf(inta,intb) {intc;if(a>b)c=1;elseif(a==b)c=0;elsec=-1;return(c);}运行结果:0运行结果:1/942.函数声明函数定义在main()之后,需要进行函数说明。类型名函数名(类型1变量1,类型2变量2,…,类型n变量n);说明:函数声明应与该函数定义的函数类型与名称、形参的个数、类型、次序相一致。函数声明中的形参名可省略,其形式为: 类型名函数名(类型1,类型2,…,类型n);类型名函数名();当函数定义在主调函数之前,即先定义,后调用,则调用时函数声明可以省略。若函数返值是char或int型,系统自动按int型处理/94对被调用函数要求:必须是已存在的函数库函数:#include<.h>用户自定义函数:函数类型说明函数说明作用:告诉编译系统函数类型、参数个数及类型,以便检验函数定义与函数说明不同函数说明位置:程序的数据说明部分(函数内或外)/94[例7-7]编写计算x的n次乘方的程序。#include"stdio.h”main(){floatx,y;intn;floatpower(floatx,intn);scanf("%f,%d",&x,&n);y=power(x,n);printf(“%8.2f”,y);}floatpower(floatx,intn){inti;floatt=1;for(i=1;i<=n;i++)t=tx;returnt;}/943.形参与实参实参的个数必须与形参相等,且参数顺序、类型要对应一致。实参与形参是按位置一一对应地传递数据的。[例7-8]编程输入两个数,输出其中较大的。#include“stdio.h”main(){inta,b,m;intmax(int,int);scanf(“%d,%d”,&a,&b);m=max(a,b);printf(“max=”,m);}/94若程序运行时输入为:10,5便有输出为:10调用max函数时,实参a把值传给形参x,实参b把值传给形参y,按顺序传递,与形参名称无关。实参a和形参x,实参b和形参y一一对应。intmax(intx,inty){intt;if(x>y)t=x;elset=y;returnt;}/941)形参y之间值的传递如图4.7所示意。axby2)关于形式参数和实际参数说明如下:形式参数在函数被调用时才被分配内存。当函数执行完毕返回时,形式参数占用的内存空间便被释放。实参可以是变量、常量和表达式,形参只能是指定类型的变量。如:y=power(x,4);y=power(x,i2);但实参必须有确定的值。3)形参和实参的类型必须相容。4)形参和实参之间的关系是:单向的值的传递5)若形参与实参类型不一致,自动按形参类型转换———函数调用转换101055/94例7-9函数返回值类型转换main(){floata,b;intc;scanf("%f,%f",&a,&b);c=max(a,b);printf("Maxis%d\n",c);}max(floatx,floaty){floatz;z=x>y?x:y;return(z);} |
|