c++ 函数章节总结

一、为什么要使用函数?

1. 简化代码,增强程序的可读性。

把一些计算或操作编成通用的函数,以供随时调用,从而避免了代码的重复冗长;简化代码量,对各个部分进行封装,使问题变得简单而且直观,提高了程序的易读性。

2.提升程序的可维护性。

如果我们把主程序拆分成许多个步骤,为每一个功能编写一个函数,那么根据函数的函数名每个函数的功能就非常清晰了。如果我们要修改某一个函数的功能,其他的函数也丝毫不会受到影响。

3.提高团队的开发效率。

设计一个规模很大的程序,它有几千项功能,若把他们都放在一个主函数里,就只能由一个人来编写。但如果我们把这几千项功能分拆为一些函数,分给几百个人去编写,最后用主函数把这些完成的函数组织一下,一个程序就可以很快完工。

4.降低程序执行效率。【缺点】

在程序中运用函数,就需要传递参数,开辟缓存、堆栈等,相比较而言,这个歌过程会耗一些多余的效率。

二、为什么要用函数重载?

【定义】两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据形参和实参的类型和个数的最佳匹配,自动确定调用哪一个函数,称作函数的重载。

  • 重载函数的形参必须不同(形参个数不同或者类型不同)
  • 与返回值的类型无关

【使用函数重载的好处】

重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。当函数的编写者充分考虑了不同情况下应该运行稍有不同的函数,函数的使用者就不必为这些小细节而烦恼了。

【注意】当使用具有默认形参值的函数重载形式时,需要注意防止二义性


void fun(int length,int weight = 2,int height = 33);   //由于weight和height具有默认初始值,只需要一个参数length即可调用函数
void fun(int length);   //只需要参数length即可调用函数
/*此时,对于语句fun(1),编译器会指出语法错误*/

三、值传递 VS 地址传递 VS 引用传递

1.值传递

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

int fun(int x);

2.地址传递

形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

int fun(int *x);

3.引用传递

形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

int fun(int &x);

4.三种传递方式的比较

【代码】分析三种传值方式函数操作地址的不同


#include < iostream >

using namespace std;
	
//值传递
void change1(int n) {
	cout << "值传递--函数操作地址" << &n << endl;     //显示的是拷贝的地址而不是源地址 
	n++;
}

//引用传递
void change2(int& n) {
	cout << "引用传递--函数操作地址" << &n << endl;  //显示的是源地址(即引用为别名)
	n++;
}
//指针传递
void change3(int* n) {
	cout << "指针传递--函数操作地址 " << n << endl;   //显示的是源地址
	*n = *n + 1;
}
int main() {
	int n = 10;
	cout << " n的地址" << &n << endl<< endl;
	change1(n);
	cout << "值传递结果   n=" << n << endl<< endl;
	change2(n);
	cout << "引用传递结果 n=" << n << endl<< endl;
	change3(&n);
	cout << "地址传递结果 n=" << n << endl<< endl;
	return true;
}

【结论】

  • 当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
  • 当函数内部需要修改参数并且希望改动影响调用者时,采用引用传递或者地址传递。
  • 当一个函数实际需要返回多个值,而只能显式返回一个值时,可以将另外需要返回的变量以地址或者引用传递
    给函数,这样在函数内部修改并且返回后,调用者可以拿到被修改过后的变量,也相当于一个隐式的返回值传递。

四、递归函数

【定义】一种可以直接或间接调用自身的函数(自己调用自己)

  • 递归的边界
  • 递归的逻辑--公式

【例1】阶乘

【分析】阶乘的递归公式为

【代码】

#include< iostream >
using namespace std; 
int F(int n){ 
	if(n==0)//递归边界 
		return 1; 
	return n*F(n-1);//递归公式
} 

int main(){ 
	int n; 
	cin >> n; 
	cout << F(n) << endl;
	return 0;
}

【例2】汉诺塔

【分析】

1)n == 1
         第1次  1号盘  A---->C       sum = 1 次
2) n == 2
         第1次  1号盘  A---->B
         第2次  2号盘  A---->C
         第3次  1号盘  B---->C        sum = 3 次
3)n == 3
			第1次  1号盘  A---->C
			第2次  2号盘  A---->B
			第3次  1号盘  C---->B
			第4次  3号盘  A---->C
			第5次  1号盘  B---->A
			第6次  2号盘  B---->C
			第7次  1号盘  A---->C        sum = 7 次
  • 假设A为存放盘子的塔,B为目标塔,C为辅助塔,算法分为三步:
  • step1:将A上n-1个盘子全部放到C塔上
  • step2:将A上剩下的一个盘子放到B塔上
  • step3:将C塔上的盘子全部放到B塔上

【代码】

#include<iostream>
using namespace std;

void move(char src, char dest) {   //移动函数
	cout << src << "-->" << dest << endl;
}

void hanoi(int n, char src, char mid, char dest) {
	if (n == 1) move(src, dest);
	else {
		hanoi(n - 1, src, dest, mid);  //把上面的n-1个移动到备用柱子
		move(src, dest);    //把第n个移动到目标柱子
		hanoi(n - 1, mid, src, dest);   //把备用柱子上的n-1个移动到目标柱子
	}
}

int main() {
	int m;
	cout << "enter the num:";  //输入环个数
	cin >> m;
	hanoi(m, 'A', 'B', 'C');
	return 0; 
}

posted @ 2019-09-16 20:55  王姝  阅读(303)  评论(0编辑  收藏  举报