一个C语言程序是由若干函数组成的,c++同样沿用了c语言使用函数的方法。我们可以认为不论c还会c++,程序中的各项操作基本上都由函数来实现的。程序实质上就是一个个函数的编写和组织,所以我们应该掌握函数的概念以及学会如何去设计一个函数。
函数的一般格式为:
返回值类型 函数名称([函数参数]){
函数体…
}
我们来看一个基本的例子:
#include <iostream>
using namespace std;
/*
*
*/
int max(int a, int b) {
return a > b ? a : b;
}
int main(int argc, char** argv) {
cout << "max number is :" << max(3, 10) << endl;
return 0;
}
上面给出了函数的一般格式,在定义函数的时候,比如这里的int a, int b称之为函数的形参,而在main函数中调用的时候传入的3,10称之为函数的实参。
我们需要 注意的是一个函数必须要有返回值,如果该函数没有返回值,那么我们就应该将这个函数申明为void类型的函数。
同理,一个函数可以拥有参数,也可以没有参数,具有参数的函数可以有一个或多个参数。
接下来我们说一下关于函数一些特效。
1.参数按值传递和按地址传递
我们通常见到的函数一般都是按值传递,顾名思义就是传递到函数中的参数全部是数值,并不是参数变量本身。
当按地址传递一个变量的时候,我们传递的是变量本身,在函数中对参数变量所做的任何修改都会影响函数外被传递的变量。
按值传递的参数其实质是,在函数接收到参数,会自动生成对应的变量,并且赋予同样的值。
按地址传递的实质是,参数本身其实是一个地址的指针,这个指针指向的就是该参数的内存地址。这样理解的话,其实按地址传递应该也是一种特殊的值传递,只不过这个值和变量指向的是同一块内存地址,从而使函数内部的修改会影响函数外的变量。
我们通过一个例子来看下两者的使用:
#include <iostream>
using namespace std;
/*
*
*/
int max(int a, int b) {
a += 1;
b += 1;
return a > b ? a : b;
}
int main(int argc, char** argv) {
int a = 10;
int b = 3;
cout << "max number is :" << max(a, b) << endl;
cout << "a = " << a << " b = " << b << endl;
return 0;
}
这是一个值传递的示例,其运行结果如下:
max number is :11
a = 10 b = 3
大家可以清楚看到,在函数内部我们对a,b分别进行了加1操作,但是调用函数后,并未影响原来a,b的值。
接下来再看按地址传递参数的例子:
#include <iostream>
using namespace std;
/*
*
*/
int max(int& a, int& b) {
a += 1;
b += 1;
return a > b ? a : b;
}
int main(int argc, char** argv) {
int a = 10;
int b = 3;
cout << "max number is :" << max(a, b) << endl;
cout << "a = " << a << " b = " << b << endl;
return 0;
}
输出:
max number is :11
a = 11 b = 4
两者唯一的不同是就是我们在申明函数的时候参数的类型后面多了一个“&”取址符。注意了,这个只在c++中适用,如果是c中的话,大家还是得适用指针来完成同样的操作。
2.函数 参数的默认值
想必大家都接触过编程语言,关于函数的默认值是不陌生的。举个例子来说,我们每天都要开车出行,稍微不注意就要被交警扣分罚款,我们写个函数模拟一下。
#include <iostream>
using namespace std;
/*
*
*/
int surplusScore(int deductPointsType, int origin = 12) {
switch (deductPointsType) {
case 0:
//闯红灯交通违法记分
origin -= 6;
break;
case 1:
// ,不挂号牌或遮挡号牌
origin -= 12;
break;
case 2:
// 驾驶人员有违反机动车载物规定条例
origin -= 1;
break;
default:
break;
}
return origin;
}
int main(int argc, char** argv) {
// 假设原来满分,但是闯红灯
cout << "闯红灯后剩余分数: " << surplusScore(0) << endl;
return 0;
}
在这里我们可以看到这么两句代码
int surplusScore(int deductPointsType, int origin = 12)
surplusScore(0)
函数申明我们为初始分数指定了一个默认值12,在调用函数的时候我们只传递了违法交通的类型,并没有传入origin参数。在这种我们指定默认值得情况,如果在调用函数的时候没有传递该参数,那么使用默认值,这里就是12,如果传递了该参数,那么传递的参数会替换默认值作为新值。我们验证一下:
cout << "闯红灯后剩余分数: " << surplusScore(0,6) << endl;
输出: 0,当然了直观一点的可以在函数内打印下这个参数的值。
3.函数重载
函数重载指的是不同的函数可以使用相同的函数名称,但是呢必须满足该条件:
参数必须拥有不用的参数个数或者类型
int qsgMax(int a, int b) {
return a > b ? a : b;
}
int qsgMax(int a, int b, int c) {
return a > b ? (a > c ? a : c) : (b > c ? b : c);
}
double qsgMax(double a, double b) {
return a > b ? a : b;
}
int main(int argc, char** argv) {
cout << "max is :" << qsgMax(2, 5) << endl;
cout << "max is :" << qsgMax(2, 6, 8) << endl;
cout << "max is :" << qsgMax(2.2, 5.3) << endl;
return 0;
}
4.内联函数
内联函数指该函数必须在被调用的地方以代码的形式被编译。这也就相当于一个宏定义。它使用关键字inline指令来完成,好处就是对于特别短的函数来说,可以避免调用函数的一些常规操作时间,比如参数堆栈操作。所以它的编译结果的运行会更快一些。
示例:
inline void testfunc(int a, int b) {
cout << a <<endl << b << endl;
}
5.函数模板
使用函数模板通常情况下我们是需要建立一个通用的函数,其函数类型和形参不具体指定,而是用一个虚拟的类型来代替,这个通用的函数就是函数模板。
凡是函数体相同的函数都可以使用这个模板来代替,而不用定义多个函数,就比如我们上面的例子。在调用函数的时候,系统会根据实参的类型来取代模板的虚拟类型,从而实现不同功能。
定义函数模板的一般格式为:
template <typename T>
我们看个例子:
template<typename T>
T qsgMaxTemplate(T a, T b) {
return a > b ? a : b;
}
int main(int argc, char** argv) {
cout << "max is :" << qsgMaxTemplate(2,10) << endl;
cout << "max is :" << qsgMaxTemplate(2.5,10.1) << endl;
return 0;
}
输出:
max is :10
max is :10.1