在C++中传递数组参数是一件很简单的事情,但是这里面也有一些需要注意的细节,不能忽视,(只能说C++太难了,也太好玩了)。
数组形参
在这个里面,数组是作为形参传递的,有以下几种:
void printArr(int*) {/* ... */}
void printArr(int []) {/* ... */}
void printArr(int [10]) {/* ... */}
这三种达到的目的是一样的,也是等价的,都会被看做int *
形参的长度会引起误解
编译器会忽略任何数组形参指定的长度的,根据数组的长度(权且这样说),可以在函数内部遍历数组:
void printArr(const int a[10]){
for(size_t i = 0; i != 10; i++){
cout<< a[i] <<endl;
}
}
这里我们已经知道,编译器会忽略数组的长度,但是我们在形参写了长度,这样我们就默认使用了这个长度(会出现一些不可控的问题)。
例如,如下的调用都是合法的:
int main(){
int i =0, j[2] = {0,1};
printArr(&i); //ok! &i 是 int *, 但是运行会出现越界。
printArr(j); // ok! j 会被转换为 int *, 但是也会越界。
return 0;
}
这里虽然编译没问题,但是调用和运行都是有问题的。
数组实参
和其他类型一样,C++比C多了引用类型,(这里强调一下,标准C99版本的C语言是没有参数引用的)。数组形参可以定义为引用或非引用类型。大部分情况如下,数组以普通的非引用类型用作类型传递,此时数组会悄悄的转换为指针,一般来说,非引用类型的形参会初始化为其相应的实参副本,而在传递数组时,实参是指向数组的第一个元素的指针,形参是复制了指针的值,改变的是指针指向的值,并没有更改指针本身的值。
通过引用来传递数组
数组形参可以声明为数组的引用,如果形参是数组的引用,编译器不会把数组实参转化为指针,而是传递数组本身,这种情况下,数组大小成为形参和实参类型的一部分,编译器会检查数组的大小。
void printArr(int (&a)[10]) { /* ... */ }
int main(){
int i = 0, j[2] = {0,1}, k[10] = {0};
printArr(&i); // error!
printArr(j); //error!
printArr(k); // ok!
return 0;
}
这个版本,会严格检查数组的大小。
多维数组的传递
在C++中本来没有多维数组,所以其实多维数组,就是数组中的数组。
这里区分下数组指针和指针数组的问题:
1. 数组指针,是指针。 int (*a)[10];
2. 指针数组,是数组。 int *a [10];
详情看我的博客:C++学习 - 数组指针/指针数组.
除了第一维以外的所有维的长度都是元素类型的一部分,必须明确指定。
上面这句话很重要,它说明了传递多维数组参数必须的形式。
例子:
void printArr( int (*a)[10], int rowSize );
上面这个语句,括号是省不了的,一定要加上。假如不加的话。
void printArr( int a[][10], int rowSize );
一定要这样写才行。
传递给函数的数组处理
非引用的数组形参,只是检查类型,确保实参是和数组元素具有同样类型的指针,而不会检查实际上是否指向数组指定大小。
有三种常见的办法来保证函数的操作,不会让数据实参越界操作。
标记结束
第一种是在数组本身防止一个标记来检测数组的结束,C风格的字符串是以null为结束标记的。
标准库方法
第二种是传递指向数组第一个和最后一个元素的下一个位置的指针,这种变成风格是由标准库所使用的技术。例如:
void printArr(const int *beg, const int *end){
while(beg != end){
cout << *beg++ <<endl;
}
}
int main(){
int j[2] = {0,1};
printArr(j, j+2);
return 0;
}
这种循环很像用vector
迭代器编写的程序。
显示传递数组大小
第三种方法就是把第二个方法中的结尾指针,变成数组的大小,这种方法在C程序和标准化之前的C++程序是十分普遍的。
void printArr(const int a[], size_t size){
for(size_t i = 0; i != size; ++i){
cout << a[i] << endl;
}
}
int main(){
int j[] = {0,1};
printArr(j, sizeof(j)/sizeof(*j));
return 0;
}
这个版本是用来形参size来确定要输出的元素个数,这样size可以控制访问数组的范围,size不能超过实际大小,程序就能安全运行。
以上。