Download presentation
Presentation is loading. Please wait.
1
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院
2
函数的定义和声明 定义函数的一般格式为: 返回类型 函数名 (数据类型1 参数1, 数据类型2 参数2,... ) { 函数体; }
定义函数的一般格式为: 返回类型 函数名 (数据类型1 参数1, 数据类型2 参数2,... ) { 函数体; } 形参表 返回类型:任意数据类型 函数名:符合C++标识符的一般命名规则 形参列表:需指定参数类型和参数名 函数体:语句序列
3
例子 #include <iostream.h> int max(int x,int y) { int z;
函数定义 #include <iostream.h> int max(int x,int y) { int z; z=(x>y)?x:y; return z ; } void main() int a,b; cin>>a>>b; cout<<max(a,b)<<endl; 函数体:函数所完成的具体操作 函数调用
4
函数原型 函数原型的一般形式: 返回值类型 函数名(参数列表);
如果函数定义在先,调用在后,调用前可以不必声明;如果函数定义在后,调用在先,调用前必须声明。 加上参数名会使函数的 功能和参数更清晰。 int max(int, int);//或int max(int a,int b); void main(){ int value=max(5,6); } int max(int x, int y){......}; 2019/5/18
5
函数调用 函数调用的一般形式为: 各实际参数表中的实际参数应与形参表中的形参一一对应,即个数相等且对应参数的数据类型相同。
函数调用是一个表达式,函数名连同括号是函数调用运算符。表达式的值就是被调函数的返回值,它的类型就是函数定义中指定的函数返回值的类型,即函数的类型。 如果函数的返回值为void,说明该函数没有返回值。 例如:cout<<max(a,b)<<endl; 函数名 (参数1, 参数2,... ); 实际参数表
6
C++程序的内存空间 当一个程序准备运行时,操作系统会为程序分配一块内存空间,C++程序的内存通常被分为四个区:
全局数据区:存放全局变量、静态变量、字符串常量、常变量 代码区:存放代码 栈区:存放为运行函数而分配的函数参数、局部变量、返回地址等 堆区:用于动态内存分配
7
函数参数的按值传递 函数参数传递过程的实质是将实参值通过栈空间一一传送给形参的过程。 2019/5/18
8
例子:函数参数的按值传递 #include<iostream.h> void swap(int a,int b) {
int t; t=a, a=b, b=t; } void main() int x=7,y=11; cout<<"x="<<x<<" y="<<y<<endl; swap(x,y); cout<<"after swap:"; 函数定义 传值调用
9
函数的嵌套调用 在一个函数中调用其它函数叫函数的嵌套。 C++中函数的定义是平行的,除了main函数以外,都可以互相调用。
函数不可以嵌套定义,但可以嵌套调用。比如函数1调用了函数2,函数2再调用函数3,这便形成了函数的嵌套调用。
10
递归调用 在调用一个函数的过程中又直接或间接地调用该函数本身的这一现象,叫做函数的递归调用。 1 (n=0) n!=
n(n-1)! (n>0) 递归可以分为: 直接递归调用:是在调用函数的过程中又调用该函数本身; 间接递归调用:是在调用f1()函数的过程中调用f2()函数,而f2()中又需要调用f1()。
11
内联函数 宏定义带来的问题 最后j的值为是0。问题出在编译器在遇到宏时只是进行简单的宏替换。
#define abs(a) ((a) < 0 ? –(a):(a)) int i = -2, j; j = abs(++i); ==> j = ((++i) < 0 ? –(++i) : (++i)) 最后j的值为是0。问题出在编译器在遇到宏时只是进行简单的宏替换。 2019/5/18
12
用inline定义一个内联函数 使用宏的好处是没有类似于普通函数调用时的系统开销,并且宏定义的参数可以适宜大多数类型的数据。但其缺点是有时会产生不可预料的副作用。 C++中的内联函数既具有宏定义的优点,又克服了宏定义的缺点。 在函数名前加上“inline”,即为内联函数。 inline void func(int a, int b); 因为是在编译时在调用func的地方用函数体进行了替换,所以程序执行时会减少调用开销。 2019/5/18
13
内联函数举例举例 注意事项: inline long abs(long value) {
return (num < 0 ? –num : num); } 注意事项: 并非所有函数都需要定义为内联函数,一般只会将那些频繁被调用的,并且函数体较小的(只有几条语句)函数定义为内联函数。 内联函数内不允许有循环语句和switch语句,否则按照普通函数来处理。 2019/5/18
14
函数重载 两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器会根据实参的类型及个数的最佳匹配来自动确定调用哪一个函数。
void main(){ int a , b ,c; float f1, f2; add(a, b); add(f1, f2); add(a, b, c); } //形参列表不同 int add(int x, int y){…..}; float add(float x, float y){…..}; int add(int x, int y, int z){…..}; 2019/5/18
15
几点注意 不能以形参名字或函数返回类型的不同来区分函数。 //错误!编译器不以形参名来区分函数
int add(int x, int y){ return x+y;} int add(int a, int b){ return a+b;} //错误!编译器不以返回值来区分函数 float add(int x, int y){ return (float)(a+b);} 2019/5/18
16
不要将不同功能的函数定义为重载函数,以免出现混淆。
int add(int x, int y){ return x+y;} float add(float x, float y){ return x-y;} 2019/5/18
17
带默认形参值的函数 在定义函数时预先声明默认的形参值。调用时如果给出实参,则用实参初始化形参;否则采用预先声明的默认形参值。例如:
int add(int x=5, int y=6){ return x+y;} void main( ){ int ret; ret=add(10, 20); ret=add(10); ret=add(); } 2019/5/18
18
默认形参值必须按照从右向左的顺序声明。在有默认值的形参右边,不能出现无默认值的形参。(请思考:为什么??)
int add(int x=5, int y=6,int z=7){…}//正确 int add(int x=5, int y=6,int z){…}//不正确 int add(int x=5, int y,int z=7){ …}//不正确 2019/5/18
19
默认形参值可以在函数原型中给出,例如: int add(int x=5, int y=6); void main( ) {
int ret = add(); } int add(int x, int y){ return x+y;} 2019/5/18
20
在相同的作用域内,默认形参值的说明应保持唯一;但在不同的作用域内,允许说明不同的默认形参值。
int add(int x=5, int y=6); void main( ){ int add(int x=7,int y=8); int ret = add(); //实现7+8 } void func( ){ add( );}//实现5+6 int add(int x, int y){ return x+y;} 2019/5/18
21
请分析以下情况是否正确 int add(int x, int y){ return x+y;}
int add(int x, int y, int z=2){ return x+y+z;} void main( ){ int ret; ret=add(10,20); } 这种调用在编译时会出错! 2019/5/18
Similar presentations