来自 http://community.youkuaiyun.com/Expert/topic/3142/3142075.xml?temp=.2214624
举个例子,有如下一个数组:
int a[10][10];
如果想得到数组a的首地址,我们可以使用这样的语句:
printf("a:/t%p/n", a); // 1
这样,在显示屏上就可以输出该数组的十六进制首地址了。一般而言,这个首地址是位于栈上的。
事实上,数组名a只是一个别名,它代表了一个地址常量。打印a的值,实际输出的就是它代表的地址值。通常在使用a的时候,我们可以把它当作数组来看待,使用下标运算符[]来寻址其中的元素;也可以把它当作地址来看待,使用取值运算符*来寻址其中的元素。比如:
a[0][0] 等价于 *(*a)
然而,要得到数组的首地址,方法有很多,并不限于打印数组名对应的地址值。还可以使用如下语句来输出数组首地址:
printf("&a[0][0]:/t%p/n", &a[0][0]); // 2
这个办法学过C的人都应该知道,因为数组中第一个元素总是分配在数组的最前头,因为它的首地址也必然与数组的首地址相同。但是,要注意的是,这两个地址只是值相同,而它们的数据类型并不相同!!!!
让我们换一种输出方式,就可以让它们数据类型的不同显现出来。方法如下:
printf("a+1:/t%p/n", a+1); // 3
printf("&a[0][0]:/t%p/n", &a[0][0]+1); // 4
通过观察打印值,可以发现a+1的地址值比a的地址值多出了40个字节,而&a[0][0]+1却只比&a[0][0]多了4个字节。也就是说,a+1一下子跳过了10个整型元素(每个元素占4字节),而&a[0][0]+1只跳过了1个整型元素。
嘿嘿,发现了吗?虽然首地址相同,可是首地址的数据类型,却并不相同。
a的地址的数据类型,是int (*)[10]。它指向拥有10个元素的一维数组,其中每一个元素的数据类型又是拥有10个元素的一维数组。我们知道,a[0]与a[1]的不同,其实就是跳过了一个元素。而a[0]与*a实际是等价的(在实际使用数组时,通常会退化为对其地址--类似一个指针--进行操作),a[1]与*(a+1)也是等价的。因此,对a+1而言,应该跳过一个元素,即实际输出a+1对应的地址值时,应该跳过40个字节(最后一维数组中的元素个数*每个元素大小)。
而a[0][0]的数据类型是int,对应地,&a[0][0]的数据类型是int *。按上面说过的,&a[0][0]+1实际上就只跳过了一个整型值占用的字节数,即4字节。
所以咯,下面的东东就不说作很详细的说明了,我只给出它们对应的数据类型,大家不理解的话就多从它们的数据类型下手去思考吧。
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
int a[10][10];
printf("a:/t%p/n", a); // int (*)[10] 或者是 int [][10]
printf("a+1:/t%p/n", a+1); // int (*)[10]
printf("&a:/t%p/n", &a); // int (*)[10][10] 或者是 int [][10][10]
printf("&a+1:/t%p/n/n", &a+1); // int (*)[10][10]
// printf("&&a:/t%p/n", &&a); // 不可能
// printf("&&a+1:/t%p/n/n", &&a+1); // 不可能
printf("a[0]:/t%p/n", a[0]); // int * 或者是 int []
printf("a[0]+1:/t%p/n", a[0]+1); // int *
printf("&a[0]:/t%p/n", &a[0]); // int (*)[10] 或者是 int [][10]
printf("&a[0]+1:/t%p/n/n", &a[0]+1); // int (*)[10]
printf("&a[0][0]:/t%p/n", &a[0][0]); // int * 或者是 int []
printf("&a[0][0]+1:/t%p/n/n", &a[0][0]+1); // int *
system("PAUSE");
return 0;
}
仔细观察,呵呵,有规律可循的。
如果还有什么问题,或者是有什么错误,大家都可以提出咯。