3.1 函数的定义与使用
3.1.1 函数的定义
函数是面向对象程序设计中,对功能的抽象
3.1.2 函数的调用
- 调用前先声明函数原型:
- 调用形式
- 嵌套调用:函数可以嵌套调用,但不允许嵌套定义。
- 递归调用:函数直接或间接调用自身
例:
由于函数power 的定义位于调用之后,所以需要先对函数原型加以声明。
例: 输入一个8位二进制数,将其转换为十进制数输出。11012 = 1(23) + 1(22) + 0(21) + 1(20) = 1310 所以,如果输入1101,则应输出13
例:其中arctan用如下形式的级数计算: 直到级数某项绝对值不大于10-15为止;π和x均为double型。
例:寻找并输出11~999之间的数m,它满足m、m2和m3均为回文数。
回文:各位数字左右对称的整数。 例如:11满足上述条件 112=121,113=1331。
分析: 10取余的方法,从最低位开始,依次取出该数的各位数字。按反序重新构成新的数,比较与原数是否相等,若相等,则原数为回文。
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
例:计算如下公式,并输出结果。
其中r 、s的值由键盘输入。sinx 的近似值按如下公式计算:
计算精度为10-6,当某项的绝对值小于计算精度时,停止累加,累加和即为该精度下的sinx的近似值
例:投骰子的随机游戏
游戏规则是:每个骰子有六面,点数分别为1、2、3、4、5、6。游戏者在程序开始时输入一个无符号整数,作为产生随机数的种子。
每轮投两次骰子,第一轮如果和数为7或11则为胜,游戏结束;和数为2、3或12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮、第三轮...直到某轮的和数等于点数则取胜,若在此前出现和数为7则为负。
由rolldice函数负责模拟投骰子、计算和数并输出和数。
2、嵌套调用
例:输入两个证书,求他们的平方和
1 #include <iostream>
2 using namespace std;
3
4 int fun1(int x,int y)
5 {
6 int fun2(int m);
7 return (fun2(x)+fun2(y));
8 }
9
10 int fun2(int m)
11 {
12 return (m*m);
13 }
14
15 void main(void)
16 {
17 int a,b;
18 int fun1(int x,int y);
19 cin>>a>>b;
20 cout<<"a、b的平方和:" <<fun1(a,b)<<endl;
21 }
3、递归调用
函数可以直接或间接地调用自身,称为递归调用。
递归过程的两个阶段:
- 递推: 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
- 未知 ← 已知
例:求n!
分析:计算n!的公式如下:
1 #include <iostream>
2 using namespace std;
3 long fac(int n)
4 {
5 long f;
6 if (n<0)
7 cout<<"n<0,data error!"<<endl;
8 else if (n==0) f=1;
9 else f=fac(n-1)*n;
10 return(f);
11 }
12 void main()
13 {
14 long fac(int n);
15 int n;
16 long y;
17 cout<<"Enter a positive integer:";
18 cin>>n;
19 y=fac(n);
20 cout<<n<<"!="<<y<<endl;
21 }
运行结果:
Enter a positive integer:8
8!=40320
例:用递归法计算从n 个人中选择k个人组成一个委员会的不同组合数。
分析: 由n个人里选k个人的组合数 = 由n-1个人里选k个人的组合数 + 由n-1个人里选k-1个人的组合数
当n==k或k==0时,组合数为1
例:汉诺塔问题:有三根针A、B、C。A针上有N个盘子,大的在下,小的在上,要求把这N个盘子从A针移到C针,在移动过程中可以借助B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。
分析: 将n 个盘子从A针移到C针可以分解为下面三个步骤:
①将A 上n-1个盘子移到 B针上(借助C针);
②把A针上剩下的一个盘子移到C针上;
③将n-1个盘子从B针移到C针上(借助A针);
事实上,上面三个步骤包含两种操作:
①将多个盘子从一个针移到另一个针上,这是一个递归的过程。 hanoi函数实现。
②将1个盘子从一个针上移到另一针上。 用move函数实现。
运行结果:
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
3.1.3 函数的参数传递
在函数被调用时才分配形参的存储单元。
1、值传递
例:输入两整数交换后输出
运行结果:
x=5 y=10
x=5 y=10
分析:从上面的运行结果可以看出,并没有达到交换的目的。这是因为,采用的是值传递,函数调用时传递的是实参的值,是单向传递过程。形参值的改变对实参不起作用。
2、形参传递
引用(&)是一种特殊类型的变量,可以被认为是另一个变量的别名
使用引用时必须注意下列问题:
- 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
- 一旦一个引用被初始化后,就不能改为指向其它对象。
用引用作为形参,在函数调用时发生的参数传递,称为引用传递。
例:输入两个整数交换后输出
运行结果:
x=5 y=10
x=10 y=5
3.2内联函数
声明时使用关键字 inline。
对于一些功能简单、规模较小又使用频繁的函数,可以设计为内联函数。
内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。这样就节省了参数传递、控制转移等开销。
注意:
- 内联函数体内不能有循环语句和switch语句。
- 内联函数的声明必须出现在内联函数第一次被调用之前。
- 对内联函数不能进行异常接口声明。
例:
3.3 带默认形参值得函数
函数在定义时可以预先声明默认的形参值。调用时如果给出实参,则用实参初始化形参,如果没有给出实参,则采用预先声明的默认形参值。
默认形参值的说明次序:
默认形参值必须从右向左顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。例如:
默认形参值与函数的调用位置:
如果一个函数在定义之前又有原型声明,默认形参值需要在原型声明中给出,定义中不能再出现默认形参值。
默认形参值的作用域:
在相同的作用域内,默认形参值的说明应保持唯一,但如果在不同的作用域内,允许说明不同的默认形参。
3.4函数的重载
C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。
注意事项:
- 重载函数的形参必须不同: 个数不同或类型不同。
- 编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
- 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好。
例子:编写三个名为add的重载函数,分别实现两整数相加、两实数相加和两个复数相加的功能。
运行结果:
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)
3.5 C++ 系统函数
C++的系统库中提供了几百个函数可供程序员使用。 例如:求平方根函数(sprt)、求绝对值函数(abs)等。
使用系统函数时要包含相应的头文件。 例如:math.h 或 cmath
例:从键盘输入一个角度值,求出该角度的正弦值、余弦值和正切值。
分析: 系统函数中提供了求正弦值、余弦值和正切值的函数:sin()、cos()、tan(),函数的说明在头文件math.h中。
运行结果:
30
sin(30)=0.5
cos(30)=0.866025
tan(30)=0.57735
3.6 深度搜索
3.6.1 运行栈与函数调用的执行
3.6.2 函数声明与类型安全
来源:https://www.cnblogs.com/alec7015/p/12391839.html