1 函数介绍
函数是一个命名了的代码块,通过调用函数执行相应的代码,函数可以有0个或多个参数,而且通常会产生一个结果,可以重载函数,一个函数名对应不同的几个函数
典型的函数定义包括:返回类型(return type)、函数名字、由0个或多个形参(parameter)组成的列表以及函数体
形参以逗号隔开,位于一对圆括号内
函数执行的操作在语句块中说明,该语句块称为函数体(function body)
调用运算符来执行函数
调用运算符的形式是一对圆括号,作用于一个表达式,表达式是函数或者指向函数的指针
圆括号内是一个用逗号隔开的实参列表,用实参初始化函数的形参
调用表达式的类型就是函数的返回类型
- 编写函数
//阶乘例子
int fact(int val){
int ret = 1; // 局部变量,保存计算结果
while(val>1)
ret *= val--; // 把ret和val的乘积赋给ret,然后将val减1
return ret; // 返回结果
}
- 调用函数
调用fact函数,提供一个整数,得到结果也是整数
int main(){
int j = fact(5);
cout << "5!" is "" << j << endl;
return 0;
}
函数调用完成两项工作:
- 用实参初始化函数对应的形参
- 将控制器转移给调用函数,主调函数执行被暂时中断,被调函数开始执行
- 形参和实参
实参是形参的初始值,第一个实参初始化第一个形参,第二个实参初始化第二个形参,以此列推
实参与形参有对应关系,但是没有规定求值顺序,编译器可以以任意可行的顺序对实参求值
实参的类型必须与对应的形参类型匹配
- 函数的形参列表
函数的形参列表可以为空,但是不能省略
定义不带形参的函数,可以使用空列表,也可以使用C语言中的void
形参采用逗号隔开,每个形参都是含有一个声明符的声明,即要写明形参类型
任意两个形参不能同名
- 函数返回类型
大多数类型都可以返回
特殊的返回类型是void,表示函数无返回值
函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针
2 局部对象
名字有作用域,对象有声明周期
名字的作用域是程序文本的一部分,名字在其中可见
对象的声明周期是程序执行过程中该对象存在的一段时间
形参和函数体内部定义的变量统称为局部变量,对函数而言是局部的,仅在函数的作用域内可见
-
自动对象
只存在于块执行期间的对象称为自动对象
形参是一种自动对象,函数开始时为形参申请存储空间,因为形参定义在函数体作用域内,所以函数终止,形参也就被销毁
用传递给函数的实参初始化形参对应的自动对象 -
局部静态对象
有些时候,有必要令局部变量的生命周期贯穿到函数调用之后的时间,将局部变量定义成static类型从而获得这样的对象
size_t count_calls(){
static size_t ctr = 0; // 调用结束后仍有效
return ++ctr;
}
int main(){
for (size_t i=0; i != 10; ++i)
cout << count_calls() << endl;
return 0;
}
ctr被创建并初始化为0,每次调用会递增1并返回
每次执行count_calls函数时,ctr值已存在,并且等于上一次函数退出时的ctr的值
局部静态变量没有显式初始值,则执行值初始化,内置类型的局部静态变量初始化为0
- 函数声明
和其他名字一样,函数的名字也必须在使用之前声明
函数只能定义以此,但可以声明多次
如果一个函数永远不会用到,那么就只有声明没有定义
函数的声明和定义非常类似,唯一区别时没有函数体,用一个分号代替即可
函数声明没有函数体,所以也无须形参的名字,经常可以省略形参的名字,尽管如此,还是建议写上便于理解
函数的三要素(返回类型、函数名、形参类型)描述了函数的接口,说明了调用该函数所需的全部信息,函数声明也称作函数原型
建议变量在头文件中声明,函数也应该在头文件中声明,在源文件中定义
定义函数的源文件应该把含有函数声明的头文件包含进来,编译器负责研制函数的定义和声明是否匹配
- 分离式编译
对于复杂的程序,可以采用分离式编译和链接多个源文件