第4章 函数和作用域 (2008-06-09 08:39:47) 转载 标签: it 分类: c++学习相关 第4章 函数和作用域 引例:计算 的和 一个C++程序必须由一个主函数和若干个子函数(可以是零个)构成。程序的运行,总是开始于主函数,也结束于主函数。 一般由主函数调用子函数,子函数之间也可以相互调用。同一子函数可被一个或多个函数调用任意多次,每调用一次函数时,最多可以得到一个返回值。 4.1 函数的定义 一、函数定义的一般形式 static 返回值类型 函数名(形参表) extern { 函数体 } 二、有关说明: 1、static:静态函数,限文件内使用 extern:外部函数,其它文件也可以调用。省略时按extern方式处理。 2、返回值类型 char 返回一个字符型值 要求函数体内有 return语句 int 返回一个整型值 double 返回一个双精度值 void 明确不带返回值 可以无return语句 4.2 函数的说明和调用(使用) 一、调用前的准备(函数的说明) 在调用函数之前,一般应进行调用前的准备,即对被调函数的返回值类型、函数参数等做出说明,以便编译器事先了解情况,做好调用前的准备。 如果一个函数定义在先,调用在后,则调用前可以不必说明;否则,如果一个函数定义在后,调用在先,则调用前必须说明。虽然如此,但总是提倡进行“函数说明”的做法。 函数的说明的格式 static 返回值类型 函数名(形参表); extern 二、函数调用的格式 函数名(实参表); 三、函数调用机制 1、形参的特点:形参就是形式上的参数,它们是一些带类型的标识符。在函数未被调用的时候形参不占内存单元,在定义函数的时候,可以将其理解为“已知量”。 2、实参的特点:实参就是实际上的参数。实参必须有类型,其具体形式可以是常量,也可以是变量或表达式。在即将进行函数调用的时刻,实参值必须是可求出的。 3、C++要求:函数的实参和形参个数相等,对应类型一致。 4、函数调用的机制: A)函数调用前,形参不占用内存单元; B)函数调用启动时,临时给形参分配内存单元; C)计算实参的值,并将其一一对应地传递给形参; D)执行被调函数的函数体; E)系统释放形参所占内存单元。 F)返回主调函数的调用点。 结论:实参的任务是为形参提供数据,由于在函数调用后即将返回调用点之前已经释放了形参所占的内存单元,因此,无论在任何情况下,形参值的变化永远也影响不了实参。 四、默认参数值 1、默认参数值的设置是在 “函数的说明”时进行的; 2、默认参数值的设置遵守“靠后有值”原则。即:当某个参数有默认值时,其后的参数必有默认值。 五、例题 1、一般变量作为函数参数 例题2:已知x=3,y=4,用公式 求d=? #include <iostream.h> #include <math.h> double f(double x,double y) { double z; x=x*x; y=y*y; z=sqrt(x+y); return z; } void main() { double f(double x,double y); double a,b,d; a=3.0; b=4.0; d=f(a,b); cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"d="<<d<<endl; } 运行结果: a=3 b=4 d=5 2、引用作为函数参数 #include <iostream.h> #include <math.h> double f(double &x,double &y) { double z; x=x*x; y=y*y; z=sqrt(x+y); return z; } void main() { double f(double &x,double &y); double a,b,d; a=3.0; b=4.0; d=f(a,b); cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"d="<<d<<endl; } 运行结果: a=9 b=16 d=5 3、地址作为函数参数 一维数组中有10个double型元素,求其各元素的平均值。 方案一: #include <iostream.h> double average(double x[],int n) { double aver=0.0; for(int i=0;i<n;i++) aver+=x[i]; return aver/10.0; } void main() { double average(double a[],int n); double a[10]={1,2,3,4,5,6,7,8,9,10}; double y; y=average(a,10); cout<<"average="<<y<<endl; } 方案二: #include <iostream.h> double average(double *p,int n) { double aver=0.0; for(int i=0;i<n;i++) aver+=*p++; return aver/10.0; } void main() { double average(double a[],int n); double a[10]={1,2,3,4,5,6,7,8,9,10}; double y; y=average(a,10); cout<<"average="<<y<<endl; } 4.3 内联函数 一、函数调用的利弊 使用函数有利于代码重用,可以提高开发效率,增强程序的可靠性,也便于分工合作,便于修改维护。 但是,函数调用时都会需要一些额外的开销,主要是系统栈的保护、代码的传递、系统栈的恢复、参数传递等,对于一些调用频率很高的函数,这种开销就变得非常可观,特别是对于一些函数体非常小的函数,这样的开销会让人觉得很不划算。 内联函数不是在调用时发生转移,而是在编译时将函数体嵌入调用处,这样就可以节省调用时参数传递、系统栈的保护与恢复等开销。 二、内联函数的语法格式 inline返回值类型 函数名(形参表) { 函数体 } 三、使用内联函数应该注意的 1、内联函数体中不许出现循环语句和开关语句,也不许出现递归。 2、内联函数的定义必须出现在第一次被调用之前。 3、对内联函数不能进行异常接口声明。 四、例题 #include <iostream.h> inline int max(int x,int y) { if(x>y) return x; else return y; } void main() { int a,b,c,d,e,m; a=34; b=56; c=22; d=100; e=88; m=max(a,b); m=max(m,c); m=max(m,d); m=max(m,e); cout<<"max="<<m<<endl; } 课堂作业:P135—2、11 4.5 函数重载 函数的重载也称多态函数。函数的重载一般出现在功能相近的函数之间。 C++允许两个或多个函数取名相同,但其形参个数、或者形参的类型不能相同。调用函数时,系统会根据实参与形参的个数或类型进行匹配,自动确定该调用哪个函数。这就是函数的重载。 注意:C语言没有重载机制。 一、参数类型不同的函数重载 #include <iostream.h> int add(int x,int y); double add(double x,double y); void main() { cout<<add(10,23)<<endl; cout<<add(10.0,20.5)<<endl; } int add(int x,int y) { return (x+y); } double add(double x,double y) { return (x+y); } 二、参数个数不同的函数重载 #include <iostream.h> int max(int,int); int max(int,int,int); int max(int,int,int,int); void main() { cout<<max(10,23)<<endl; cout<<max(1,20,18)<<endl; cout<<max(1,10,15,33)<<endl; } int max(int a,int b) { return (a>b?a:b); } int max(int a,int b,int c) { int t=max(a,b); return max(t,c); } int max(int a,int b,int c,int d) { int t1=max(a,b); int t2=max(c,d); return max(t1,t2); } 4.6 函数的嵌套调用和递归调用 一、函数的嵌套调用 计算 的值,假定 #include <iostream.h> const int k=4; const int n(6); int sumOfPowers(int k,int n); int powers(int m,int n); void main() { cout<<sumOfPowers(n,k)<<endl; } int powers(int x,int y) //计算x的y次方 { int product=1; for(int i=1;i<=y;i++) product *= x; return product; } int sumOfPowers(int n,int k) { int sum(0); for(int i=1;i<=n;i++) sum+=powers(i,k); return sum; } 二、函数的递归调用 递归函数又叫自调用函数,其特点是在函数内部直接或间接地自己调用自己。 递归函数的经典例题只有两个:求阶乘、计算兔子问题(P113)。 例题:求阶乘 #include <iostream.h> long fac(int n); long fac(int n) { long p; if(n==0) p=1; else p=n*fac(n-1); return p; } void main() { cout<<fac(8)<<endl; } 例题:计算兔子问题 #include <iostream.h> long F(unsigned n); long F(unsigned n) { if(n==0||n==1) return 1; else return F(n-1)+F(n-2); } void main() { cout<<F(8)<<endl; } 4.7 作用域(起作用的范围,自学) 一