#includeusing namespace std; int GetSize(int data[]) { return sizeof(data); } int main() { int data1[] = {3, 5, 1, 4, 2}; int size1 = sizeof(data1); cout << "size1 = " << size1 << endl; int *data2 = data1; int size2 = sizeof(data2); cout << "size2 = " << size2 << endl; int size3 = GetSize(data1); cout << "size3 = " << size3 << endl; return 0; }
打印结果:
size1 = 20 size2 = 8 size3 = 8 Process finished with exit code 0
- data1是一个数组,sizeof(data1)是求数组的大小。这个数组包含5个整数,每个整数占4个字节,因为总共是20个字节。
- data2声明为指针,尽管它指向了数组data1,对认真指针求sizeof,得到的结果都是8。
- 在C/C++中,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。因此尽管函数GetSize的参数data被声明为数组,但它会退化为指针,size3的结果仍然是8。
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
int a[] = {0,1,2}; // 含有三个整数的数组
int s2[] = a; // 错误:不允许使用一个数组初始化另一个数组
a2 = a; // 错误:不能把一个数组直接赋值给另一个数组
2、使用数组是通常将其转化成指针
在C++语言中,指针和数组有非常紧密的联系。使用数组的时候编译器一般会把它转换成指针。
通常情况下,使用取地址符(&)来获取指向某个对象的指针,取地址符也可以用于任何对象。数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。因此像其他对象一样,对数组的元素使用取地址符就能的搭配指向该元素的指针:
string nums[] = {"one", "two", "three"}; // 数组元素是string对象
string *p = &nums[0]; // p指向nums的第一个元素
然而,数组还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
string *p2 = nums; // 等价于p2 = &nums[0]
在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
三、数组作为函数形参数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响。
- 因为不能拷贝数组,所以我们无法以值传递的方式使用数组参数。
- 因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。
尽管不能以值传递的方式传毒数组,但是我们可以把形参写成类似数组的形式:
#includeusing namespace std; void print01(int *arr) { printf("print01---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); } void print02(int arr[]) { printf("print02---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); } void print03(int arr[0]) { printf("print03---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); } void print04(int arr[10]) { printf("print04---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]); } int main() { int arr[] = {3, 5, 1, 4, 2}; printf("数组arr的地址 = arr= %d; 数组arr的地址 = &arr= %d; 数组arr的首元素地址 = &arr[0]= %d; arr的首元素 = *arr = %d; arr的首元素 = arr[0] = %dn", arr, &arr, &arr[0], *arr, arr[0]); print01(arr); print02(arr); print03(arr); print04(arr); return 0; }
打印结果:
数组arr的地址 = arr= -717228336; 数组arr的地址 = &arr= -717228336; 数组arr的首元素地址 = &arr[0]= -717228336; arr的首元素 = *arr = 3; arr的首元素 = arr[0] = 3 print01---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758 print02---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758 print03---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758 print04---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758 Process finished with exit code 0
-
尽管表现形式不同,但上面的4个函数是等价的:每个函数的唯一形式都是int类型的。当编译器处理对print函数的调用时,只检查传入的参数是否是int类型。
-
如果我们传给print函数的是一个数组,则实参自动地转换成指向数组首元素的指针,数组的大小对函数的调用没有影响。
-
和其他使用数组的代码一样,以数组作为形参的函数也必须确保使用数组时不会越界。
- 数组作为函数参数,传值还是传址?
- 函数参数中的数组元素个数能否确定?
#includeusing namespace std; void testArrayArg(int a[]) { cout << endl; cout << "testArrayArg---->a地址: " << a << endl; cout << "testArrayArg---->a大小: " << sizeof(a) << endl; cout << "testArrayArg---->a元素数量: " << sizeof(a) / sizeof(a[0]) << endl; cout << "将第4个元素的值改变为10。" << endl; a[3] = 10; } int main() { int arr[] = {1, 2, 3, 4, 5}; cout << "main---->arr地址: " << arr << endl; cout << "main---->arr大小: " << sizeof(arr) << endl; cout << "main---->arr元素数量: " << sizeof(arr) / sizeof(arr[0]) << endl; testArrayArg(arr); cout << endl << "第4个元素的值 = " << arr[3] << endl; return 0; }
打印结果:
main---->arr: 0x9b92dff690 main---->arr地址: 0x9b92dff690 main---->arr大小: 20 main---->arr元素数量: 5 testArrayArg---->a地址: 0x9b92dff690 testArrayArg---->a大小: 8 testArrayArg---->a元素数量: 2 将第4个元素的值改变为10。 第4个元素的值 = 10 Process finished with exit code 0
当我们直接将数组arr作为参数调用testArrayArg()时,实参与形参的地址均是0x9b92dff690。并且,在testArrayArg()中将a[3]的值修改为10后,返回main()函数中,a[3]的值也已经改变。这些都说明:
- C++中数组作为函数参数是传址。
- 特别需要注意的是,在main()中,数组的大小是可以确定的。
main---->arr大小: 20 main---->arr元素数量: 5
- 但数组作为函数参数传递后,其大小信息丢失,只剩下数组中第一个元素的信息。这是因为C++实际上是将数组作为指针来传递,而该指针指向数组的第一个元素。至于后面数组在哪里结束,C++的函数传递机制并不负责。
testArrayArg---->a大小: 8 testArrayArg---->a元素数量: 2
- 上面的特性可总结为,数组仅在定义其的域范围内可确定大小。
- 因此,如果在接受数组参数的函数中访问数组的各个元素,需在定义数组的域范围将数组大小作为另一辅助参数传递。则有另一函数定义如下:
void testArrayArg2(int a[], int arrayLength) { cout << endl << "the last element in array is: " << a[arrayLength - 1] << endl; - 可在main()中这样调用,这样,testArrayArg2()中便可安全地访问数组元素了:
testArrayArg2(a, sizeof(a) / sizeof(a[0]));
参考资料:
详谈C++中数组作为函数参数
C++数组作为函数参数的几个问题
C++数组作为函数参数



