第七章函数§7.1函数一、函数及其定义1.函数定义的一般形式(p114)返回值类型函数名(形式参数表)形式参数类型描述;{(函数内部的)变量定义与有关说明语句部分函数的可执行语句序列}[函数头]、[函数体][例7-1]求两个整数的最大值的函数定义。(或p115)intmax(x,y)/*定义了有两个形式参数x,y且返回int值的函数max*/intx,y;/*说明了形参x,y均为int型*/{intz;/*定义了函数内部使用的变量z*/z=xy?x:y;/*将x,y中较大值送入z*/return(z);/*将z做为函数返回值,并使函数返回到被调程序(父程序)*/}2.关于函数返回值类型①允许C基本数据类型和任何有意义的用户自定义类型。②如果省略返回值类型则隐含返回int类型。③没有返回值的函数。3.关于形式参数及形参说明函数参数是为在函数和父程序间传递数据而设置的。各参数在被父程序调用时才从父程序处获得真正的值,因而在定义函数时参数是“形式上”的值称形式参数,简称形参。函数被调用时形参从父程序处获得的真实值称实际参数,简称实参。实参传递给形参的过程称实形结合,加上函数处理结果返回到父程序的过程统称函数的参数传递,函数参数传递是函数技术中的重要内容。①形参之间以“,”分隔。②形参是局部性变量,只在函数内有效。③两种形参说明效果相同。④无参函数的()不能省略,以示位于()前面的标识符是函数名。charGetCHAR(){intk;k=getchar();if(k=’a’&&k=’z’)returnk-32;elsereturn0;}4.关于函数体与函数返回。①函数体是实现函数功能的程序片断,函数体的设计与通常的编程在编程思想和技术上没有任何差别。②返回语句return使函数退出运行返回到父程序继续执行,同时将函数值带回父程序。return语句共有4种形式。return(表达式);return表达式;return;无return语句。③return语句可以安排在函数体任何位置,也可安排多条return语句。5.关于多个函数的位置关系:并列关系而非嵌套关系。6.关于主函数main()①程序中有且仅有一个main()函数,程序从main()函数开始执行。②main()函数也有形参,参数由操作系统给出,即“命令行参数”。二、函数调用1.函数调用的一般形式(p115)函数名(实参表)2.函数调用与函数执行过程(p116)(1)为函数的形参分配内存空间;(2)计算实参表达式的值,并将实参表达式的值赋给对应的形参;(3)为函数的局部变量分配内存空间;(4)执行函数体内的语句片段;(5)函数体执行完毕或执行了函数体内的return语句(若return语句带表达式,则计算出该表达式的值,并以此值作为函数的返回值)后,释放为这次函数调用分配的全部内存空间;(6)将函数及返回值返回到父程序的函数调用处,继续执行父程序。[例7-2]如下给出了程序中调用max函数的全过程说明。#includestdio.hfloatmax(floatx,floaty){floatz;z=xy?x:y;returnz;}main(){floata=19.8,b=-98.8,c;c=max(a,b);printf(MAX(a,b)=%f\n,c);}三、函数的参数传递方式1.传值方式[例7-3]返回阶乘的函数及其调用,函数调用时参数采用传值方式。#includestdio.hfloatfac(intn){intf=1.0;while(n=1){f=f*n;--n;}return(f);}main(){intk=6;printf(%8.1f\n,fac(k));}2.传地址方式[例7-4]返回阶乘的函数及其调用,函数调用时采用传地址方式。#includestdio.hfloatfac(int*n){intf=1.0;while(*n=1){f=f*(*n);--(*n);}return(f);}main(){intk=6;printf(%8.1f\n,fac(&k));}[要点]传值方式中函数对形参的处理是在函数内部变量中进行的,形参在函数内的改变不会使与之结合的实参变量发生变化,称变量直接操作。传地址方式中函数对形参的处理是在形参的所指对象单元即与形参结合的实参变量上进行的,形参在函数中的改变实质是实参变量的改变,称变量间接操作。四、函数的类型说明[函数类型说明有三种方法]①将函数定义放在函数调用之前。②在函数调用之前的任何位置安排一条类型说明语句,形式为:返回值类型函数名();③在调用函数的父程序内的变量定义处,顺便说明函数返回值类型。[规定]如果函数返回int,char类型可以不进行函数类型说明。§7.2指针与函数的参数传递一、向函数中传递变量的指针[例7-5]试图用swap()函数将两实参变量的值交换。void_swap(intx,inty){intz;z=x;x=y;y=z;}main(){inta=10,b=20;_swap(a,b);printf(a=%d,b=%d\n,a,b);}[结论]传值方式不能将“形参的值”“传回”父程序中的实参。[例7-6]用swap函数将两实参变量的值交换。#includestdio.hvoidswap(int*x,int*y){intz;z=*x;*x=*y;*y=z;}main(){inta=10,b=20;swap(&a,&b);printf(a=%d,b=%d\n,a,b);}[结论]传地址方式可以将“形参的值”“传回”父程序中的实参。二、通过指针向函数中传递一维数组[方法]定义一个指针形参,函数调用时将实参数组的首地址赋值给指针形参,从而达到“对形参数组的处理是在实参数组上进行的”的效果。[例7-7]求整型数组各元素之和。intadd(int*x,intn){intsum,i;for(sum=0,i=0;in;i++)sum+=*(x+i);returnsum;}main(){intarr[4]={1,3,4,5},s;s=add(arr,4);printf(%d\n,s);}数组的元素描述形式也可采用下标法或元素指针法。for(sum=0,i=0;in;i++)sum+=x[i];/*下标法*/for(sum=0,i=0;in;i++)sum+=x++;/*元素指针法*/20001arr[0]20023arr[1]20044arr[2]20065arr[3]20082000x20104n2012sum2014i三、通过指针向函数中传递字符串[方法]定义一个指向字符(串)的指针变量作形参,调用时将字符串的首地址与形参变量结合使形参指针指向了实参字符串。这样在函数中对字符串的处理实质是在实参字符串上进行的。[例7-8]将字符串中所有小写字母改成大写字母进行输出,小写转大写工作由自定义函数StrToUpr()完成。voidStrToUpr(char*s){while(*s!='\0'){if(*s='a'&&*s='z')*s=*s-('a'-'A');++s;}}main(){charstr[40];gets(str);StrToUpr(str);puts(str);}[例7-9]用函数实现字符串的复制。#includestdio.hvoidStrCopy(char*from,char*to){while(*from!='\0')*to++=*from++;*to='\0';}main(){charstr1[40],str2[40];gets(str1);StrCopy(str1,str2);puts(str2);}四、通过指针向函数中传递二维数组[方法]传二维数组首地址以使函数中的形参指针指向二维数组,形成“对形参数组处理实质上是在实参二维数组上进行”的效果。[例7-10]求二维数组中元素的最大值。[程序1]intArr2Max(inta[][3],intm)/*intArr2Max(int(*a)[3],intm)*/{intmax=-32768,i,j;for(i=0;im;i++)for(j=0;j3;j++)if(a[i][j]max)max=a[i][j];returnmax;}main(){intarr[2][3]={{1,4,7,},{4,18,6}};printf(MAX=%d\n,Arr2Max(arr,2));}[程序2]形参描述为指向一维数组的指针,函数描述改为intArr2Max(int(*a)[3],intm)。[程序3]形参描述为指向一维数组的指针,元素的处理采用游动的元素指针法。#includestdio.hintArr2Max(int(*a)[3],intm){intmax=-32768,j;int(*p)[3];for(p=a;pa+m;p++)for(j=0;j3;j++)if((*p)[j]max)max=p[0][j];returnmax;}main(){intarr[2][3]={{1,4,7,},{4,18,6}};printf(MAX=%d\n,Arr2Max(arr,2));}五、返回指针的函数[例7-11]某字符数组中存有两个字符串以‘\0’做为串结束符,即字符数组中先存一个字符串以‘\0’结束,从‘\0’的下一字符位置又存有一个字符串以‘\0’结束,如下程序可以打印出第2个字符串。#includestdio.hchar*SecondStr(char*s){while(*s!='\0')s++;return(s+1);}main(){charstr[40]=abcdef\0ABCDEFGH,*str2;str2=SecondStr(str);puts(str2);}§7.3函数程序设计[要点1]必须了解开发环境所能提供的系统函数。[要点2]如何设计给定功能的函数,设计必须严格按如下步骤进行。(1)清楚知道函数所要完成的功能。(2)入口参量设计。要说明参数个数,传递方式,形参名,参数含义。(3)出口参量设计。要说明出口参量个数,参量传递方式,参量含义。(4)写出正确的函数头描述。(5)函数体设计。[要点3]如何划分函数。一、给定功能设计函数[例7-12]设计函数计算n![设计过程](1)明确函数功能:求一个正整数的阶乘。(2)入口参量设计。(3)出口参量设计。(4)函数头描述:floatfac(intn)(5)函数体设计。floatfac(intn){inti;floatp;for(p=1,i=1;i=n;i++)p*=i;returnp;}[例7-13]设计函数求一维数组中的最大值和最小值。[设计过程]⑴入口参量。⑵出口参量。⑶函数头描述。voidMaxMin(a,n,max,min)floata[],*max,*min;/或float*a,*max,*min;*/intn;⑷函数体设计。[函数及调用程序]voidMaxMin(a,n,max,min)floata[],*max,*min;intn;{inti;*max=*min=a[0];for(i=1;in;i++){if(a[i]*max)*max=a[i];if(a[i]*min)*min=a[i];}}main(){floata[5]={1,23,45,-9,7},c,d;MaxMin(a,5,&c,&d);printf(MAX=%6.1fMIN=%6.1f\n,c,d);}[例7-14]编写函数将3个整数排序并求和。[设计过程]⑴参量设计。⑵函数头描述。intSortSum(int*x1,int*x2,int*x3)[函数设计结果]intSortSum(int*x1,int*x2,int*x3){intt;if(*x1*x2){t=*x1;*x1=*x2;*x2=t;}if(*x1*x3){t=*x1;*x1=*x3;*x3=t;}if(*x2*x3){t=*x2;*x2=*x3;*x3=t;}return(*x1+*x2