第三章 函数湖南科技大学 莫尚丰
C++语言程序设计
C++语言程序设计 湖南科技大学
2
本章主要内容
函数的声明和调用
函数间的参数传递
内联函数
带默认形参值的函数
函数重载
C++系统函数
C++语言程序设计 湖南科技大学
3
函数的声明
函数是面向对象程序设计中,对功能的抽象
函数声明的语法形式类型标识符 函数名(形式参数表)
{
语句序列
}
函数的声明与使用 是被初始化的内部变量,寿命和可见性仅限于函数内部若无返回值,写 void
C++语言程序设计 湖南科技大学
4
函数的声明
形式参数表
<type1> name1,<type2> name2,...,
<typen> namen
函数的返回值
– 由 return 语句给出,例如:
return 0
– 无返回值的函数( void类型),不必写
return语句。
函数的声明与使用
C++语言程序设计 湖南科技大学
5
函数的调用
调用前先声明函数原型:
– 在调用函数中,或程序文件中所有函数之外,按如下形式说明:
类型标识符 被调用函数名(含类型说明的形参表) ;
调用形式函数名(实参列表)
嵌套调用
– 函数可以嵌套调用,但不允许嵌套定义。
– 递归调用
– 函数直接或间接调用自身。
函数的声明与使用
C++语言程序设计 湖南科技大学
6
例 3-1编写一个求 x的 n次方的函数
#include <iostream>
using namespace std;
double power(double x,int n);
int main()
{ cout<<"5 to the power 2 is "
<<power(5,2)<<endl;
}
double power(double x,int n)
{ double val=1.0;
while (n--) val=val*x;
return(val);
}
函数的声明与使用
C++语言程序设计 湖南科技大学
7
运行结果:
5 to the power 2 is 25
例 3-1编写一个求 x的 n次方的函数函数的声明与使用
C++语言程序设计 湖南科技大学
8
例 3-2 数制转换题目:
输入一个 8位二进制数,将其转换为十进制数输出。
例如:
11012=1(23)+1(22)+0(21)+1(20)=1310
所以,如果输入 1101,则应输出 13
函数的声明与使用
#include <iostream>
using namespace std;
double power (double x,int n);
int main()
{
int i;
int value = 0;
char ch;
cout << "Enter an 8 bit binary number ";
for (i = 7; i >= 0; i--)
{
cin >> ch;
if (ch == '1')
value += int(power(2,i));
}
cout <<"Decimal value is "<<value<<endl;
}
double power (double x,int n)
{
double val = 1.0;
while (n--) val *= x;
return(val);
}
运行结果:
Enter an 8 bit binary number 01101001
Decimal value is 105
9
C++语言程序设计 湖南科技大学
10
例 3-3编写程序求 π的值其中 arctan用如下形式的级数计算:
直到级数某项绝对值不大于 10-15为止;
π 和 x均为 double型 。
函数的声明与使用




239
1ar ct an4
5
1ar ct an16π

753
)a r c t a n (
753 xxx
xx
#include<iostream>
using namespace std;
int main()
{
double a,b;
double arctan(double x);//函数原型声明
a=16.0*arctan(1/5.0);
b=4.0*arctan(1/239.0);
//注意:因为整数相除结果取整,
//如果参数写 1/5,1/239,结果就都是 0
cout<<"PI="<<a-b<<endl;
}
11
double arctan(double x)
{ int i;
double r,e,f,sqr;
sqr=x*x;
r=0; e=x; i=1;
while(e/i>1e-15)
{
f=e/i;//表达式中每一项
r=(i%4==1)? r+f,r-f;//r是计算结果
e=e*sqr; i+=2;
}
return r;
}
运行结果:
PI=3.14159
12
C++语言程序设计 湖南科技大学
13
例 3-4
寻找并输出 11~999之间的数 m,它满足 m、
m2和 m3均为回文数。
– 回文:各位数字左右对称的整数。
例如,11满足上述条件
112=121,113=1331。
分析:
– 10取余的方法,从最低位开始,依次取出该数的各位数字。按反序重新构成新的数,比较与原数是否相等,若相等,则原数为回文。
函数的声明与使用
#include <iostream>
using namespace std;
int 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;
}
14
bool symm(long n)
{
long i,m;
i=n ; m=0 ;//m表示翻转后的数
while(i)
{
m=m*10+i%10;//i%10 表示 i的个位数
i=i/10 ;
}
return( m==n );
}
//该程序最好单步跟踪调试
15
运行结果:
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
16
C++语言程序设计 湖南科技大学
17
例 3-5
计算如下公式,并输出结果:
其中 r,s的值由键盘输入。 sin x的近似值按如下公式计算,计算精度为 10-6:
(即某项绝对值不大于 10-6为止)
函数的声明与使用


22
2222
r)s in (
2
1
r)(s in)(s in
ssr
ssr
k
当当

1
12
1
753
)!12()1(!7!5!3!1s in n
n
n
n
xxxxxx?
#include <iostream>
#include<cmath>
using namespace std;
int main()
{
double k,r,s;
double tsin(double x);
cout<<"r=";
cin>>r;
cout<<"s=";
cin>>s;
if (r*r<=s*s)
k=sqrt(tsin(r)*tsin(r)+tsin(s)*tsin(s));
else
k=tsin(r*s)/2;
cout<<k<<endl;
}
18
double tsin(double x)
{
double p=0.000001,g=0,t=x;//g是运算结果
int n=1;
do {
g=g+t;
n++;
t=-t*x*x/(2*n-1)/(2*n-2);//表示每一项
}while(fabs(t)>p); //fabs,求绝对值
return g;
}
运行结果:
r=5
s=8
1.37781 19
C++语言程序设计 湖南科技大学
20
例 3-6投骰子的随机游戏每个骰子有六面,点数分别为 1,2,3,4,5,6。
游戏者在程序开始时输入一个无符号整数,作为产生随机数的种子 。
每轮投两次骰子,第一轮如果和数为 7或 11则为胜,
游戏结束;和数为 2,3或 12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮,第三轮,..直到某轮的和数等于点数则取胜,若在此前出现和数为 7则为负 。
由 rolldice函数负责模拟投骰子,计算和数并输出和数 。
函数的声明与使用
#include <iostream>
#include <cstdlib>
using namespace std;
int rolldice(void);
int main()
{
int gamestatus,sum,mypoint;
unsigned seed;
cout<<"Please enter an unsigned integer:";
cin>>seed; //输入随机数种子
srand(seed); //将种子传递给 rand()
sum=rolldice(); //第一轮投骰子、计算和数
21
switch(sum)
{
case 7,//如果和数为 7或 11则为胜,状态为 1
case 11,gamestatus=1;
break;
case 2,//和数为 2,3或 12则为负,状态为 2
case 3,
case 12,gamestatus=2;
break;
default:
//其他情况,游戏尚无结果,状态为 0,记下点数,为下一轮做准备
gamestatus=0;
mypoint=sum ;
cout<<"point is "<<mypoint<<endl;
break;
}
22
while(gamestatus==0) //只要状态仍为 0,就继续进行下一轮
{
sum=rolldice();
if(sum==mypoint) //某轮的和数等于点数则取胜,状态置为 1
gamestatus=1;
else
if ( sum==7 )//出现和数为 7则为负,状态置为 2
gamestatus=2;
}
//当状态不为 0时上面的循环结束,以下程序段输出游戏结果
if( gamestatus==1 )
cout<<"player wins\n";
else
cout<<"player loses\n";
}
23
rand
函数原型,int rand(void);
所需头文件,<cstdlib>
功能和返回值:求出并返回一个伪随机数
srand
函数原型,void srand(unsigned int seed);
参数,seed产生随机数的种子。
所需头文件,<cstdlib>
功能:为使 rand()产生一序列伪随机整数而设置起始点。使用 1作为 seed参数,可以重新初化 rand()。
24
int rolldice(void)
{ //投骰子、计算和数、输出和数
int die1,die2,worksum;
die1=1+rand()%6;
die2=1+rand()%6;
worksum=die1+die2;
cout<<"player rolled
"<<die1<<'+'<<die2<<'='<<worksum<<endl;
return worksum;
}
25
运行结果 2:
Please enter an unsigned integer:23
player rolled 6+3=9
point is 9
player rolled 5+4=9
player wins
26
C++语言程序设计 湖南科技大学
27
函数调用的执行过程函数的声明与使用
main()
调 fun()
结束
fun()
返回
① ②



保存:
返回地址当前现场

恢复:
主调程序现场返回地址

C++语言程序设计 湖南科技大学
28
嵌套调用函数的声明与使用
main{}
调 fun1()
结束
fun1()
调 fun2()
返回
fun2()
返回
① ② ③



⑥⑧

C++语言程序设计 湖南科技大学
29
例 3-6 输入两个整数,求平方和。
#include <iostream>
using namespace std;
int main()
{
int a,b;
int fun1(int x,int y);
cin>>a>>b;
cout<<"a,b的平方和,"
<<fun1(a,b)<<endl;
}
函数的声明与使用
int fun1(int x,int y)
{
int fun2(int m);
return (fun2(x)+fun2(y));
}
int fun2(int m)
{
return (m*m);
}
运行结果:
3 4
a,b的平方和,25
30
C++语言程序设计 湖南科技大学
31
递归调用
函数直接或间接地调用自身,称为递归调用。
递归过程的两个阶段:
– 递推:
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
未知 已知函数的声明与使用
C++语言程序设计 湖南科技大学
32
例 3-8 求 n!
分析:计算 n!的公式如下:
这是一个递归形式的公式,应该用递归函数实现。
函数的声明与使用

)0()!1(
)0(1
!
nnn
n
n
源程序:
#include <iostream>
using namespace std;
long fac(int n)
{ long f;
if (n<0)
cout<<"n<0,data error!"<<endl;
else if (n==0) f=1;
else f=fac(n-1)*n;
return(f);
}
33
int main()
{
long fac(int n);
int n;
long y;
cout<<"Enter a positive integer:";
cin>>n;
y=fac(n);
cout<<n<<"!="<<y<<endl;
}
运行结果:
Enter a positive integer:8
8!=40320
34
C++语言程序设计 湖南科技大学
35
例 3-9
用递归法计算从 n个人中选择 k个人组成一个委员会的不同组合数。
分析:
由 n个人里选 k个人的组合数
=由 n-1个人里选 k个人的组合数
+由 n-1个人里选 k-1个人的组合数当 n==k或 k==0时,组合数为 1
函数的声明与使用
#include<iostream>
using namespace std;
int main()
{ int n,k;
int comm(int n,int k);
cin>>n>>k;
cout<<comm(n,k)<<endl;
}
int comm(int n,int k)
{ if (k>n) return 0;
else if( n==k||k==0 )
return 1;
else
return comm(n-1,k)+comm(n-1,k-1);
}
运行结果:
18 5
8568
36
C++语言程序设计 湖南科技大学
37
例 3-10汉诺塔问题有三根针 A,B,C。 A针上有 N个盘子,大的在下,小的在上,要求把这 N个盘子从 A针移到 C针,在移动过程中可以借助 B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。
函数的声明与使用
A B C
分析:
将 n 个盘子从 A针移到 C针可以分解为下面三个步骤:
①将 A 上 n-1个盘子移到 B针上(借助 C针) ;
② 把 A针上剩下的一个盘子移到 C针上 ;
③ 将 n-1个盘子从 B针移到 C针上(借助 A针) ;
事实上,上面三个步骤包含两种操作:
①将多个盘子从一个针移到另一个针上,这是一个递归的过程。 hanoi函数实现。
②将 1个盘子从一个针上移到另一针上。
用 move函数实现。
38
#include <iostream>
using namespace std;
void move(char getone,char putone)
{ cout<<getone<<"-->"<<putone<<endl; }
void hanoi(int n,char one,char two,char three)
{ void move(char getone,char putone);
if (n==1) move (one,three);
else
{ hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
39
int main()
{
void hanoi(int n,char one,char two,char three);
int m;
cout<<"Enter the number of diskes:";
cin>>m;
cout<<"the steps to moving "<<m
<<" diskes:"<<endl;
hanoi(m,'A','B','C');
}
40
运行结果:
Enter the number of diskes:3
the steps to moving 3 diskes:
A-->C
A-->B
C-->B
A-->C
B-->A
B-->C
A-->C
41
C++语言程序设计 湖南科技大学
42
函数的参数传递机制
—— 传递参数值
在函数被调用时才分配形参的存储单元。
实参可以是常量、变量或表达式。
实参类型必须与形参相符。
传递时是传递参数值,即单向传递。
函数的声明与使用
C++语言程序设计 湖南科技大学
43
函数的参数传递机制
—— 参数值传递举例
X N
被调函数:
主调函数:
32.5A
D = power(A,3)
2.5 3
double power(double X,int N)
函数的声明与使用
C++语言程序设计 湖南科技大学
44
例 3-11 输入两个整数交换后输出
#include<iostream>
using namespace std;
void Swap(int a,int b);
int main()
{
int x(5),y(10);
cout<<"x="<<x<<" y="<<y<<endl;
Swap(x,y);
cout<<"x="<<x<<" y="<<y<<endl;
return 0;
}
函数的声明与使用
void Swap(int a,int b)
{
int t;
t=a;
a=b;
b=t;
}
运行结果,
x=5 y=10
x=5 y=10
45
a=b;
5
x
10
y
5
a
10
b
执行主函数中的函数调用
Swap(x,y);
t=a;
5
x
10
y
5
a
10
b
5t
b=t;
5
x
10
y
10
a
5
b
5t
5
x
10
y
10
a
10
b
5t
在 Swap子函数中返回主函数以后 5
x
10
y 4646
C++语言程序设计 湖南科技大学
47
函数的参数传递 —— 用引用做形参
引用 (&)是标识符的别名,例如,
int i,j;
int &ri=i;
//建立一个 int型的引用 ri,并将其
//初始化为变量 i的一个别名
j=10;
ri=j;//相当于 i=j;
声明一个引用时,必须同时对它进行初始化,
使它指向一个已存在的对象。
一旦一个引用被初始化后,就不能改为指向其它对象。
引用可以作为形参
void swap(int& a,int& b) {...}
函数的声明与使用
C++语言程序设计 湖南科技大学
48
例 3-12 输入两个整数交换后输出
#include<iostream>
using namespace std;
void Swap(int& a,int& b);
int main()
{ int x(5),y(10);
cout<<"x="<<x<<" y="<<y<<endl;
Swap(x,y);
cout<<"x="<<x<<" y="<<y<<endl;
return 0;
}
void Swap(int& a,int& b)
{ int t;
t=a;
a=b;
b=t;
}
函数的声明与使用运行结果,
x=5 y=10
x=10 y=5
t=a;
x
5
t
5
x 的别名
a
x y
5 10
y 的别名x 的 别名
a b
y 的别名x 的别名
a b
x
10
y
10
a=b b=t;
y
5
t
5
y 的地址
b
x y
10 5
Swap(x,y);
49
C++语言程序设计 湖南科技大学
50
内联函数声明与使用
声明时使用关键字 inline。
编译时在调用处用函数体进行替换,
节省了参数传递、控制转移等开销。
注意:
– 内联函数体内不能有 循环语句 和 switch
语句。
– 内联函数的声明必须出现在内联函数第一次被调用之前。
– 对内联函数不能进行异常接口声明。
内联函数
C++语言程序设计 湖南科技大学
51
例 3-14 内联函数应用举例
#include<iostream>
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<<area<<endl;
return 0;
}
内联函数
C++语言程序设计 湖南科技大学
52
默认形参值的作用
函数在声明时可以预先给出默认的形参值,
调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。
例如:
int add(int x=5,int y=6)
{ return x+y; }
int main()
{ add(10,20);//10+20
add(10); //10+6
add(); //5+6
}
带默认形参值的函数
C++语言程序设计 湖南科技大学
53
默认形参值的说明次序
默认形参值必须 从右向左 顺序声明,
并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。
例:
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);//错误带默认形参值的函数
C++语言程序设计 湖南科技大学
54
默认形参值与函数的调用位置
调用出现在函数体实现之前时,默认形参值必须在函数原形中给出;而当调用出现在函数体实现之后时,
默认形参值需在函数实现时给出。
例:
int add(int x=5,int y=6);
int main()
{ add(); //调用在实现前
}
int add(int x,int y)
{ return x+y; }
int add(int x=5,int y=6)
{ return x+y; }
int main()
{ add(); //调用在实现后
}
带默认形参值的函数
C++语言程序设计 湖南科技大学
55
默认形参值的作用域
在相同的作用域内,默认形参值的说明应保持惟一,但如果在不同的作用域内,允许说明不同的默认形参。
例:
int add(int x=1,int y=2);
int main()
{ int add(int x=3,int y=4);
add();//使用局部默认形参值(实现 3+4)
}
void fun()
{,..
add();//使用全局默认形参值(实现 1+2)
}
带默认形参值的函数
C++语言程序设计 湖南科技大学
56
重载函数的声明
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);
函数重载
C++语言程序设计 湖南科技大学
57
注意事项
– 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:
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; }
函数重载
– 重载函数的形参必须不同,个数 不同或 类型 不同。
– 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
C++语言程序设计 湖南科技大学
58
例 3-16重载函数应用举例编写三个名为 add的重载函数,分别实现两整数相加、两实数相加和两个复数相加的功能。
#include<iostream>
using namespace std;
struct complex
{
double real;
double imaginary;
};
函数重载
int main()
{
int m,n;
double x,y;
complex c1,c2,c3;
int add(int m,int n);
double add(double x,double y);
complex add(complex c1,complex c2);
cout<<"Enter two integer,";
cin>>m>>n;
cout<<"integer <<m<<'+'<<n<<"="<<add(m,n)<<endl;
59
cout<<"Enter two real number,";
cin>>x>>y;
cout<<"real number "<<x<<'+'<<y<<"= "<<add(x,y)
<<endl;
cout<<"Enter the first complex number,";
cin>>c1.real>>c1.imaginary;
cout<<"Enter the second complex number,";
cin>>c2.real>>c2.imaginary;
c3=add(c1,c2);
cout<<"complex number ("<<c1.real<<','
<<c1.imaginary <<")+("<<c2.real<<','
<<c2.imaginary<<")=("<<c3.real<<','
<<c3.imaginary<<")\n";
}
60
int add(int m,int n)
{ return m+n; }
double add(double x,double y)
{ return x+y; }
complex add(complex c1,complex c2)
{
complex c;
c.real=c1.real+c2.real;
c.imaginary=c1.imaginary+c2.imaginary;
return c;
}
61
运行结果:
Enter two integer,3 5
integer 3+5=8
Enter two real number,2.3 5.8
real number 2.3+5.8= 8.1
Enter the first complex number,12.3 45.6
Enter the second complex number,56.7 67.8
complex number (12.3,45.6)+(56.7,67.8)= (69,113.4)
62
C++语言程序设计 湖南科技大学
63
C++系统函数
C++的系统库中提供了几百个函数可供程序员使用。
例如:求平方根函数( sqrt)、求绝对值函数( fabs)等。
使用系统函数时要包含相应的头文件。
例如,math.h 或 cmath
使用C++
系统函数
C++语言程序设计 湖南科技大学
64
例 3-17系统函数应用举例
题目:
从键盘输入一个角度值,求出该角度的正弦值、余弦值和正切值。
分析:
系统函数中提供了求正弦值、余弦值和正切值的函数,sin(),cos(),tan(),函数的说明在头文件 math.h和 cmath中。
使用C++
系统函数
#include<iostream>
#include<cmath>
using namespace std;
const double pi(3.14159265);
int main()
{ double a,b;
cin>>a;
b=a*pi/180;
cout<<"sin("<<a<<")="<<sin(b)<<endl;
cout<<"cos("<<a<<")="<<cos(b)<<endl;
cout<<"tan("<<a<<")="<<tan(b)<<endl;
}
运行结果:
30
sin(30)=0.5
cos(30)=0.866025
tan(30)=0.57735
65
C++语言程序设计 湖南科技大学
66
查找系统函数的使用说明
查编译系统的库函数手册
查联机帮助 —— VC++6.0联机帮助的使用方法:
help/Contents
->(,活动子集”栏 )Visual C++
Documentation
->Visual C++ Documentation
->Using Visual C++
-> Visual C++ Programmer's Guide
-> Run-Time Library Reference
->Run Time Routines by Category
-> Run Time Routines by Category
使用C++
系统函数
C++语言程序设计 湖南科技大学
67
小结与复习建议
主要内容
– 函数的声明和调用、函数间的参数传递、内联函数、带默认形参值的函数、函数重载,C++
系统函数
达到的目标
– 学会将一段功能相对独立的程序写成一个函数,
为下一章学习类和对象打好必要的基础。
实验任务
– 实验三
作业
– P88 3-12