第7章 函数
1. 函数的基本知识
要使用函数,必须完成这3种工作:提供函数原型、提供函数定义、调用函数
函数分类:有返回值函数和没有返回值函数
C++对于函数返回值类型的限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针、结构和对象
函数原型:描述函数到编译器的接口,将函数返回值类型以及参数类型和数量告诉编译器。避免使用原型的唯一方法就是在首次使用函数之前定义它,但这并不总是可行的。原型参数列表中可以不包括变量名。另外原型自动将被传递的参数强制转换为期望的类型。
2. 函数参数和按值传递
用于接收传递值的变量称为形参, 传递给函数的值称为实参。函数声明的变量(包括参数)是该函数私有的。
函数可以有多个参数,只需使用逗号将这些参数分开即可
3. 函数和数组
给函数传递数组,通常要传递数组长度,这样为使函数通用,而不限于特定长度的数组。
由于数组名和指针一样,所以参数int *arr和int arr[]一样,都是接受一个int类型数组。传递数组,函数使用的是原本数组元素,因为传递的是数组首元素的地址,这样节省了传递整个数组的时间和内存,但是增加了破坏原始数据的危险,但是const修饰符解决了这种问题。
还有另一种给函数提供所需信息的方法:指定元素区间,通过传递两个指针,一个标识开头,一个标识数组的尾部(最后一个元素后面的指针)。
指针和const:如果数据类型本身不是指针,则可以将const数据或非const数据的地址赋给指向const的指针,但只能将非const数据的地址赋给非const指针。如果数据类型是指针,const和非const混合指针赋值方式将不再安全。
4. 函数和二维数组
//已有一个原型
int sum(int (*ar2)[4], int size); //int(*ar2)[4]等价于int ar2[][4],指出它指向一个由4个int组成的数组
//所以说参数ar2是一个指向数组的指针
//size指定二维数组行数,所以列数固定了
//const只能用于指向基本类型的指针,对于指向指针的指针使用const不安全
5. 函数和C风格字符串
表示字符串的方式有3种:char数组、引号括起的字符串常量、设置为字符串地址的char指针
将C风格字符串作为函数参数:由于C风格字符串末尾以空字符结尾,所以不用传递字符串长度给函数。
函数返回C风格字符串:返回指向字符串的地址,返回一个指针
6. 函数和结构
函数接受结构参数:按值接受结构、传递结构地址,引用。
函数按值传递结构,函数将使用原始结构的副本,如果结构非常大,则复制结构会增加内存,降低系统运行速度,所以这种按值传递适用于结构较小。
传递结构地址,调用函数时,将结构的地址而不是结构本身传递给函数,防止更改结构数据可加上const修饰
7. 函数和string对象
传递string对象和结构相似。
8. 函数和array对象
array<double, 4> expenses; //已有一个array对象
//处理array对象的函数定义应该是这样
void show(array<double, 4> da); //传递array对象
void fill(array<double, 4> *pa); //传递array对象地址
9. 递归
递归:函数自己调用自己。递归函数为了防止自己调用自己无限循环下去,一定要有一个终止条件。
10. 函数指针
函数也有地址,它的地址是存储在其机器语言代码的内存的开始地址。
传递函数的地址,意味着可以在不同的时间使用不同的函数。
获取函数的地址:函数名就是函数的地址。
声明函数指针:必须确定指针所指向的函数类型,意味着声明应指定函数的返回类型以及函数的特征标(参数列表)。
int (*ptr)(double); //ptr就是个函数指针,它所指向函数返回int值,接受一个double参数,*ptr就是函数
使用指针调用函数:就上面函数指针为例,可以(*ptr)(1.1)调用函数,也可以ptr(1.1)来调用函数。
使用C++11的关键字auto自动类型推断功能,能自动匹配函数指针所指向函数的类型。
函数指针数组:int (*ptr[3])(double); //由于[]的优先级高于 *,所以这是一个指向特定类型函数的指针数组。注意:这里不能使用auto自动类型判断,auto只能用于单值初始化,而不能用于初始化列表。
为了简化声明,可以使用关键字typedef来为特定类型创建别名。