第7章用函数实现模块化程序设计程序员在设计一个复杂的应用程序时,往往是把整个程序划分成若干个功能较为单一的程序模块,先分别予以实现,然后再把所有的程序模块象搭积木一样装配起来,这种在程序设计中分而治之的策略,被称为模块化程序设计方法。voidmain(){voidprintstar();voidprint_message();printstar();print_message();printstar();}************Howdoyoudo!************voidprintstar(){printf(**************\n);}voidprint_message(){printf(Howdoyoudo!\n);}声明定义调用函数——是一段可以重复调用的、功能相对独立完整的程序段。C是函数式语言(C程序的基本组成单位——函数)必须有且只能有一个名为main的主函数C程序的执行总是从main函数开始,在main中结束函数间可以互相调用,但不能调用main函数。main函数是被操作系统调用的。函数不能嵌套定义,可以嵌套调用函数的分类:从用户角度标准函数(库函数):由系统提供用户自定义函数从函数形式无参函数getchar();rand();有参函数sqrt(x);pow(x,y);fabs(x);7.2.2定义函数的方法1.定义无参函数:类型名函数名(void){声明部分语句部分[return表达式;]}类型名函数名(){声明部分语句部分[return表达式;]}指出该函数return返回值的类型,除int,float,char等外还有void型(即函数无返回值).缺省时为int.#includestdio.hinta(){inti=1,x;x=i*4;returnx;}voidmain(){printf(%d\n,a());}7.2.2定义函数的方法2.定义有参函数:类型名函数名(形式参数列表){声明部分语句部分[return表达式;]}#includestdio.hinta(inti){intx;x=i*4;returnx;}voidmain(){printf(%d\n,a(5));}形参实参7.3调用函数的方法格式为:函数名(实参表列)注意:1.如果无参数,括号也不能省2.如果有多个实参,则各参数间用逗号隔开3.实形结合的“三一致”即:实参与形参的个数一致,对应类型一致,顺序一致(实参与形参一一对应传递数据)4.在调用函数之前必须先进行函数声明,如果不想声明,则要把函数的定义段放在主调函数之前。1、用作独立的语句2、用在表达式里3、用在实参里#includestdio.hvoidmain(){intmax(intx,inty);inti,j;scanf(%d,%d,&i,&j);printf(%d\n,max(i,j));}intmax(intx,inty){intz;z=xy?x:y;return(z);}声明调用定义例1:求任意两数中的较大数实参形参returnxy?x:y;用函数原型作为声明也可写为max(int,int);主调函数自定义函数#includestdio.hintmax(intx,inty){intz;z=xy?x:y;return(z);}voidmain(){inti,j;scanf(%d,%d,&i,&j);printf(%d\n,max(i,j));}例1:求任意两数中的较大数returnxy?x:y;主调函数自定义函数例2:计算组合公式C(m,n)=m!/(n!(m-n)!)voidmain(){intm,n;longcmn;longfac(intn);scanf(%d,%d,&m,&n);cmn=fac(m)/(fac(n)*fac(m-n));printf(%ld\n,cmn);}longfac(intn){longm=1;inti;for(i=1;i=n;i++)m*=i;returnm;}函数返回值声明调用定义#includestdio.hintgys(int,int);voidmain(){intm,n,g;scanf(%d,%d,&m,&n);g=gys(m,n);printf(“公约数=%d\n,g);}intgys(inta,intb){intr;do{r=a%b;if(r==0)break;else{a=b;b=r;}}while(1);returnb;}例3:下面是求最大公约数的函数以及调用他们的主函数7.5函数的嵌套调用例7.5输入4个整数,找出其中最大的数。用函数的嵌套调用来处理。函数不能嵌套定义但可以嵌套调用(即在一个函数内部不能定义另一个函数,但可以调用另一个函数)7.7数组作为函数参数数组元素作函数实参——传值数组名作函数参数——传地址(注意课本194黑字)intmain(){intmax(intx,inty);inta[10],m,n,i;printf(“10integernumbers:\n);for(i=0;i10;i++)sanf(%d,&a[i]);for(i=1,m=a[0],n=0;i10;i++){if(max(m,a[i])m){m=max(m,a[i]);n=i;}}printf(“largestnumberis%d\n,m);printf(“%dthnumber.\n“,n+1);}例7.9输入10个数,输出其中值最大的元素和该数是第几个数。自定义函数max:intmax(intx,inty){return(xy?x:y);}数组元素作为实参形参也是普通变量7.7.2数组名作函数参数例7.10有一个一维数组score,内放10个学生成绩,求平均成绩。#includestdio.hintmain(){floataverage(floatarray[]);floatscore[10],aver;inti;printf(input10scores:\n);for(i=0;i10;i++)scanf(%f,&score[i]);printf(\n);aver=average(score);printf(%5.2f\n,aver);return0;}函数声明实参是数组名函数调用floataverage(floatarray[]){inti;floataver,sum=array[0];for(i=1;i10;i++)sum=sum+array[i];aver=sum/10;return(aver);}定义形参数组score[0]score[i]194页例7.10有个问题:如果调用时数组的大小有变化,怎么办?答:增加一些参数从键盘输入一字符串,将该字符串反序显示屏幕上。#includestdio.h#includestring.hvoidmain(){intn;chara[100];voidfx(charx[],intn);gets(a);n=strlen(a);fx(a,n);printf(%s\n,a);}voidfx(charx[],intn){chart;inti;for(i=0;in/2;i++){t=x[i];x[i]=x[n-1-i];x[n-1-i]=t;}}可从三个方面对变量分类,即变量的数据类型,变量作用域和变量的存储类型。1、变量的作用域——是指变量在程序中的有效范围。分为局部变量和全局变量。局部变量和形参的作用域是函数内部。全局变量的作用域是整个文件。但可以通过声明一个extern的全局变量扩展全局变量的作用域,也可以通过定义一个static的全局变量限制这种扩展。2、变量的存储类型——是指变量在内存中的存储方式,表示了变量的生存期。分为静态存储和动态存储动态存储类型:auto型、register型。静态存储类型:extern型、static型。静态的局部变量只能被赋一次初值,并且生存期与全局变量相同,但作用域仍是函数内部。7.8局部变量和全局变量注意:当小作用域内的变量名与大作用域内的变量名同名时,在小作用域内引用这个变量时,遵从最小作用域原则。floatf1(inta){intb,c;……}charf2(intx,inty){inti,j;……}intmain(){intm,n;……return0;}a、b、c仅在此函数内有效x、y、i、j仅在此函数内有效m、n仅在此函数内有效floatf1(inta){intb,c;……}charf2(intx,inty){inti,j;……}intmain(){inta,b;……return0;}类似于不同班同名学生a、b也仅在此函数内有效intmain(){inta,b;……{intc;c=a+b;……}……}c仅在此复合语句内有效a、b仅在此复合语句内有效7.8.2全局变量在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量全局变量、全程变量可以为本文件中其他函数所共用有效范围为从定义变量的位置开始到本源文件结束例7.15若外部变量与局部变量同名,分析结果。#includestdio.hinta=3,b=5;intmain(){intmax(inta,intb);inta=8;printf(“max=%d\n”,max(a,b));return0;}intmax(inta,intb){intc;c=ab?a:b;return(c);}a为局部变量,仅在此函数内有效b为全局变量#includestdio.hinta=3,b=5;intmain(){intmax(inta,intb);inta=8;printf(“max=%d\n”,max(a,b));return0;}intmax(inta,intb){intc;c=ab?a:b;return(c);}a、b为局部变量,仅在此函数内有效7.9变量的存储方式和生存期7.9.1动态存储方式与静态存储方式7.9.2局部变量的存储类别7.9.3全局变量的存储类别7.9.4存储类别小结7.9.1动态存储方式与静态存储方式从变量的作用域的角度来观察,变量可以分为全局变量和局部变量从变量值存在的时间(即生存期)观察,变量的存储有两种不同的方式:静态存储方式和动态存储方式静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式动态存储方式是在程序运行期间根据需要进行动态的分配存储空间的方式程序区静态存储区动态存储区用户区将数据存放在此区全局变量全部存放在静态存储区中①函数形式参数②函数中定义的没有用关键字static声明的变量③函数调用时的现场保护和返回地址等存放在动态存储区程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中占据固定的存储单元函数调用开始时分配,函数结束时释放。在程序执行过程中,这种分配和释放是动态的每一个变量和函数都有两个属性:数据类型和数据的存储类别数据类型,如整型、浮点型等存储类别指的是数据在内存中存储的方式(如静态存储和动态存储)存储类别包括:自动的、静态的、寄存器的、外部的根据变量的存储类别,可以知道变量的作用域和生存期7.9.2局部变量的存储类别1.自动变量(auto变量)局部变量,如果不专门声明存储类别,都是动态地分配存储空间的调用函数时,系统会给局部变量分配存储空间,调用结束时就自动释放空间。因此这类局部变量称为自动变量自动变量用关键字auto作存储类别的声明7.9.2局部变量的存储类别intf(inta){autointb,c=3;┇}可以省略7.9.2局部变量的存储类别2.静态局部变量(static局部变量)希望函数中的局部变量在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值(就是上一次函数调用结束时的值),这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明3.寄存器变量(register变量)一般情况下,变量(包括静态存储方式和动态存储方式)的值是