?教学目的与要求:
了解内联函数的声明及作用 。
掌握函数的定义与调用及带默认参数的函数 。
教学内容提要:
1,函数的定义与调用;
2,内联函数;
3,带默认参数的函数;
教学重点:带默认参数的函数 。
教学难点:带默认参数的函数 。
教学进度,P26~ P31
教学过程:
第 4 讲 函数函数 是一个能完成某一独立功能的子程序,也就是程序模块。每个
C++程序至少包含一个函数,即 main函数(主函数) 。在面向过程的程序设计中,一个较为复杂的程序一般通过模块化,分解成主模块与若干子模块的组合,即一个主函数与若干子函数。程序是以函数为单位,由一个或多个函数组成的。
在面向对象的程序设计中,一个 C++程序是由类的实例(对象)构成。
函数主要用于定义对象的操作接口。
本章介绍有关函数的一些基本知识,如:函数的定义及调用等。这些知识虽然大部分是建立在面向过程的程序设计方法的基础上,但它们也是我们学习面向对象程序设计的基础。
在面向过程的程序设计中,一个 C++程序由一个或多个函数组成。当程序开始运行时,系统自动调用主函数。主函数可以调用子函数,子函数还可以调用其他子函数。
调用其他函数的函数称为主调函数,被其他函数调用的函数称为被调函数。
【 4.1 函数的定义及调用 】
声明函数,就是告诉编译器函数的名称、类型和形式参数。
☆ 在 C++程序中,使用函数前首先需要声明函数,然后定义函数。
在 C++程序中,定义一个函数的格式如下:
类型 函数名(形式参数表)
{
语句序列
}
定义函数,就是告诉编译器函数所做的工作。
☆ 函数不能调用没有声明的函数。
函数的返回值是需要返回给主调函数处理的结果,由 return语句给出。当该函数没有返回值时,函数的类型为 void,可不写 return语句。
该函数的类型,即该函数返回值的类型。
一个标识符,在命名时,
其中主函数的名称应取编译器默认的名称 main。
可以有 0条,1条或多条语句。
当是 0条语句时,该函数称作空函数 。
【 4.1.1 函数的定义 】
形参在该函数被调用时,由主调函数 初始化 。在函数 没有被调用 时,
形参只是一个符号。它 标示着 该函数将可以从主调函数那里获取什么数据。
在 实际调用 时,主调函数将 把实际参数赋给形参 。
每个函数都是一个功能独立的模块,绝对不允许在一个函数体内定义另一个函数。
函数的定义
double rectanglearea(double a,double b)
{
double s;
s=a*b;
return s;
} 说明:用于计算一个长方形的面积。其中 a,b分别对应于长方形的长和宽。
【 4.1.1 函数的定义 】
例 4-1
声明函数,一般采用声明函数原型。
形式如下:
类型 函数名(形式参数表);
函数原型中的 类型、函数名和形参表 必须与定义该函数时 完全一致,但函数原型中可以 不包含 参数名,而 只包含 形参的类型。
例如,double rectanglearea(double a,double b);
double rectanglearea(double,double);
声明函数还有 另外一种方法,即在其他函数调用之前定义函数。
在函数体内声明的函数原型只对拥有这个函数体的函数 有效 。如果其他函数也需要调用它,必须 另外声明函数 。注
【 4.1.3 函数的调用 】
除 主函数 main由系统自动调用外,其他函数都由主函数直接或间接调用的。
必须以分号结尾。
【 4.1.2 函数的声明 】
函数的调用的一般形式如下:
函数名(实际参数表)
如果函数的返回类型为 void,说明该函数 没有返回值 。该函数的调用表达式只能在其后 加分号 用作表达式语句。否则,该函数的调用表达式可作为一个子表达式,用作其他表达式的操作数。
实际参数表中的实际参数又称 实参,它是一个表达式,用来初始化被调用函数的形参,因此,应与该函数定义中的形参表中的形参 一一对应,
即个数相等且对应参数的数据类型相同。
函数调用 是一个表达式,其中的括号是函数调用运算符。 表达式的值就是被调用函数的返回值,类型 是函数定义中指定的函数返回值的类型,
也即 函数的类型 。
函数调用,
计算出每个实参表达式的值使用该值去初始化对应的形参,即用第 1个实参初始化第
1个形参,第 2个实参初始化第 2个形参,…,依次类推。
【 4.1.3 函数的调用 】
意义,计算出其中表达式的值,并将这个值返回给主调函数作为调用子函数的结果值。同时结束该函数的执行,继续执行函数表达式后面的操作。
函数的返回值是通过返回语句 return来实现的。
return语句的一般格式如下:
return 表达式;
情况分类没有 return语句,函数在被调用时,程序执行完函数体的最后一条语句后,自动返回主调函数。
有 return语句,这时的 return语句应表示为,return;
一个函数中允许出现 多个 return语句,分别用于不同条件下的函数返回。
函数的调用
//根据用户输入的长方形的长及宽计算出它的面积
#include<iostream.h>
对于 没有返回值的函数,return语句可有可无。注例 4-2
double rectanglearea(double a,double b);
void main()
{
double length,width;
cout<< ″Please input the length and width of the rectangle:″;
cin>>length>>width;
cout<< ″the area of the rectangle is ″<<rectanglearea(length,width);
cout<<endl;
}
double rectanglearea(double a,double b)
{
double s;
s=a*b;
return s;
}
说明:由两个函数组成,函数 main接受用户的输入后,用输入值作为实参调用函数 rectanglearea,子函数 rectanglearea计算出长方形的面积,并将其值返回给函数 main,由函数 main显示出来。
(续)
在一个函数带有多个参数时,C++语言并没有明确规定调用这个函数时对实参的求值顺序,而是让编译器根据对代码进行优化的需要自行决定对实参的求值顺序。它的不确定性在某些情况下会带来 二义性问题 。
Please input the length and width of the rectangle:
the area of the rectangle is 200
提示用户输入数据,假设用户输入,
20 10
例 4-3 实参求值顺序不同所带来的二义性问题
#include<iostream.h>
int area(int a,int b);
void main( )
{
(续)
改变 调用函数表达式中实参的表示形式,避免有可能带来 二义性 的写法。
说明:调用函数 area时,实参求值顺序有两种可能先计算 a*2,再计算 --a
先计算 --a,再计算 a*2
赋给形参 b的值有可能是 40,也有可能是 38。
int a(20);
int s;
s=area(--a,a*2);
cout<<s<<endl;
}
int area(int a,int b)
{
return (a*b);
}
实参求值顺序不同所带来的二义性问题例 4-3
改写成:避免因实参求值顺序不同所带来的二义性问题
#include<iostream.h>
int area(int a,int b);
void main(void)
{
int a(20);
int s;
--a;
s=area(a,a*2);
cout<<s<<endl;
}
int area(int a,int b)
{
return (a*b);
}
例 4-4
一个 C++程序经过编辑、编译、链接后生成可执行的代码( EXE
件),存储在计算机的 外部存储器 中。
main()
{
statement;
fun1();
statement;
}
fun1()
{
statement;
fun2();
statement;
return;
}
fun2()
{
statement;
return;
}
保存返回地址及当前现场恢复函数 main
的现场,取得返回地址保存返回地址及当前现场恢复函数 fun1
的现场,取得返回地址图 函数调用的执行过程
【 4.1.4 函数调用的执行过程 】
寻找并输出 11~999之间的数 m,它满足 m,m2和 m3均为回文数。
回文:各位数字左右对称的整数。
例如,11满足上述条件
112=121,113=1331。
分析:
–10取余的方法,从最低位开始,
依次取出该数的各位数字。按反序重新构成新的数,比较与原数是否相等,若相等,则原数为回文。
例 4-5
#include <iostream.h>
void main( )
{
bool symm(long n);
long m;
for(m=11; m<1000; m++)
if (symm(m)&&symm(m*m)&&symm(m*m*m))
cout<<"m="<<m<<" m*m="<<m*m<<"
m*m*m="<<m*m*m<<endl;
}
bool symm(long n)
{
long i,m;
i=n ; m=0 ;
while(i)
{
m=m*10+i%10;
i=i/10 ;
}
return ( m==n );
}
运行结果:
m=11 m*m=121 m*m*m=1331
m=101 m*m=10201 m*m*m=1030301
m=111 m*m=12321 m*m*m=1367631
使用内联函数,编译器在编译时 并不生成真正的函数,而是将程序中出现的每一个内联函数调用表达式 直接 用该内联函数的函数体 替换 。
内联函数应该定义在前,调用在后,定义时只需在前面加上关键字 inline。
形式如下:
inline 类型 函数名(形参表)
{
......//函数体
}
例 4-6 内联函数的使用
//计算正方形的面积
#include<iostream.h>
inline double area(double x)
{
return x*x;
}
说明:仅在声明函数原型时加上关键字 inline,并不能达到内联效果。
说明:用来根据用户的输入,计算出一个正方形的面积。内联函数用来计算面积。
【 4.2 内联函数 】
Please input the length of a spuare:
the area of a spuare is,42.25
提示用户输入正方形的边长。
假设输入,6.5
内联函数的使用会增加程序的代码量。注内联函数一般来说仅适用于只有一、两条语句的小函数。
例 4-7
void main( )
{
double x;
cout<< ″Please input the length of a spuare,″;
cin>>x;
x=area(x);
cout<<endl<< ″the area of a spuare is:\ t ″<<x;
cout<<endl;}
内联函数的使用在进行函数调用时,主调函数的实参与被调函数的形参按 从左到右 对应的位置结合,当实参的数目 少于 形参时,如果对应位置形参又 没有设定默认值,就会产生 编译错误 。如果 设定 了默认值,编译器将为那些没有对应实参的形参 取默认值 。
在 声明函数时 为其形参 指定默认值 。默认值的 定义 必须遵守 从右到左的顺序,即:函数的某个形参没有默认值,则它前面的参数就不能有默认值。
例如,double area(double a=2.6,double b=4);
double area(double a,double b=4);
double area(double=2.6,double =4);
double area(double a=2.6,double b);
double area(double =2.6,double b,double=4);
例 4-8 带默认形参值的函数
//计算长方体的体积
#include<iostream.h>
int volume(int length,int width=10,int height=20);
说明:函数省略了形参名。
【 4.3 带默认形参值的函数 】
例 4-8
void main()
{ int l(50),w(40),h(30);
int area;
area=volume(l,w,h);
cout<<endl<< ″the area of cube equal:\ t ″<<area;
cout<<endl<<endl;
area=volume(l,w);
cout<<endl<< ″the area of cube equal:\ t ″<<area;
cout<<endl<<endl;
area=volume(l);
cout<<endl<< ″the area of cube equal:\ t ″<<area;
cout<<endl<<endl;
// area=volume( );
}
int volume(int length,int width,int height)
{cout<< ″The information of the cube is:\ tlength=\ t ″<<length; cout<< ″
\ twidth=\ t ″<<width<< ″\ theight=\ t ″<<height;
return (length*width*height);
}
带默认形参值的函数
The information of the cube is,length=50 width=40 height=30
the area of cube equal,60000
The information of the cube is,length=50 width=40 height=20
the area of cube equal,40000
The information of the cube is,length=50 width=10 height=20
the area of cube equal,10000
被调用函数在 调用之后 定义:
必须在函数原型中指定默认值。
被调用函数在 调用之前 定义:
形参的默认值既可在函数原型中指定,也可在定义函数时指定。
不能 在声明函数原型和定义函数时 指定默认值,即使其 值一样 也不可以。
在形参带有默认值的情况下,不声明函数原型,而是利用定义在先的方法同样是 合法的,应该在函数头中给形参赋默认值。
在给形参赋默认值时,应该指出,形参的默认值可以是任意复杂的表达式,甚至函数调用。注
(续)
默认值为函数 调用
#include<iostream.h>
int area(int a,int b);
int totalarea(int a,int b=area(0,0));
void main()
{ int number;
int length1,width1;
int length2,width2;
int total;
cout<<,Please tell me how many rectangle are there? 1 or 2:,;
cin>>number;
cout<<“Please input the length and width of the first rectangle:,;
cin>>length1>>width1;
cout<<endl;
if(number==2)
{ cout<<,Please input the length and width of the second
rectangle:,;
例 4-9
cin>>length2>>width2;
cout<<endl;
total=totalarea(area(length1,width1),area(length2,width2));
cout<< ″The sum of the two rectangles′s area is,″<<total<<endl;
}
else
{
total=totalarea(area(length1,width1));
cout<< ″The sum of the rectangle′s area is,″<<total<<endl;
}
}
int area(int a,int b)
{
return a*b;
}
int totalarea(int a,int b)
{
return (a+b);
}
注 在相同作用域中只能定义一次默认值,但 C++语言允许在不同作用域中,分别声明函数,并对其形参设置不同的默认值。
(续)
#include<iostream.h>
int add1(int a,int b=2);
int add2();
void main(void)
{
int total1,total2;
total1=add1(4);
total2=add2();
cout<<total1<< ″\ t\ t ″<<total2<<endl;}
int add1(int a,int b)
{
return a+b;
}
在不同作用域中声明函数说明,函数 add2的函数体中声明的函数原型的作用域仅仅是 在函数 add2的函数体内,且这个声明会在函数 add2内 屏蔽在程序起始 处对函数 add1的声明。
说明:在程序起始位置声明的函数原型的作用域是整个程序。
例 4-10
int add2()
{
int add1(int a,int b=5);
return add1(4);
}
6 9
说明:主程序中的两次函数调用其实都是
add1(4)。 有不同的结果,完全是由于在函数 add2中对 add1做了默认值 不同的声明 。
(续)
#include<iostream.h>
int m=8;
int add(int,int,int =m);
void main( )
{
int a=3,b=5,c=20;
int s=add(a,b);
cout<<s<< ″\ t\ t ″;
s=add( c);
cout<<s<<endl;
}
int add(int a,int b,int c)
{
return a+b+c;
}
练习,下列程序是否存在错误?
小结
函数的定义和调用格式 。
内联函数的作用和声明格式 。
默认参数的函数的声明和调用方法 。
作业
P46