高质量程序设计指南c++/c语言(31)--数组形参
数组有两个特殊的性质,影响我们定义和使用作用在数组上的函数:一是不能复制数组,而是使用数组名字时,数组名会自动转化为指向其第一个元素的指针。因为数组不能复制,所以无法编写数组类型形参的函数。数组会自定转化为指针,所以处理数组的函数通常通过操纵指向数组中的元素的指针来处理数组。
1、数组形参的定义
void printValues(int *){} void printValues(int []){} void printValues(int [10]){}
上面三个函数定义时完全等价的,形参类型都是int *
2、形参的长度会引起误解
编译器忽略为任何数组形参指定的长度。
#include<iostream> using namespace std; void printValues(const int a[10]) { int i; for(i=0; i<10; i++) { cout << a[i] << endl; } } int main(void) { int i=0, j[2] = {0,1}; printValues(&i); //运行时错误 printValues(j); //运行时错误 return 0; }
虽然编译都没有问题,但是这两个调用都是错误的,可能导致运行时失败。在这两个调用中,由于函数printValues假设传进来的数组至少含有10个元素,因此造成数组内存的越界访问。程序的执行可能产生错误的输出,也可能崩溃,这取决于越界访问的内存中恰好存储的数值是什么。当编译器检查数组形参关联的实参时,它只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,而不会检查数组的长度。
3、数组实参
和其他类型一样,数组形参也可以定义为引用类型或非引用类型。大部分情况下,数组以普通的非引用类型传递,此时数组会悄悄的转化为指针。一般来说,非引用类型的形参会初始化为相应实参的副本。而在传递数组时,实参是指向数组第一个元素的指针,形参复制的是这个指针的值,而不是数组元素本身。函数操纵的指针的副本,因此不会修改实参指针的值。然而,函数可以通过该指针修改它所指向的数组元素的值。
4、通过引用传递数组
如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器会检查数组实参的大小与形参的大小时候匹配。
#include<iostream> using namespace std; void printValues(int (&arr)[10]) { } int main(void) { int i=0, j[2] = {0,1}; int k[10] = {0}; printValues(&i); //error:argument is not an array of 10 ints printValues(j); //error:argument is not an array of 10 ints printValues(k); //ok return 0; }
5、多维数组的传递
和一维数组一样,多维数组是以指向0号元素的指针方式传递的。多维数组的元素本身就是数组。除了第一位以外的所有维的长度都是元素类型的一部分,需要明确指定:
void printValues(int (*matrix)[10], int rowSize); void printValues(int matrix[][10], int rowSize);
上面的语句是等价的,将matrix声明为指向含有10个int型元素的数组的指针。