数组名和指针的区别和联系、数组名取地址&a

前言

  • 在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向该数组首元素的指针。
  • 所以,在大多数表达式中,使用数组名其实是在使用一个指向该数组首元素的指针。

数组名其实是种特殊的指针

int main()
{
	int a[] = { 0,1,2,3,4 };
	printf("a is %x\n", a);
	printf("&a is %x\n", &a);
	printf("&a[0] is %x\n", &a[0]);

	int *p = &a[0];
	//int * p1 = &a;
	//上句报错信息:&a的类型为int(*)[5],不能用来初始化int *
	decltype(a) t;
	decltype(&a) tt;
	
	cout << "p is "<<p << endl;
	printf("a + 1,p + 1 are %x,%x\n", a + 1,p + 1);
	printf("&a + 1 is %x\n", &a +1);

	cout << sizeof(a) << " " << sizeof(&a) << endl;
}

在这里插入图片描述
在这里插入图片描述

  1. 从局部变量表可以看出,数组a和指针p的构成是很相似的。它们实际存的都是一个地址,都会指向一个对象(或多个对象的第一个对象)。所以说数组名其实是种特殊的指针。
  2. 但它俩自身又有不同,指针本身是一个对象,在内存中是为其分配了空间的;但数组名在内存空间中没有分配到空间(这将导致&a操作的效果可能和预想的不大一样)。

数组名a、数组名取地址&a、数组首元素地址&a[0]、指向数组首元素的指针*p

在这里插入图片描述

  1. a既然是种特殊的指针,那么其打印时就会是存的地址。
  2. &a的类型是int(*)[5](读法从小括号里往外,首先是指针,然后是大小为5的数组,然后数组元素类型是int),从局部变量中看到其类型也可写成int[5] *:即指向大小为5的int数组的指针。由于数组名没有内存分配空间,所以&a取地址还是取到的是数组首元素的地址。
  3. &a[0]就是取一个int对象的地址,这个int对象是数组首元素。综上所述,就造成了a &a &a[0]三者打印出来的地址是一样的。
  4. p,指向数组首元素的指针。
  5. a + 1,p + 1都是按照元素大小的字节数(4字节),增加4。
  6. &a + 1,前面说了 &a的类型是指向大小为5的int数组的指针,大小为5的int数组所占字节数为20,所以&a + 1就应该增加20。
  7. sizeof(a)为20,因为数组总的字节大小为20。sizeof(&a)为4,因为&a是一种指针,指针在32位系统中占4字节。

指向数组首元素的指针可使用操作符[]

a[1], p[1]都能取出数组的1索引元素。
上面这句的效果和原理和这句*(a + 1),*(p + 1)一样。

对了,你也可以int *p = a,也是指向数组首元素的指针。

指向非首元素的指针使用操作符[]

int *p = &a[2]指向了2索引的元素。
int j = p[1],3索引的元素。相当于*(p + 1)
int k = p[-2],0索引的元素。这里是内置的取下标操作,所以可以用有符号数。(标准库类型取下标的话,则必须使用无符号数)
但一定注意这里的p都必须指向数组中的元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值