1 传递数组给函数
数组的两个特殊性质决定了数组在函数作用中的特殊性:
- 性质1:不允许拷贝数组。因此不能以值传递的方式将数组传给函数。
- 性质2:使用数组时(通常)会将其转换成指针(指向首元素地址)。因此向函数传递数组时,实际上传递的是指向数组首元素的指针。
1.1 传递数组形参的三种写法
尽管不能以值传递的方式传递数组给函数,但我们可以把形参写成形式上的数组形式。此时如果我们直接传给函数的是一个数组(而不是显式的指向数组首地址的指针),根据使用数组时的自动转换原则,编译器也会让实参(传进去的数组名)自动地转成指向数组首元素的指针。
范例:
//虽然形式不同,但以下三个函数等价,因为每个函数的形参类型(忽略形参名)其实都是const int *类型
void print(const int *);
void print(const int[]);
void print(const int[10]) //以上三个写法,int和*或[]之间有没有空格都是正确的
//请特别注意,以上三个函数声明中,显式声明其形参名的写法应该如下
void print(const int *arr);
void print(const int arr[]);
void print(const int arr[10]);
//后两种写法要特别注意不要错误写成以下形式
void print(const int[] arr); //❌
void print(const int[10] arr); //❌
//编译器处理对print函数的调用时,只检查传入的参数是否是const int *类型
int i = 0, j[2] = {
0, 1};
print(&i); //正确,&i的类型是int *,int *对象(实参)可以用来初始化const int *对象(形参)
print(j); //正确,使用数组j时,自动将数组名(j)转换成指向数组首元素的指针(int *)类型,也就是说j现在其实是一个指向j[0]的int *对象,当然也可以用int *对象(实参j)来初始化const int *对象(形参arr)
1.2 传递数组尺寸给函数
因为数组是以指针的形式传递给函数的,所以一开始函数并不知道传入数组的确切尺寸,因此,需要把数组尺寸通过额外的信息传递给函数,这主要有三种方法:
1.2.1 使用标记指定数组长度
这种方法要求数组本身包含一个结束标记,该方法不需要传参时传递代表尺寸的额外信息。典型范例是C风格字符串,因为C风格字符串存储在字符数组内,且在最后一个字符后还有一个空字符作为结束标记,函数在处理C风格字符串时遇到空字符则停止,范例:
void print(const char *cp) {
if (cp) {
//若cp不是一个空指针
while (*cp) {
//只要指针cp所指的字符不是空字符
cout << *cp++; //输出当前字符(先cout *cp),并将指针向前移动一个位置(再cp++)
}
}
}
1.2.2 使用标准库规范
这种方法通过向函数传递指向数组首元素和尾后元素的指针来间接传递数组的尺寸并实现对数组的操作,这是标准库技术中的常用规范:
void print