1、函数的定义与使用
main函数是C++程序的主函数,主函数是程序执行的起点。由主函数调用子函数,子函数也可以调用子函数。
调用其他函数的被称为主调函数,被其他函数调用的称为被调函数。
1.1 函数的定义
函数定义的语法:
类型说明符 函数名(含类型说明的形式参数表){
语句序列
}
类型说明符规定了函数的返回给主调函数的返回值类型。如果不返回任何值给主调函数,这时可以使用void。当类型说明符不为void时,说明有返回值,返回值需要由return语句给出:
return 表达式;//有返回值时一定含有return语句
return;//没有返回值可以这样写,也可以不写
函数下形参表可以为空,表示没有任何形参。如main()函数就可以没有形参。main也可以有形参,这时比较特殊,main函数的形参也叫命令行参数,由操作系统在启动程序时初始化。
1.2 函数的调用
1.2.1 函数调用形式
调用函数之前首先要定义函数,但如果希望在定义一个函数前调用它,则需要在调用函数之前添加该函数的函数原型声明。
函数原型声明只是将有关函数的有关信息告诉了编译器,此时不产生任何代码。
如果在所有函数之前声明了函数原型,那么该函数在本程序文件中任何地方都可以调用。如果只是在某个主调函数内部声明了被调函数原型,那么该原型只能在这个函数内部有效。
函数原型声明的形式如下:
类型说明符 函数名(含类型说明的形参表)
//!!函数原型声明的时候形参表的形参名可以省略,只包含类型信息即可,但不推荐
声明了函数原型之后就可以调用函数了:
函数名(实参列表)
1.2.2 嵌套调用、递归调用
嵌套调用:如果函数1调用了函数2,就形成了嵌套调用。
递归调用:函数可以直接或间接地调用自身,称为递归调用
1.3 函数的参数传递
函数的参数传递指定就是形参核实参的结合(形实结合),形实结合的方式有值传递和引用传递。
- 实参指的是调用函数时放在参数列表的变量
- 形参指定是在函数体内部使用的参数列表的变量
1.3.1 值传递
值传递是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。形参获得了值之后就与实参脱离了关系,此后形参发生什么样的变化都不会影响到实参。
1.3.2 引用传递
引用传递可以解决值传递中的问题——形参无法对实参产生影响。
引用是一种特殊类型的变量,可以被认为是另一个变量的别名,通过引用名与通过被引用的变量名访问变量的效果是一样的。
2、内联函数的声明与使用
2.1 什么是内联函数
意指:当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置。这样做的好处是省去了调用的过程,加快程序运行速度。
- 声明时使用关键帧inline。
- 编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销。
- 本质上就是空间换时间
2.2 内联函数定义
只要在函数声明或定义前加一个 inline 修饰符。
inline int max(int a, int b)
{
return (a>b)? a : b;
}
2.3 内联函数注意事项
- 含有递归调用的函数不能设置为inline
- 内联函数体不能有循环语句、switch语句
- 内联函数增加体积的特性,所以建议inline函数内的代码有关很短小,最好几行内搞定。
- 内联函数的声明必须出现在内联函数第一次被调用之前
- 对内联函数不能进行异常接口声明
2.4 内联函数和宏定义函数的区别
- 内联函数是在编译的时候展开的,宏是在预编译时展开;在编译时,内联函数直接被嵌入到目标代码中去,而宏只是有关简单的文本替换。
- 内联函数可以进行类型安全检查、语句是否正确等编译功能,宏不具有这样的功能;宏不是函数,inline是函数。
- 内联函数在运行时可以运行,宏定义不行。
- 内联函数可以访问类的成员变量,宏不可用。
3、带默认形参的函数
3.1、作用:
函数在声明时可以预先给出默认的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。
int add(int x=5,int y=6)
{
return x+y;
}
3.2、次序:
默认形参值必须从右向左顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。
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); //错误
3.3、调用位置:
调用出现在函数体实现之前时,默认形参值必须在函数原形中给出;而当调用出现在函数体实现之后时,默认形参值需在函数实现时给出。
int add(int x=5,int y=6);//提前声明函数原型的话要加默认值
void main(void)
{ add(); //调用在实现前
}
int add(int x,int y)
{ return x+y; }
int add(int x=5,int y=6)
{ return x+y; }
void main(void)
{ add(); //调用在实现后
}
4、默认形参的作用域
在相同的作用域内,默认形参值的说明应保持唯一,但如果在不同的作用域内,允许说明不同的默认形参。
int add(int x=1,int y=2);
Int z=10;
void main(void)
{ int z=5;
int add(int x=3,int y=4);
add(); //使用局部默认形参值(实现3+4)
}
void fun(void)
{ ...
add(); //使用全局默认形参值(实现1+2)
}
4、函数重载
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);
下面是一些错误的情况
//编译器不以形参名来区分。函数重载是在编译阶段,但如果用形参来区分需要在运行的阶段,所以不行。
int add(int x,int y);
int add(int a,int b);
//编译器不以返回值来区分
int add(int x,int y);
void add(int x,int y);
不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:
5、函数指针和指针函数
5.1 函数指针
在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。
int* func(int x); // 声明一个函数
int* (*f) (int x); // 声明一个函数指针 ,返回值为int*,形参只有一个int
f=func; // 将func函数的首地址赋给指针f
5.2 指针函数
一个函数不仅可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。
(int *) f(x,y);