执行函数的第一步是(隐式地)定义并初始化它的形参。首先创建一个名为形参名的变量,然后将它初始化为调用时所用的实参的值。
局部对象,static
形参和函数体内部定义的变量统称局部变量。
只存在于块执行期间的对象称为自动对象。
内置类型的未初始化变量将产生未定义的值。
局部静态对象:static类型可以令局部变量的生命周期贯穿函数调用和之后的时间。
如果局部静态对象没有显式的初始值,将会执行值初始化,内置类型会初始化为0.
函数声明
函数只能定义一次,但可以声明多次。
函数的三要素(返回类型,函数名,参数类型)描述了函数接口,函数声明也叫函数原型
函数应在头文件中声明而在源文件中定义。
如果把函数声明放在头文件中,就能确保同一函数的所有声明保持一致。而且想修改函数接口只需要修改头文件中的声明即可,不用去源文件中一个一个修改。
定义函数的源文件应该把含有函数声明的头文件包含进来。
使用引用避免拷贝
拷贝大的类型对象比较低效,或者根本不支持拷贝,此时通过引用形参访问该类型对象比较好。
尽量使用常量引用
把函数不会改变的形参定义为普通引用会给函数的调用者带来一种误导,即函数可以修改它的实参的值。
使用引用而非常量引用也会极大地限制函数所能接受的类型——我们不能吧const对象,字面值或者需要类型转换的对象传递给普通的引用形参。
数组形参
以下三种形式等价,形参都是const int*类型的。(因为数组不允许拷贝,数组会转换为指针)
void print(const int*);
void print(const int[]);
void print(const int[10]);
传的是指针,因此不知道数组尺寸。
当函数不需要对数组元素执行写操作时,数组的形参应该是指向const的指针。
数组引用形参
void print(int (&arr)[10]); //形参是数组的引用,维度是类型的一部分
这么定义,只能将函数作用于大小为10的数组
传递多维数组
多维数组是数组的数组,传递多维数组的时候真正传递的是指向数组首元素(数组)的指针,数组第二维(以及后面的)的大小是数组类型的一部分,因此不能省略。只有第一维可以省略。
void print(int (*matrix)[10], int rowSize);
void print(int matrix[][10], int rowSize);
返回值
返回值用来初始化调用点的一个临时量,该临时量就是函数调用的结果。
不要返回局部对象的引用或指针,因为函数完成后它所占用的存储空间会被释放掉。
调用一个返回引用的函数得到左值,其他返回类型得到右值。
函数重载
默认实参
一旦某个形参被赋予了默认值,他后面所有的形参都必须有默认值
函数声明可以多次,但是一个作用域内一个形参只能被赋予一次默认实参。
函数指针
当我们把函数名作为一个值使用时,该函数自动转换为指针。
int length(int a, int b);
int (*pf)(int, int);
pf = length; //pf指向名为length的函数
pf = &length; //等价的赋值语句,取地址符是可选的。
可以直接使用指向函数的指针调用该函数,无需提前解应用指针。以下三个调用等价。
pf(1, 2);
(*pf)(1, 2);
length(1, 2);
如果定义了指向重载函数的指针,指针类型必须与某一个函数精确匹配。
不能定义函数类型的形参,但是可以是指向函数的指针,且函数形式会自动转换为指针。因此可以把函数直接当实参使用。