C++%20Lesson%206

Views:
 
Category: Entertainment
     
 

Presentation Description

No description available.

Comments

Presentation Transcript

好用的工具——函数 : 

好用的工具——函数 函数的声明、定义以及调用 函数的类型和返回值 形式参数与实际参数,参数值的传递 函数重载——多功能“开瓶器” 递归函数——汉诺塔游戏 带有缺省参数值的函数——自动的“工具” 内联函数 变量的作用域、生存周期和存储类别

Slide 2: 

主函数写得很简单,它的作用就是调用各个函数,程序各部分的功能全部都是由各函数实现的。主函数相当于总调度,调动各函数依次实现各项功能。 库函数:开发商和软件开发人员将一些常用的功能模块编写成函数,放在函数库中供公共选用。 一个程序文件中可以包含若干个函数,但只能有一个main函数。 程序总是从main函数开始执行的,主函数调用其他函数,其他函数也可以互相调用。 函数(function): 一个函数就是一个功能。

Slide 3: 

例 在主函数中调用其他函数。 void printstar(void) { cout<<″****************************** ″<<endl; } void print_message(void) { cout<<″ Welcome to C++!″<<endl; } int main(void) { printstar( ); print_message( ); printstar( ); return 0; }

定义函数的一般形式 : 

定义函数的一般形式 函数声明的语法形式 函数返回值 函数名(形式参数表) { 复合语句 } C++要求在定义函数时必须指定函数的类型! 给你的函数起个好名字! 形式参数表 <type1> name_1, ... , <type n> name_n 函数的返回值 由 return 语句给出 无返回值的函数(void类型),不必写return语句

Slide 5: 

例:无参函数 void printstar(void) { cout<<″********************** ″<<endl; } 例如:有参函数 int max(int x,int y) {   int z;   z=x>y?x:y;    return (z); }

Slide 6: 

例: 调用函数时的数据传递。 int max(int x,int y) { int z; z=x>y?x:y; return(z); } int main( ) { int a,b,c; cin>>a>>b; c = max(a,b); cout<<″max=″<<c<<endl; return 0; }

Slide 7: 

有关形参与实参的说明: (1) 在未出现函数调用时,形参并不占内存中的存储单元,称形式参数或虚拟参数.发生函数调用时,函数中的形参才被分配内存单元,以便接收从实参传来的数据。在调用结束后,形参所占的内存单元也被释放。 (2) 实参可以是常量、变量或表达式,如: max(3, a+b); 但要求a和b有确定的值。

Slide 8: 

(3) 在定义函数时,必须在函数首部指定形参的类型. (4) 实参与形参的类型应相同或赋值兼容。 例如:实参a的值为3.5,而形参x为整型,则将3.5转换成整数3,然后送到形参b。 字符型与整型可以互相通用。

Slide 9: 

(5) 实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实参。在调用函数时,编译系统临时给形参分配存储单元。 请注意: 实参单元与形参单元是不同的单元。

函数的返回值 : 

函数的返回值是通过函数中的return语句获得的。 return语句将被调用函数中的一个确定值带回主调函数中去。 函数的返回值 int max(int x,int y) { int z; z=x>y?x:y; return(z); } int main( ) { int a,b,c; cin>>a>>b; c = max(a,b); cout<<″max=″<<c<<endl; return 0; } (4) 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准,即函数类型决定返回值的类型 (3) 函数返回值的类型:应是确定的类型,必须在定义函数时指定函数值的类型

函数调用的方式 : 

按函数在语句中的作用来分,可以有以下3种函数调用方式: 1. 函数语句   如 printstar( ); 2. 函数表达式   如 c = 2*max(a,b); 3. 函数参数-函数调用作为一个函数的实参   如 m = max(a,max(b,c)); 函数调用的方式

Slide 12: 

一个函数调用另一个函数需要具备的条件: (1) 首先被调用的函数必须是已经存在的函数。 (2) 如果使用库函数,应该在文件开头用 #include命令将有关头文件“包含”到本文件中来 (3) 如果使用用户自己定义的函数,而该函数与调用它的函数(即主调函数)在同一个程序单位中,且位置在主调函数之后,则必须在调用此函数之前对被调用的函数作声明。

Slide 13: 

函数声明(declare): 在函数尚在未定义的情况下,事先将该函数的有关信息通知编译系统,以便使编译能正常进行。 void main( ) { float add(float x,float y) ; float a,b,c; cout<<″please enter a,b:″; cin>>a>>b; c = add(a,b); cout<<″sum=″<<c<<endl; } float add(float x,float y) { float z; z=x+y; return (z); } 调用前先声明函数原型: 函数返回值 函数名 (形参表);

Slide 14: 

注意:对函数的定义和声明不是同一件事情。 定义是指对函数功能的确立,包括指定函数名、函数类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。 声明的作用则是把函数的名字、函数类型以及形参的个数、类型和顺序(注意,不包括函数体)通知编译系统,以便在对包含函数调用的语句进行编译时,据此对其进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。

Slide 15: 

函数原型(function prototype) 在函数声明中也可以不写形参名,而只写形参的类型   float add(float,float);  这种函数声明称为函数原型(function prototype)。  作用: 根据函数原型在程序编译阶段对调用函数的合法性进行全面检查。如果发现与函数原型不匹配的函数调用就报告编译出错。它属于语法错误。用户根据屏幕显示的出错信息很容易发现和纠正错误。 应当保证函数原型与函数首部写法上的一致,即函数类型、函数名、参数个数、参数类型和参数顺序必须相同。在函数调用时函数名、实参类型和实参个数应与函数原型一致。

Slide 16: 

程序员习惯用法: 一般都把main函数写在最前面,用函数原型来声明函数。 (2) 函数声明的位置可以在调用函数所在的函数中,也可以在函数之外。

Slide 17: 

函数调用的执行过程 调用函数时需要一定的时间和空间的开销:

例:用函数实现交换变量 : 

例:用函数实现交换变量 #include <iostream> using namespace std; void swap(int x,int y); //交换函数声明 int main() { int a=10,b=55; swap(a,b); //调用交换函数 cout <<"a=" <<a <<endl; cout <<"b=" <<b <<endl; return 0; } void swap(int x,int y) //交换函数定义 { int temp; temp=x; x=y; y=temp; } 运行结果 a=10 b=55 为什么会这样?!

问题的所在 : 

问题的所在 变量a@swap 变量b@swap 变量temp@swap 数据1 数据2 数据2 变量a@main 变量b@main 数据1 数据2 数据1 数据2 函数调用结束后,swap函数内的变量 都消失了,主函数的变量没有变化。

给变量和参数起个“绰号”——引用 : 

给变量和参数起个“绰号”——引用 所谓引用(Reference)就是给变量起一个“别名”。对变量引用的操作相当于对变量本身的操作,例如: int a; int &b=a; int b=5; 相当于 int a; int a=5;

用引用传递参数 : 

用引用传递参数 变量a@main 变量b@main 变量temp@swap 变量a@main 变量b@main 使用了引用之后,函数可以导致 调用处的变量发生改变。 数据1 数据2 数据1 数据2 数据2

用函数交换变量——编码 : 

用函数交换变量——编码 #include <iostream> using namespace std; void swap(int &x,int &y); //交换函数,用引用传递参数 int main() { int a=10,b=55; swap(a,b); //调用交换函数 cout <<"a=" <<a <<endl; cout <<"b=" <<b <<endl; return 0; } void swap(int &x,int &y) { int temp; temp=x; x=y; y=temp; } 运行结果 a=55 b=10

多功能“开瓶器”——函数重载 : 

多功能“开瓶器”——函数重载 C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。 例:

Slide 24: 

注意事项 重载函数的形参必须不同: 个数不同或类型不同。 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:

Slide 25: 

例: 求3个数中最大的数(分别考虑整数、双精度数、长整数的情况)。 void main( ) { int max(int a,int b,int c); double max(double a,double b,double c); long max(long a,long b,long c); int i1,i2,i3,i; cin>>i1>>i2>>i3; //输入3个整数 i = max(i1,i2,i3); //求3个整数中的最大者 cout<<″i_max=″<<i<<endl; double d1,d2,d3,d; cin>>d1>>d2>>d3; //输入3个双精度数 d = max(d1,d2,d3); //求3个双精度数中的最大者 cout<<″d_max=″<<d<<endl; long g1,g2,g3,g; cin>>g1>>g2>>g3; //输入3个长整数

Slide 26: 

g=max(g1,g2,g3); //求3个长整数中的最大者 cout<<″g_max=″<<g<<endl; } int max(int a,int b,int c) //定义求3个整数中的最大者的函数 { if(b>a) a=b; if(c>a) a=c; return a; } double max(double a,double b,double c) //定义求3个双精度数中的最大者 { if(b>a) a=b; if(c>a) a=c; return a; } long max(long a,long b,long c) //定义求3个长整数中的最大者的函数 { if(b>a) a=b; if(c>a) a=c; return a; }

老和尚和小和尚的故事 : 

老和尚和小和尚的故事 从前有座山,山上有座庙,庙里住着老和尚和小和尚,老和尚给小和尚讲故事:“从前有座山,山上有座庙,庙里住着老和尚和小和尚,老和尚给小和尚讲故事:‘从前有座山,山上有座庙,庙里住着老和尚和小和尚,老和尚给小和尚讲故事:……’从前…………”

函数的递归调用 : 

函数的递归调用 函数直接或间接地调用自身,称为递归调用。 递归过程的两个阶段:  递推: 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 未知 已知

Slide 29: 

例:用递归方法求n!。 可用下面的递归公式表示: n!= 1 (n=0,1) n·(n-1)! (n>1)

Slide 30: 

long fac(int n) //递归函数 { long f; if(n<0) { cout<<″n<0,data error!″<<endl; f = -1; } else if (n==0||n==1) f = 1; else f = fac(n-1)*n; return f; }

Slide 31: 

求Fibonacci数列前40个数。这个数列有如下特点:第1、2个数为1、1。从第3个数开始,每个数是其前面两个数之和。即 F1=1 (n=1) F2=1 (n=2) Fn=Fn-1+Fn-2 (n≥3) int  F (int n) {    if(n<3) { return (1); } else { return (F (n-1)+F (n-2)); } }

Slide 32: 

汉诺塔游戏!

有默认参数的函数 : 

有默认参数的函数 函数在声明时可以预先给出默认的形参值 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 }

Slide 34: 

默认形参值 必须从右向左 顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。 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); //错误

Slide 35: 

调用出现在函数体实现之前时,默认形参值必须在函数原形中给出; 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( ); } 当调用出现在函数体实现之后时,默认形参值需在函数实现时给出。

Slide 36: 

在相同的作用域内,默认形参值的说明应保持唯一,但如果在不同的作用域内,允许说明不同的默认形参。 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) }

Slide 37: 

使用带有默认参数的函数时要注意: 一个函数不能既作为重载函数,又作为有默认参数的函数。 因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,出现二义性,系统无法执行。 int max(int a,int b,int c=0) { if(b>a) a=b; if(c>a) a=c; return a; } int max(int a,int b) { if(a>b) return a; else return b; } void main( ) { int a=8,b=-12,c=27; max(a,b); }

内联函数 : 

内联函数 声明时使用关键字 inline。 编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销。 注意: 内联函数体内不能有循环语句和switch语句。 内联函数的声明必须出现在内联函数第一次被调用之前。 对内联函数不能进行异常接口声明。

Slide 39: 

例4 函数指定为内置函数。 inline int max(int,int, int); //声明函数,注意左端有inline int main( ) { int i=10,j=20,k=30,m; m = max(i,j,k); cout<<″max=″<<m<<endl; return 0; } inline int max(int a,int b,int c) //定义max为内置函数 { if(b>a) a=b; //求a,b,c中的最大者 if(c>a) a=c; return a; }

Slide 40: 

说明: 由于在定义函数时指定它为内置函数,因此编译系统在遇到函数调用“max(i,j,k)”时,就用max函数体的代码代替“max(i,j,k)”,同时将实参代替形参。 程序第6行 “m=max(i,j,k);”就被置换成 if (j>i) i=j; if(k>i) i=k; m=i;

Slide 41: 

注意: 可以在声明函数和定义函数时同时写inline,也可以只在其中一处声明inline,效果相同,都能按内置函数处理。 使用内置函数可以节省运行时间,但却增加了目标程序的长度。因此一般只将规模很小(一般为5个语句以下)而使用频繁的函数(如定时采集数据的函数)声明为内置函数。

authorStream Live Help