1 / 53

C++ 语言程序设计 第五章 C++ 函数 (第一讲)

C++ 语言程序设计 第五章 C++ 函数 (第一讲). 学习目标. . 掌握函数定义和函数调用的方法,会使用函数原形和头文件; 了解参数传递的原理,熟练掌握通过传值方式向函数传递数据的方法,掌握使用数组参数和可选参数; 掌握函数重载; 了解函数和变量作用域;. 第一讲主要内容. C++ 函数的概念 函数的定义 函数的调用 函数原形与头文件 函数调用中的参数传递 内联( inline )函数 函数重载与名字混成 函数和变量的作用域 函数模板. . x. 0. 0. -1. y. 1. 1. -2. 4. 2. x 2.

alaula
Télécharger la présentation

C++ 语言程序设计 第五章 C++ 函数 (第一讲)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C++语言程序设计第五章 C++函数(第一讲)

  2. 学习目标  • 掌握函数定义和函数调用的方法,会使用函数原形和头文件; • 了解参数传递的原理,熟练掌握通过传值方式向函数传递数据的方法,掌握使用数组参数和可选参数; • 掌握函数重载; • 了解函数和变量作用域;

  3. 第一讲主要内容 C++函数的概念 函数的定义 函数的调用 函数原形与头文件 函数调用中的参数传递 内联(inline)函数 函数重载与名字混成 函数和变量的作用域 函数模板 

  4. x 0 0 -1 y 1 1 -2 4 2 x2   C++函数的概念.. • —— 函数的概念源于数学,是一个集合到另一个集合的映射。例如对于数学中的函数 y=f(x)=x2:

  5. C++函数的概念.. • 前例用C++函数表示就是:int y(int x){ return x*x;} 对应因变量y 对应自变量x 对应映射规则X2

  6. (5,9) (7,5) (5,5) … (7,8) (9,7) …  5  7  C++函数的概念.. { • —— 再如,对于数学中的函数 • m (m<=n) • min=f(m,n)= • n (m>n)

  7. C++函数的概念.. 此例用C++函数表示就是: int min(int m,int n){ if(m<=n) return m; else return n;}

  8. 函数的定义.. • — 定义格式: • 类型修饰符函数名(形式参数表)函数体 一个变量表,用来接收调用程序传来的数据。 形式参数简称形参。 规定函数值(函数返回值)的类型,如 int、double 等。 用{}括起来的语句序列,形同一个复合语句。

  9. 函数的定义.. —— 一般情况下,函数体中应以return 表达式;结束函数的运行。 —— 无参函数:形式参数表为空(或为 void):double PI(void){ return 3.1415926;} 

  10. 函数的定义.. • —— 无返回值的函数:返回值类型规定为 void 的函数。例如: • void Hi(void){ cout<<"Hi!"<<endl; return;} 可以不要 无返回值的函数通过副作用体现其功能

  11. 函数的定义 —— 主函数(main 函数)可以声明为有参函数,也可以声明为无参函数;可以声明为有返回值函数,也可以声明为无返回值函数。

  12. 函数的调用.. —— 调用格式:函数名(实在参数表) 实在参数简称实参,每一个实参就是一个表达式; 实参的个数必须与形参的个数相同; 实参表达式的类型应当与对应形参变量的类型相同; 调用时,实参表达式的值被传送给函数,为对应的形参变量所接收。 

  13. 函数的调用.. —— 作为表达式的函数调用其本身就是一个表达式,或者是某个表达式中的一个子表达式,它的值将参与整个表达式的求值过程。例如:s=min(5,7)*10; 无返回值函数不能作为表达式加以调用

  14. 函数的调用.. —— 作为语句的函数调用 在一个语句中单独使用函数调用,通过函数的副作用发挥其作用。例如:Hi(); //显示 Hi!min(5,7);//无意义

  15. 函数的调用..  • 若调用的是有返回值的函数,其返回值被舍弃不用; • 函数的作用通过其副作用体现 • 对于无副作用的函数,作为语句调用是没有意义的。

  16. 函数的调用.. —— 递归调用 函数直接或间接地调用自身。递归调用是实现递归算法的手段。

  17. 函数的调用.. —— 递归算法及递归调用举例: long fact(long n) { if(n<=1L) return 1L; return n*fact(n-1L); }

  18. 函数的调用.. • —— 递归算法都必须满足的的三个条件: • 1.有明确的结束递归的条件:n=0或n=1,此条件下可以直接得出结果:1 ; • 2.要解决的问题可以转化为相对简单的同类型的问题:n!可转化为 n·(n-1)!,而 (n-1)! 就是比 n! 稍简单的同类型的问题; • 3.随着问题的逐次转换,最终能达到结束递归的条件:算法中的参数 n 在递归过程中的逐次减少,必然会到达 n=0 或 n=1 的时刻。

  19. 函数原形与头文件.. ——函数原形 格式:类型修饰符函数名(形式参数表) 作用:提供完成函数调用所必需的接口 信息 使用位置:函数调用之前(程序首部) 什么情况下必须使用?函数的定义出现在函数调用之后,或在别的文件中。 

  20. 函数原形与头文件.. —— 头文件 是扩展名为 .h 的含有函数原形 (或 其他声明)的纯文本文件; 通过使用#include命令可把头文件中的内容包含(插入)到程序文件中; 头文件有利于维护函数原形的一致性; 

  21. 函数原形与头文件.. 通过使用头文件可使函数的实现(定义)和函数的使用(调用)分离,从而提高函数的重用性 通过使用头文件可把系统分解成多个程序文件,以便于多人分工合作 使用C/C++标准函数必须包含相应的头文件,如: #include<math.h> 

  22. 函数调用中的参数传递.. —— C++参数传递的基本方式——“传值” double DOUBLE(double n){ n*=2; //形参变量n的值被改变return n;}void main(){ double m=7.0; cout<<endl<<m; cout<<endl<<DOUBLE(m); cout<<endl<<m;} 运行

  23. 函数调用中的参数传递.. —— 数组参数 可以把整个数组作为参数传递给函数。 在说明一个一维数组参数时,可以不限定数组元素的个数;在说明一个二维数组参数时,可以不限定数组的行数(数组参数的第一维可不限定)。 在调用具有数组参数的函数时,须以单独的数组名作为实在参数。 

  24. 函数调用中的参数传递.. • 例5.5:设计函数sum,它计算并返回作为参数的数组中所有元素的合计值: • int sum(int array[],int size);

  25. 函数调用中的参数传递.. (例5.5) 运行 int sum(int array[],int size) { int s=0; for(int i=0;i<size;i++) s+=array[i]; return s; } void main() { int v1[]={1,2,3,4,5}; cout<<sum(v1,5)<<endl; int v2[]={1,2,3,4,5,6,7,8}; cout<<sum(v2,8)<<endl; }

  26. 函数调用中的参数传递.. • 例5.6:设计函数sumAll,计算 5 列二维数组 data 的每一行元素的合计,并把结果存入一维数组 result 的对应元素中:void sumAll(int data[][5], int result[], int rows);

  27. 函数调用中的参数传递.. (例5.6) void sumAll(int data[][5], int result[], int rows) { for(int i=0;i<rows;i++){ result[i]=0; for(int j=0;j<5;j++) result[i]+=data[i][j]; } } 

  28. 函数调用中的参数传递.. (例5.6续): 运行 void main() { int v[][5]={{1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7}}; int s[3]; sumAll(v,s,3); for(int i=0;i<3;i++) cout<<s[i]<<‘ ’; }

  29. 函数调用中的参数传递.. 注意:仅用行下标引用一个二维数组时,所引用的是对应于该行的那个一维数组。用此方法,可把二维数组的某一行作为一维数组使用。如例5.7: void sumAll(int data[][5], int result[], int rows) { for(int i=0;i<rows;i++) result[i]=sum(data[i],5); }

  30. 函数调用中的参数传递.. ——可选参数 通过设定默认值,可把一个形参说明为可选参数,说明格式是:类型修饰符变量名=默认值例如:int f(int a,char b,char c='Z', char *s=”READY”);

  31. 函数调用中的参数传递.. 只能把形参表中最后的若干形数说明为可选参数; 在调用具有可选参数的函数时,可以不给出对应于可选参数的实参,编译系统会自动以设定的默认值作为实参; 被省略的实参必须是最后若干个可选参数所对应的实参; 

  32. 函数调用中的参数传递.. 例如对于 int f(int a,char b,char c='Z',char *s=”READY”); f(3,'a','b')  f(3,'a','b',”READY”) f(3,'a')  f(3,'a','Z', ”READY”) f(3,'a',”NOT_READY”)  ?

  33. 函数调用中的参数传递.. • 可选参数的说明只与函数调用的代码生成有关,而对函数定义及其代码生成毫无影响。因此:可选参数应该在函数原形中进行说明

  34. 函数调用中的参数传递.. 例5.8:设计函数area_of_fan,它根据给出的半径和角度计算扇形面积。

  35. 函数调用中的参数传递.. • #define PI 3.1415926 • double area_of_fan(double radius, double angle=360.0); • void main(){ • cout<<endl<<area_of_fan(5.0,90.0); • cout<<endl<<area_of_fan(5.0); • cout<<endl<<area_of_fan(5.0,360.0); • } • double area_of_fan(double radius, double angle){ • return PI*radius*radius*angle/360.0; • } 运行

  36. 内联(inline)函数..  • 在一般函数定义前面加上保留字inline,该函数即被说明为内联函数。例如:inline int add2(int n){ return n+2;} • C++有可能直接用函数体代码来替代对函数的调用,这一过程称为函数体的内联展开。

  37. 内联(inline)函数  • 在函数定义前加inline,只是向C++编译系统提出内联展开的请求,编译系统有可能不理睬这种请求。 • 内联函数的说明属于参考性说明,因此应该放置在头文件中。 • 内联函数的作用:提高运行效率。 • 内联函数适合于简单的、使用频繁的小函数。

  38. 函数重载与名字混成..  • —— 关于函数重载 • C++允许定义同名的函数,称为函数重载。 • 重载的函数必须在参数的数量上或类型上与其他同名函数有所不同。 • 函数重载的作用:使若干密切相关的函数有一个统一的调用接口。

  39. 函数重载与名字混成.. —— 关于名字混成(name mangling) 编译系统为区分同名函数而用来生成内部函数名的一种特殊方法; 内部函数名不但包含了外部函数名本身,还包含了函数的参数信息。 

  40. 函数重载与名字混成.. • 例如,对于重载函数int fun(double n);double fun(double n,int m);void fun(int m,char n[]); C++Builder中的内部名:@fun$qd@fun$qdi@fun$qipc Visual C++中的内部名: ?fun@@YAHN@Z?fun@@YANNH@Z?fun@@YAXHQAD@Z

  41. 函数重载与名字混成.. — 用 extern "C" 可阻止编译系统进行名字混成: extern "C" void Cfunc(int); extern "C"{ void Cfunc1(int); void Cfunc2(int); void Cfunc3(int);}; extern "C"{ #include"locallib.h"};

  42. 函数重载与名字混成.. ——要注意可选参数对函数重载的影响。假定已经定义了: int f(int k,int m=0, double d=0.0); 合法的调用:f(3,5,6.7)、f(3,5)、f(3)不能重载: int f(int); int f(int,int); int f(int,int,double); int f(int,double=0.0);等

  43. 函数和变量的作用域..  • —— 函数的作用域 • 全局作用域(跨文件作用域):同一应用系统的任何程序文件中的任何函数都可以调用。 • 文件作用域:只允许同一程序文件中的函数调用,函数定义前须加上 static 修饰。

  44. 函数和变量的作用域.. —— 变量的作用域 跨文件作用域 文件作用域 块作用域  • —— 变量的生存期 • 静态(初值0) • 自动 • 动态

  45. 函数和变量的作用域.. —— 全局变量 定义位置:函数外 作用域: 跨文件(未加 static 修饰) 文 件(加 static 修饰) 生存期:静态 作用:记录应用系统的全局信息,是函数之间交换数据信息的媒介。 

  46. 函数和变量的作用域.. extern 说明:要访问另一个文件中定义的跨文件作用域的全局变量,必须进行extern 说明,如:extern int var;

  47. 函数和变量的作用域.. —— 局部变量 定义位置:函数内的某一个块 (复合语句)中 作用域:块 生存期: 静态(加 static 修饰) 自动(加 auto 修饰, 可省略) 作用:作为所在块的临时变量。 

  48. 函数和变量的作用域.. —— 寄存器变量 一种用 register 修饰的局部变量 这种变量中的数据是存储于寄存器中的,在使用过程中不用访问内存,从而大大提高了变量的存取速度; 但编译系统在判断不可能时,仍会将之处理为一般的自动变量。 48

  49. 函数和变量的作用域..  • — for语句中定义的变量的作用域 • 请判断下面语句序列的正误:for(int i=0;i<=10;i++) cout<<i<<','; cout<<i; • 在旧标准中这是正确的,即 for 语句中定义的 i 的作用域在 for 语句所在的块中。 • 在新标准中这是错误的,即 for 语句中定义的 i 的作用域只局限于该 for 语句。

  50. 函数和变量的作用域.. —— 静态自动变量应用实例(例5.9) #define RESET true unsigned counter(bool reset=!RESET ){ static unsigned cnt=0; if(reset) return cnt=0; return ++cnt; } 静态自动变量可用于在同一函数的不同调用之间交换数据信息

More Related