函数
函数的形参和实参
-
形参变量只有在函数被调用时才会分配内存,调用结束后,立刻释放内存,所以形参变量只有在函数内部有效,不能在函数外部使用。
-
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的数据,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参,所以应该提前用赋值、输入等办法使实参获得确定值。
-
实参和形参在数量上、类型上、顺序上必须严格一致,否则会发生“类型不匹配”的错误。当然,如果能够进行自动类型转换,或者进行了强制类型转换,那么实参类型也可以不同于形参类型。
-
函数调用中发生的数据传递是单向的,只能把实参的值传递给形参,而不能把形参的值反向地传递给实参;换句话说,一旦完成数据的传递,实参和形参就再也没有瓜葛了,所以,在函数调用过程中,形参的值发生改变并不会影响实参。
-
形参和实参可以同名。但是按值传递时 (call by value),函数内部的形参无法改变函数外部实参的值。
-
要想在函数内部修改传入的实参的值,只能使用 按指针传递 或 按引用传递 (call by reference) 的方式
#include <stdio.h>
#include <stdlib.h>
//要使用输入输出流,必须包含下面两句
#include <iostream>
using namespace std;
//按值传递
int findMax_value(int x, int y){
int max = (x>=y) ? x : y;
x=0;
y=0;
return max;
}
//指针传递
int findMax_pointer(int *x, int *y){
int max = (*x >= *y) ? *x : *y;
*x=0;
*y=0;
return max;
}
//引用传递
int findMax_reference(int &x, int &y){
int max = (x>=y) ? x : y;
x=0;
y=0;
return max;
}
int main(){
int a,b;
cin >> a >> b;
int m;
m=findMax_value(a,b);
cout << "max="<< m << ", a="<< a << ", b=" << b <<endl;
m=findMax_pointer(&a,&b);
cout << "max="<< m << ", a="<< a << ", b=" << b <<endl;
cin >> a >> b;
m=findMax_reference(a,b);
cout << "max="<< m << ", a="<< a << ", b=" << b <<endl;
return 0;
}
两次输入:10 20
运行结果为
10 20
max=20, a=10, b=20
max=20, a=0, b=0
10 20
max=20, a=0, b=0
return用法
函数一旦遇到 return 语句就立即返回,后面的所有语句都不会被执行到了。从这个角度看,return 语句还有强制结束函数执行的作用。
return 语句是提前结束函数的唯一办法。return 后面可以跟一份数据,表示将这份数据返回到函数外面;return 后面也可以不跟任何数据,表示什么也不返回,仅仅用来结束函数。
函数声明及函数原型
C语言代码由上到下依次执行,原则上函数定义要出现在函数调用之前,否则就会报错。但在实际开发中,经常会在函数定义之前使用它们,这个时候就需要提前声明。
所谓声明(Declaration),就是告诉编译器我要使用这个函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上。
函数声明的格式非常简单,相当于去掉函数定义中的函数体,并在最后加上分号;
,如下所示:
dataType functionName( dataType1 param1, dataType2 param2 ... );
也可以不写形参,只写数据类型:
dataType functionName( dataType1, dataType2 ... );
函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,称为函数原型(Function Prototype)。函数原型的作用是告诉编译器与该函数有关的信息,让编译器知道函数的存在,以及存在的形式,即使函数暂时没有定义,编译器也知道如何使用它。
使用者往往只关心函数的功能和函数的调用形式,很少关心函数的实现细节,将函数定义放在最后,就是尽量屏蔽不重要的信息,凸显关键的信息。将函数声明放到 main() 的前面,在定义函数时也不用关注它们的调用顺序了,哪个函数先定义,哪个函数后定义,都无所谓了。
☆头文件存放函数和变量的声明
然而在实际开发中,往往都是几千行、上万行、百万行的代码,将这些代码都放在一个源文件中简直是灾难,不但检索麻烦,而且打开文件也很慢,所以必须将这些代码分散到多个文件中。对于多个文件的程序,通常是将函数定义放到源文件(.c
文件)中,将函数的声明放到头文件(.h
文件)中,使用函数时引入对应的头文件就可以,编译器会在链接阶段找到函数体。
很多初学者认为 stdio.h 中包含了函数定义(也就是函数体),只要有了头文件就能运行,其实不然,头文件中包含的都是函数声明,而不是函数定义,**函数定义都放在了其它的源文件中,这些源文件已经提前编译好了,并以动态链接库或者静态链接库的形式存在,**只有头文件没有系统库的话,在链接阶段就会报错,程序根本不能运行。
除了函数,变量也有定义和声明之分。实际开发过程中,变量定义需要放在源文件(.c
文件)中,变量声明需要放在头文件(.h
文件)中,在链接程序时会将它们对应起来。
C++函数重载和函数模板
函数重载,即一物多用,同一个函数名可以有
- 不同数据类型的参数
- 不同数据类型的返回值
即可以作为多个函数(以上两者至少有一个是不同的,否则不知道系统调用哪个函数)。
例如
int max(int a, int b, int c=1){
......
}
int max(int a, int b){
......
}
//以上的max便是重载函数,拥有相同类型、不同数目的参数
也可以用函数模板来完成函数重载(适用于参数类型不同,但参数个数相同的同名函数)。
函数模板通式为
template <typename T1, typename T2> //允许有多个类型参数
ret-type func-name(parameter list)
{
// 函数的主体
}
例子
#include <iostream>
#include <string>
using namespace std;
template <typename T>
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World
函数允许有默认参数
在函数声明中可以设定默认参数;
例如
//函数声明
int findmax(int a, int b=0);
//在调用时(要给出默认值)
int main(){
int m=10,n=20;
int max=findmax(m); //表示第一个参数为10,第二个为默认值0
int max=findmax(m,n); //表示第一个参数为10,第二个为20
return 0;
}
//函数定义时不给出默认值(声明已经给过)
int findmax(int a, int b){
......
}
默认参数必须在参数列表的末尾。
注意:函数不能既作为重载函数,又作为有默认参数的函数。会出现歧义。
如
#include <iostream>
#include <string>
using namespace std;
int max(int a, int b, int c=1){
......
}
int max(int a, int b){
......
}
//以上的max便是重载函数
int main(){
int m=max(10,20);
//系统不知道上述表达式调用的是哪一个max函数
//可能是 int m=max(10,20,1) 第一个函数,带有默认参数
//也可能是 int m=max(10,20) 第二个函数,只有两个参数
}
内联函数 ( inline function )
引入内联函数的目的是为了解决程序中函数调用的效率问题,这么说吧,程序在编译器编译的时候,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体进行替换,而对于其他的函数,都是在运行时候才被替代。这其实就是个空间代价换时间的节省。所以内联函数一般都是1-5行的小函数。在使用内联函数时要留神:
- 1.在内联函数内不允许使用循环语句和开关语句;
- 2.内联函数的定义必须出现在内联函数第一次调用之前;
- 3.类结构中所在的类说明内部定义的函数是内联函数。
如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。
在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。
#include <iostream>
using namespace std;
inline int Max(int x, int y)
{
return (x > y)? x : y;
}
// 程序的主函数
int main( )
{
cout << "Max (20,10): " << Max(20,10) << endl;
cout << "Max (0,200): " << Max(0,200) << endl;
cout << "Max (100,1010): " << Max(100,1010) << endl;
return 0;
}
运行结果
Max (20,10): 20
Max (0,200): 200
Max (100,1010): 1010