第11章对函数的进一步讨论11.1传给main函数的参数11.2通过实参向函数传递函数名或指向函数的指针变量11.3函数的递归调用2020年1月11日8时45分11.1传给main函数的参数在此之前,我们在编写main函数时,其后一对圆括号中是空的,没有参数。其实在支持C的环境中,可以在运行C程序时,通过运行C程序的命令行把参数传送给C程序。2020年1月11日8时45分11.1传给main函数的参数main函数通常可用两个参数,习惯上这两个参数写为argc和argv。因此,main函数的函数头可写为main(argc,argv)C语言还规定argc(第一个形参)必须是整型变量,argv(第二个形参)必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:main(argc,argv)intargv;char*argv[];或写成:main(intargc,char*argv[])2020年1月11日8时45分11.2通过实参向函数传递函数名或指向函数的指针变量如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址,称为这个函数的指针。2020年1月11日8时45分11.2通过实参向函数传递函数名或指向函数的指针变量可以定义一个指向函数的指针变量,用来存放某一函数的起始地址,这就意味着此指针变量指向该函数。例如:int(*p)(int,int);定义p是指向函数的指针变量,它可以指向类型为整型且有两个整型参数的函数。p的类型用int(*)(int,int)表示2020年1月11日8时45分例11.1用函数求整数a和b中的大者。解题思路:定义一个函数max,实现求两个整数中的大者。在主函数调用max函数,除了可以通过函数名调用外,还可以通过指向函数的指针变量来实现。分别编程并作比较。2020年1月11日8时45分(1)通过函数名调用函数#includestdio.hintmain(){intmax(int,int);inta,b,c;printf(pleaseenteraandb:);scanf(%d,%d,&a,&b);c=max(a,b);printf(“%d,%d,max=%d\n,a,b,c);return0;}2020年1月11日8时45分intmax(intx,inty){intz;if(xy)z=x;elsez=y;return(z);}2020年1月11日8时45分(2)通过指针变量访问它所指向的函数#includestdio.hintmain(){intmax(int,int);int(*p)(int,int);inta,b,c;p=max;printf(pleaseenteraandb:);scanf(%d,%d,&a,&b);c=(*p)(a,b);printf(“%d,%d,max=%d\n,a,b,c);return0;}必须先指向,若写成p=max(a,b);错只能指向函数返回值为整型且有两个整型参数的函数2020年1月11日8时45分11.2通过实参向函数传递函数名或指向函数的指针变量定义指向函数的指针变量的一般形式为数据类型(*指针变量名)(函数参数表列);如int(*p)(int,int);p=max;对p=max(a,b);错p+n,p++,p--等运算无意义2020年1月11日8时45分例11.2输入两个整数,然后让用户选择1或2,选1时调用max函数,输出二者中的大数,选2时调用min函数,输出二者中的小数。解题思路:定义两个函数max和min,分别用来求大数和小数。在主函数中根据用户输入的数字1或2,使指针变量指向max函数或min函数。2020年1月11日8时45分#includestdio.hintmain(){intmax(int,int);intmin(intx,inty);int(*p)(int,int);inta,b,c,n;scanf(%d,%d,&a,&b);scanf(“%d”,&n);if(n==1)p=max;elseif(n==2)p=min;c=(*p)(a,b);printf(a=%d,b=%d\n,a,b);if(n==1)printf(max=%d\n,c);elseprintf(min=%d\n,c);return0;}只看此行看不出调用哪函数2020年1月11日8时45分intmax(intx,inty){intz;if(xy)z=x;elsez=y;return(z);}intmin(intx,inty){intz;if(xy)z=x;elsez=y;return(z);}2020年1月11日8时45分11.2通过实参向函数传递函数名或指向函数的指针变量指向函数的指针变量的一个重要用途是把函数的地址作为参数传递到其他函数指向函数的指针可以作为函数参数,把函数的入口地址传递给形参,这样就能够在被调用的函数中使用实参函数2020年1月11日8时45分11.2通过实参向函数传递函数名或指向函数的指针变量……intmain(){……fun(f1,f2)……}voidfun(int(*x1)(int),int(*x2)(int,int)){inta,b,i=3,j=5;a=(*x1)(i);b=(*x2)(i,j);}相当于a=f1(i);相当于b=f2(i,j);2020年1月11日8时45分例11.3有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大者,输入2,就给出a和b中小者,输入3,则求a与b之和。解题思路:与例8.23相似,但现在用一个函数fun来实现以上功能。2020年1月11日8时45分#includestdio.hintmain(){voidfun(intx,inty,int(*p)(int,int));intmax(int,int);intmin(int,int);intadd(int,int);inta=34,b=-21,n;printf(pleasechoose1,2or3:);scanf(“%d”,&n);if(n==1)fun(a,b,max);elseif(n==2)fun(a,b,min);elseif(n==3)fun(a,b,add);return0;}2020年1月11日8时45分intfun(intx,inty,int(*p)(int,int)){intresout;resout=(*p)(x,y);printf(“%d\n”,resout);}intmax(intx,inty){intz;if(xy)z=x;elsez=y;printf(max=);return(z);}输入的选项为1时相当于max(x,y)2020年1月11日8时45分intfun(intx,inty,int(*p)(int,int)){intresout;resout=(*p)(x,y);printf(“%d\n”,resout);}intmax(intx,inty){intz;if(xy)z=x;elsez=y;printf(max=);return(z);}输入的选项为2时相当于min(x,y)2020年1月11日8时45分intfun(intx,inty,int(*p)(int,int)){intresult;result=(*p)(x,y);printf(“%d\n”,result);}intmax(intx,inty){intz;if(xy)z=x;elsez=y;printf(max=);return(z);}输入的选项为3时相当于add(x,y)2020年1月11日8时45分intmin(intx,inty){intz;if(xy)z=x;elsez=y;printf(min=);return(z);}intadd(intx,inty){intz;z=x+y;printf(sum=);return(z);}2020年1月11日8时45分11.3函数的递归调用在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。C语言的特点之一就在于允许函数的递归调用。2020年1月11日8时45分f2函数调用f1函数11.3函数的递归调用intf(intx){inty,z;z=f(y);return(2*z);}f函数调用f函数f1函数调用f2函数应使用if语句控制结束调用直接调用本函数间接调用本函数2020年1月11日8时45分11.3函数的递归调用例11.4有5个学生坐在一起问第5个学生多少岁?他说比第4个学生大2岁问第4个学生岁数,他说比第3个学生大2岁问第3个学生,又说比第2个学生大2岁问第2个学生,说比第1个学生大2岁最后问第1个学生,他说是10岁请问第5个学生多大2020年1月11日8时45分11.3函数的递归调用解题思路:要求第5个年龄,就必须先知道第4个年龄要求第4个年龄必须先知道第3个年龄第3个年龄又取决于第2个年龄第2个年龄取决于第1个年龄每个学生年龄都比其前1个学生的年龄大22020年1月11日8时45分11.3函数的递归调用解题思路:age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10)1(2)1()()1(10)(nnagenagennage2020年1月11日8时45分age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10age(2)=12age(3)=14age(4)=16age(5)=18回溯阶段递推阶段2020年1月11日8时45分age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10age(2)=12age(3)=14age(4)=16age(5)=18回溯阶段递推阶段结束递归的条件2020年1月11日8时45分#includestdio.hintmain(){intage(intn);printf(NO.5,age:%d\n,age(5));return0;}intage(intn){intc;if(n==1)c=10;elsec=age(n-1)+2;return(c);}2020年1月11日8时45分age(5)输出age(5)mainc=age(4)+2age函数n=5c=age(3)+2age函数n=4c=age(1)+2age函数n=2c=age(2)+2age函数n=3c=10age函数n=1age(1)=10age(2)=12age(3)=14age(4)=16age(5)=18182020年1月11日8时45分例11.5用递归方法求n!。解题思路:求n!可以用递推方法:即从1开始,乘2,再乘3……一直乘到n。递推法的特点是从一个已知的事实(如1!=1)出发,按一定规律推出下一个事实(如2!=1!*2),再从这个新的已知的事实出发,再向下推出一个新的事实(3!=3*2!)。n!=n*(n-1)!。2020年1月11日8时45分例11.5用递归方法求n!。解题思路:求n!也可以用递归方法,即5!等于4!×5,而4!=3!×4…,1!=1可用下面的递归公式表示:)1()1()1,0(1!!nnnnnn2020年1月11日8时45分#includestdio.hintmain(){intfac(intn);intn;inty;printf(inputanintegernumber:);scanf(%d,&n);y=fac(n);printf(%d!=%d\n,n,y);return0;}2020年1月11日8时45分intfac(intn){intf;if(n0)printf(n0,dataerror!);