《程序设计实习》课程(C++ProgrammingPractice)程序设计实习第四讲函数指针和高精度计算主讲教师:田永鸿yhtian@pku.edu.cn2008年3月3日北京大学《程序设计实习》课程/702上机遇到的问题程序风格请参见第一讲《程序风格》部分常见问题:1、多个语句写在1行(特别是for语句)2、没有遵循命名规范对特定问题的分析不清晰程序设计问题数组的分配……可以选用VisualStudio.Net2003/2005或其他编译环境北京大学《程序设计实习》课程/703内容提要函数调用的内存变化示意图函数指针程序阅读练习程序设计练习作业北京大学《程序设计实习》课程/704C++组件C程序是由函数构成的。程序员编写新的函数并调用C语言的函数库中的有关函数以完成具有特定功能的程序。C++程序是由类构成的。程序员编写新的类并使用C++标准类库中的类来完成编程。C++标准类库中也提供丰富的函数(数学计算、字符串操作、字符操作、输入输出、错误检查等)供程序员使用。函数在C和C++程序中都是一个非常重要的内容。北京大学《程序设计实习》课程/705数学函数库例:计算并输出900.0的平方根,用如下语句:coutsqrt(900.0);说明:sqrt()是库函数,包含在头文件math.h中;在调用sqrt()之前必须用#includemath.h语句北京大学《程序设计实习》课程/706数学函数库在math.h中还有下列函数:ceil(x)向上取整floor(x)向下取整exp(x)log(x)底数为elog10(x)pow(x,y)x的y次方sqrt(x)sin(x)cos(x)tan(x)fabs(x)//求浮点数的绝对值fmod(x,y)//双精度数取模,即x/y的余数北京大学《程序设计实习》课程/707库函数及头文件C语言中的一些库函数assert.h//设定插入点ctype.h//字符处理float.h//浮点数处理limits.h//定义各种数据类型最值常量math.h//定义数学函数stdio.h//定义输入/输出函数stdlib.h//定义杂项函数及内存分配函数string.h//字符串处理time.h//定义关于时间的函数北京大学《程序设计实习》课程/708库函数及头文件C语言中的一些库函数iostream.h或iostream//数据流输入/输出iomapip.h//参数化输入/输出fstream.h//文件输入/输出errno.h//定义错误码wchar.h//宽字符处理及输入/输出wctype.h//宽字符分类每个头文件中包含一组函数,使用哪个头文件中的函数就必须在程序中用#include语句包含哪个头文件。北京大学《程序设计实习》课程/709函数的定义函数的定义语句如下:返回值类型函数名([参数1类型参数名1,参数2类型参数名2,…]){语句1;//语句可能与参数有关语句2;//语句可能与参数有关……return返回值;//如果返回值类型为void,则不用返//回语句}北京大学《程序设计实习》课程/7010函数定义的例子下面是一个函数定义的例子:intadd(intx,inty){returnx+y;}北京大学《程序设计实习》课程/7011函数说明和函数体intmultiple(intx,inty);//函数说明voidmain(){inta=0,b=0;scanf(%d%d,&a,&b);printf(%d\n,multiple(a,b));//函数调用}intmultiple(intx,inty){//函数体returnx*y;}北京大学《程序设计实习》课程/7012函数的调用intadd(intx,inty){returnx+y;}intminus(intx,inty){returnx-y;}北京大学《程序设计实习》课程/7013函数的调用voidmain(){intn1,n2;scanf(“%d%d”,&n1,&n2);n1=add(n1,n2);n2=minus(n1,n2);if(n10&&n20)printf(“%d\n”,add(n1,n2));elseprintf(“%d\n”,minus(n1,n2));}北京大学《程序设计实习》课程/7014函数调用的过程intmax(intx,inty){if(x=y)returnx;elsereturny;}voidmain(){intx=0,y=0,z=0;x=20;y=45;intz=max(x,y);……}北京大学《程序设计实习》课程/7015函数调用的过程北京大学《程序设计实习》课程/7016函数调用的过程北京大学《程序设计实习》课程/7017函数调用的过程北京大学《程序设计实习》课程/7018函数调用的过程北京大学《程序设计实习》课程/7019函数调用的过程北京大学《程序设计实习》课程/7020函数调用的过程北京大学《程序设计实习》课程/7021参数传递:传值和传地址A程序可以向B程序传递某些数值,也可以向B程序传递内存地址。北京大学《程序设计实习》课程/7022参数传递:传值intmax(intx,inty){if(x=y)returnx;elsereturny;}voidmain(){intx=0,y=0,z=0;x=20;y=45;intz=max(x,y);……}北京大学《程序设计实习》课程/7023参数传递:传地址(指针方式)intswap(int*x,int*y){inttmp=0;tmp=*x;*x=*y;*y=tmp;}北京大学《程序设计实习》课程/7024参数传递:传地址(引用方式)voidmain(){inta=0,b=0;a=20;b=45;if(ab)swap(&a,&b);……}北京大学《程序设计实习》课程/7025程序运行过程北京大学《程序设计实习》课程/7026程序运行过程北京大学《程序设计实习》课程/7027程序运行过程北京大学《程序设计实习》课程/7028程序运行过程北京大学《程序设计实习》课程/7029程序运行过程北京大学《程序设计实习》课程/7030程序运行过程北京大学《程序设计实习》课程/7031程序运行过程北京大学《程序设计实习》课程/7032函数的返回值函数执行完以后可以向调用它的程序返回一个值,表明函数运行的状况。很多函数的功能就是对参数进行某种运算,之后通过函数返回值给出运算结果。函数的返回值可以有不同的类型,返回值类型在函数定义时说明。北京大学《程序设计实习》课程/7033函数的返回值intmin(intx,inty);//返回值类型为int,有两个整型参数,函数名为mindoublecalculate(inta,doubleb);//返回值类型为double,有一个整型参数,一个double型参数,函数名为calculatecharjudge(void);//返回值类型为char,没有参数,函数名为judgevoiddoit(inttimes);//返回值类型为void,表示不返回任何值,有一个整型参数,函数名为doit北京大学《程序设计实习》课程/7034函数指针的定义在C语言中,函数本身不是变量,但可以定义指向函数的指针,这种指针可以被赋值、存放于数组之中,传递给函数及作为函数的返回值返回值类型(*函数指针名)(参数表);例1:intsquare(int);int(*f)(int)=square;例2:voidf1(int);voidf2(int);voidf3(int);void(*f[3])(int)={f1,f2,f3};北京大学《程序设计实习》课程/7035函数指针的使用#includestdio.hintsquare(intx){printf(0%d\n,x);return0;};int(*f)(int)=square;voidf1(intx){printf(1%d\n,x);};voidf2(intx){printf(2%d\n,x);};voidf3(intx){printf(3%d\n,x);};void(*fp[3])(int)={f1,f2,f3};voidmain(){(*f)(0);(*fp[0])(1);(*fp[1])(2);(*fp[2])(3);}北京大学《程序设计实习》课程/7036函数指针作为参数传递intsum(inta,intb,int(*term)(int)){if(ab)return0;return(*term)(a)+sum(a+1,b,(*term));}intterm(inta){returna;}voidmain(){coutsum(69,90,term)endl;ints=0;for(inti=69;i=90;i++)s+=i;coutsendl;}北京大学《程序设计实习》课程/7037程序阅读理解intsum(inta,intb,int(*term)(int)){if(ab)return0;return(*term)(a)+sum(a+1,b,(*term));}intcube_term(inta){returna*a*a;}voidmain(){coutsum(1,3,cube_term)endl;cout1*1*1+2*2*2+3*3*3endl;}北京大学《程序设计实习》课程/7038程序阅读理解#includeiostream.hdoublesum(inta,intb,double(*term)(int)){if(ab)return0;return(*term)(a)+sum(a+1,b,(*term));}doublepi_term(inta){return(1.0/(4*(a-1)+1))*(1.0/(4*(a-1)+3));}voidmain(){coutsum(2,5,pi_term)endl;cout1.0/(5*7)+1.0/(9*11)+1.0/(13*15)+1.0/(17*19)endl;}北京大学《程序设计实习》课程/7039函数模板不同数据类型用不同程序逻辑进行类似的操作。如果每种数据类型的程序逻辑和操作相同,那么用函数模板(functiontemplate)完成这项工作更加简洁和方便。程序员编写函数模板定义,编译器根据函数调用中的参数类型自动生成不同的模板函数(templatefunction)来处理不同类型的调用。一个函数模板定义了一系列解决方案。templateclassTTsum(inta,intb,T(*term)(int)){if(ab)return0;return(*term)(a)+sum(a+1,b,(*term));}intterm1(inta){returna;}intterm2(inta){returna*a*a;}doubleterm3(inta){return(1.0/(4*(a-1)+1))*(1.0/(4*(a-1)+3));}voidmain(){coutsum(1,3,term1)endl;coutsum(1,3,term2)endl;coutsum(1,3,term3)endl;}北京大学《程序设计实习》课程/7041C语言库函数中的几个带函数参数的函数#includestdlib.hqsort//快速排序Bsearch//数组的二分法搜索#includesearch.h_lfind//线性搜索_lsearch//线性搜索_lfind与_lsearch不同点在于,当找不到关键数据时_lfind仅会返回NULL,_lsearch会主动把该笔数据加入数组尾端。北京大学《程序设计实习》课程/7042qsortvoidqso