欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-11 18:54:37
...

前言

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

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

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;
}

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

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

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

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

  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都必须指向数组中的元素。