数组名取地址十分好玩,在这里记录一下,如果大家有不同见解,欢迎留言探讨:
在大多数情况下,数组名都会默认转换为指向数组的第一个元素的指针。这一点相信大家都知道。比如下边的例子:
int array[3] = {1,2,3}; cout << *array << endl; cout << array[0] << endl;
上边的两个输出的值是相同的,这个时候array作为数组名默认转换为指向数组的第一个元素的指针。对数组名称进行解引用得到的是数组的第一个元素的值。因此两个输出语句的值时相同的。
当数组名作为取地址操作符的操作数的时候情况比较有意思,这个时候数组名不是默认转换为数组的第一个元素的指针。下边来用例子稍微验证一下。
(1)对数组名作为取地址操作符的操作数得到的值和数组名默认转换成指向第一个元素的指针的值相同。
int array[3] = {1, 2, 3}; int *ptr = &array; cout << "array = " << array << endl; cout << "ptr = " << ptr << endl;
这个时候我们编译的话,编译器一般都会报错的,如下所示。这个时候我们看一下报错的信息就可以知道对数组名取地址得到的结果其实是一个: int(*)[3] ,表示的是这个指针指向的是整个数组对象,也就是说这个指针指向的是:数组起始地址开始的,以 数组长度和sizeof(int)乘积为宽度的一个数据对象(我是这么理解的,大家如果有不同的见解可以在下边留言一起讨论)。sizeof(int)是针对例子程序来分析的,不同的数据类型需要我们更换sizeof的操作数。
(2)对于例子1种的报错信息,我们更换ptr的声明方式来修正一下上边的例子:
int array[3] = {1, 2, 3}; int (*ptr)[3] = &array; cout << "array = " << array << endl; cout << "ptr = " << ptr << endl; cout << "ptr+1 = " << (ptr + 1) << endl;
运行结果如下:
对于(1)种的报错信息,我们还可以进行下边的修正:
int array[3] = {1, 2, 3}; int (*ptr)[3] = &array; int *ptr2 = (int*)&array; cout << "array = " << array << endl; cout << "ptr = " << ptr << endl; cout << "ptr2 = " << ptr2 << endl;
输出结果如下:
这两种修正方式得到的指针的值时相同的,但是这两个指针的意义却又不尽相同,参照下边的代码:
int array[3] = {1, 2, 3}; int (*ptr)[3] = &array; int *ptr2 = (int*)&array; cout << "array = " << array << endl; cout << "ptr = " << ptr << endl; cout << "ptr2 = " << ptr2 << endl; cout << "ptr+1= " << (ptr + 1) << endl; cout << "ptr2+1=" << (ptr2 + 1) << endl;
输出的结果如下:
可以看到,虽然array和ptr的值是相同的,但是使用指针加一得到的结果却是完全不同的。对于未经强制转换得到指针的值加一得到的是以整个数组为基本单元,向后移动数组大小的空间得到的指针值。对于强制转换的指针加一相当于偏移一个整形指针的长度。
指针取地址之后的指针值是和普通的指针是不一样的,这个时候的加上1之后的偏移量是一个数组的空间大小。
另外一个数组比较特殊的就是sizeof操作符。sizeof操作符的操作数是数组名的时候,得到的是整个数组的大小,即: int array[10]. sizeof(array)/sizeof(int) = 10;