• 1. 第七章 函数C++语言程序设计第七章 函数
  • 2. 2本章主要内容函数的声明和调用 函数间的参数传递 内联函数 带默认形参值的函数 函数重载
  • 3. 3函数的声明函数是面向对象程序设计中,对功能的抽象 函数声明的语法形式 类型标识符 函数名(形式参数表) { 语句序列 }函数的声明与使用若无参数,写void是被初始化的内部变量,寿命和可见性仅限于函数内部若无返回值,写void
  • 4. 4函数的声明形式参数表 name1, name2, ..., namen 函数的返回值 由 return 语句给出,例如: return 0 无返回值的函数(void类型),不必写return语句。函数的声明与使用
  • 5. 函数原型确保 函数原型语句与函数调用表达式出现在同一个文件中。 构成一个头文件 将程序中用户定义的所有全局函数的原型语句组织在一起,构成一个头文件。函数的声明与使用
  • 6. 常数参数 void f1(const int &x,char * y); 在函数定义时,只允许函数访问形参的值,而不允许修改它的值。函数的声明与使用常数形参
  • 7. 1.可以把整个数组作为参数传递给函数。 2.在说明一个一维数组参数时,可以不限定数组 元素的个数;在说明一个二维数组参数时,可以不限定数组的行数(数组参数的第一维可不限定)。 3.在调用具有数组参数的函数时,须以单独的数组名作为实在参数。 4. int c[][N]等价于 int(*c)[N];函数的声明与使用数组作为参数
  • 8. 8默认形参值的作用函数在声明时可以预先给出默认的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。 例如:int add(int x=5,int y=6) { return x+y; }void main(void) { add(10,20); //10+20 add(10); //10+6 add(); //5+6 }带默认形参值的函数
  • 9. 9默认形参值的说明次序默认形参值必须从右向左顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。 例: int add(int x,int y=5,int z=6); //正确 int add(int x=1,int y=5,int z); //错误 int add(int x=1,int y,int z=6); //错误带默认形参值的函数
  • 10. 10默认形参值与函数的调用位置调用出现在函数体实现之前时,默认形参值必须在函数原形中给出;而当调用出现在函数体实现之后时,默认形参值需在函数实现时给出。 例:int add(int x=5,int y=6); void main(void) { add(); //调用在实现前 } int add(int x,int y) { return x+y; }int add(int x=5,int y=6) { return x+y; } void main(void) { add(); //调用在实现后 }带默认形参值的函数
  • 11. 11默认形参值的作用域在相同的作用域内,默认形参值的说明应保持唯一,但如果在不同的作用域内,允许说明不同的默认形参。 例: int add(int x=1,int y=2); void main(void) { int add(int x=3,int y=4); add(); //使用局部默认形参值(实现3+4) } void fun(void) { ... add(); //使用全局默认形参值(实现1+2) }带默认形参值的函数
  • 12. 12内联函数声明与使用声明时使用关键字 inline。 编译时在调用处,用函数体进行替换,节省了参数传递、控制转移等开销。 注意: 内联函数体内不能有循环语句和switch语句。 内联函数的声明必须出现在内联函数第一次被调用之前。 内联函数
  • 13. 13例 内联函数应用举例#include using namespace std; inline double CalArea(double radius) { return 3.14*radius*radius; } int main() { double r(3.0); double area; area=CalArea(r); cout<
  • 14. 14函数的调用调用前先声明函数原型: 在调用函数中,或程序文件中所有函数之外,按如下形式说明: 类型标识符 被调用函数名 (含类型说明的形参表); 调用形式 函数名(实参列表) 嵌套调用 函数可以嵌套调用,但不允许嵌套定义。 递归调用 函数直接或间接调用自身。函数的声明与使用
  • 15. 15函数调用的执行过程函数的声明与使用main() 调fun() 结束fun() 返回①②④⑥⑦保存: 返回地址 当前现场③恢复: 主调程序现场 返回地址⑤
  • 16. 16嵌套调用函数的声明与使用main{} 调fun1() 结束fun1() 调fun2() 返回fun2() 返回①②③⑦④⑤⑥⑧⑨
  • 17. 17递归调用函数直接或间接地调用自身,称为递归调用。 递归过程的两个阶段: 递推: 4!=4×3! → 3!=3×2! → 2!=2×1! → 1!=1×0! → 0!=1 未知 已知 回归: 4!=4×3!=24←3!=3×2!=6←2!=2×1!=2←1!=1×0!=1←0!=1 未知 已知函数的声明与使用
  • 18. 函数的调用..—— 递归算法都必须满足的的三个条件: 1.有明确的结束递归的条件:n=0或n=1,此条件下可以直接得出结果:1 ; 2.要解决的问题可以转化为相对简单的同类型的问题:n!可转化为 n·(n-1)!,而 (n-1)! 就是比 n! 稍简单的同类型的问题; 3.随着问题的逐次转换,最终能达到结束递归的条件:算法中的参数 n 在递归过程中的逐次减少,必然会到达 n=0 或 n=1 的时刻。
  • 19. 19函数的参数传递机制 ——传递参数值在函数被调用时才分配形参的存储单元。 实参可以是常量、变量或表达式。 实参类型必须与形参相符。 传递时是传递参数值,即单向传递。函数的声明与使用
  • 20. 20函数的参数传递机制 ——参数值传递举例XN被调函数:主调函数:3 2.5AD = power(A,3) 2.53double power(double X, int N)函数的声明与使用
  • 21. 21函数的参数传递 ——用引用做形参引用(&)是标识符的别名,例如: int i,j; int &ri=i; //建立一个int型的引用ri,并将其 //初始化为变量i的一个别名 j=10; ri=j;//相当于 i=j; 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。 一旦一个引用被初始化后,就不能改为指向其它对象。 引用可以作为形参 void swap(int& a, int& b) {...}函数的声明与使用
  • 22. 函数返回当返回值为引用类型 例如: int &f2(int a[ ], int n) { int k=0; for(int i=1;ia[k]) k=i; return a[k]; //表达式必须是一个左值,并且不能是本函数中的局部变量。 } 注:函数的返回值是该左值的一个引用,返回为引用的函数调用表达式既可作为右值、也可作为左值。 函数的声明与使用
  • 23. 函数作用域全局作用域(跨文件作用域) 1.在整个程序的所有文件中都有效,即能被任何程序文件所调用,可用extern修饰 2.当函数<有效范围>缺省时,默认为extern,即默认为全局函数 文件作用域 1.只允许同一程序文件中的函数调用, 2.函定义前须加上 static 修饰。 函数及变量的作用域
  • 24. 变量的作用域跨文件作用域 文件作用域 块作用域 —— 变量的生存期 静态(初值0) 自动 动态函数及变量的作用域
  • 25. 变量的作用域 全局变量 定义位置:函数外 作用域: 跨文件(未加 static 修饰) 文 件(加 static 修饰) 生存期:静态 作用:记录应用系统的全局信息,是函数之间交换数据信息的媒介。
  • 26. 变量的作用域1.extern 说明: 要访问另一个文件中定义的跨文件作用域的全局变量,必须进行extern 说明,如: extern int var; 2.在函数外定义变量,不带任何存储属性,此变量具有全局作用域。 如:#include int var1=10; //作用域是全局 …..
  • 27. 变量的作用域 局部变量 定义位置:函数内的某一个块 (复合语句)中 作用域:块 生存期: 静态(加 static 修饰) 自动(加 auto 修饰, 可省略) 作用:作为所在块的临时变量。
  • 28. 变量的作用域 寄存器变量 一种用 register 修饰的局部变量 这种变量中的数据是存储于寄存器中的,在使用过程中不用访问内存,从而大大提高了变量的存取速度; 但编译系统在判断不可能时,仍会将之处理为一般的自动变量。28
  • 29. 变量的作用域..— for语句中定义的变量的作用域 请判断下面语句序列的正误: for(int i=0;i<=10;i++) cout<
  • 30. 注意事项:在函数之外定义和声明符号常量 1.可以带存储属性extern、static,则同样为全局常量或文件域常量。 2.若省略了存储属性,则默认为文件域常量。 3.例如: #include int aa=5; //全局 extern const int bb=6; //全局 static int cc=7; //文件域 const int dd=9; //文件域 …..
  • 31. 注意事项:全局变量没有初始化,默认为0。 在函数体内,若省略存储属性,则默认为auto。 auto、register没有初始化,则系统不会给它初始化,初值不确定。 static没有初始化,默认值是0,在“堆存储区”分配存储空间。
  • 32. 在外层和里层作用域定义同名的对象 例子: #include int x=10; Void main() { int y=20 cout<
  • 33. 33重载函数的声明C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。 例:形参类型不同int add(int x, int y); float add(float x, float y);形参个数不同int add(int x, int y); int add(int x, int y, int z); 函 数 重 载
  • 34. 34注意事项不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:int add(int x,int y); int add(int a,int b); 编译器不以形参名来区分int add(int x,int y); void add(int x,int y); 编译器不以返回值来区分int add(int x,int y) { return x+y; }float add(float x,float y) { return x-y; } 函 数 重 载重载函数的形参必须不同: 个数不同或类型不同。 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
  • 35. 35函数模板函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计。 声明方法: template 函数声明 函 数 模 板
  • 36. 函数模板—— 函数模版的说明格式: template <模版形参表> 函数定义 例如: template T Max(T x, T y) { return (x > y) ? x : y; };
  • 37. 函数模板..函数和函数模板举例: void addTo(int a[],int b[],int size){ for(int i=0;i void addTo(T a[],T b[],int size){ for(int i=0;i
  • 38. 函数模板—— 函数模板的实例化 在调用模板函数时,编译系统会自动生成所需的函数定义,这一过程称为函数模板的实例化。 例如:a、b两个整数调用模版函数max,系统自动生成如下实例函数: int max(int x,int y) { return (x>y?x:y); } 也可以通过max(a,b)将使max模版函数生成类型参数T为jint的实例函数。
  • 39. 39求绝对值函数的模板#include using namespace std; template T abs(T x) { return x<0?-x:x; } void main() { int n=-5; double d=-5.5; cout<
  • 40. 40求绝对值函数的模板分析编译器从调用abs()时实参的类型,推导出函数模板的类型参数。例如,对于调用表达式abs(n),由于实参n为int型,所以推导出模板中类型参数T为int。 当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数: int abs(int x) { return x<0?-x:x; } 函 数 模 板
  • 41. 指向函数的指针函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) ( 函 数 指 针函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) (函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) (函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) (函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) (函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如: int (*) (函数名同数组名一样,是指针常量。 指向函数执行代码对应存储空间的开始位置,即首地址。 格式 <函数类型> (*)(<参数表>) 如:void (*)(int); int (*) (int[ ],int);
  • 42. 指向函数的指针例: void f1(int x); void (*p1) (int)=f1; p1(10)与f1(10)完全相同。 用typedef定义函数类型 Typedef void VoidInt(int); VoidInt *p2 =f1; 在函数定义的参数表中,参数类型也可为函数类型。 例如:教材p206程序。 函 数 指 针
  • 43. The End第七章43