数组名和指针的区别和联系、数组名取地址&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和指针p的构成是很相似的。它们实际存的都是一个地址,都会指向一个对象(或多个对象的第一个对象)。所以说数组名其实是种特殊的指针。
- 但它俩自身又有不同,指针本身是一个对象,在内存中是为其分配了空间的;但数组名在内存空间中没有分配到空间(这将导致
&a
操作的效果可能和预想的不大一样)。
数组名a、数组名取地址&a、数组首元素地址&a[0]、指向数组首元素的指针*p
-
a
既然是种特殊的指针,那么其打印时就会是存的地址。 -
&a
的类型是int(*)[5]
(读法从小括号里往外,首先是指针,然后是大小为5的数组,然后数组元素类型是int),从局部变量中看到其类型也可写成int[5] *
:即指向大小为5的int数组的指针。由于数组名没有内存分配空间,所以&a
取地址还是取到的是数组首元素的地址。 -
&a[0]
就是取一个int对象的地址,这个int对象是数组首元素。综上所述,就造成了a &a &a[0]
三者打印出来的地址是一样的。 -
p
,指向数组首元素的指针。 -
a + 1,p + 1
都是按照元素大小的字节数(4字节),增加4。 -
&a + 1
,前面说了&a
的类型是指向大小为5的int数组的指针,大小为5的int数组所占字节数为20,所以&a + 1
就应该增加20。 -
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都必须指向数组中的元素。
上一篇: 数组名和&数组名的地址
下一篇: 数组名是首元素地址吗?