学习C++数组的时候,对数组的了解不是很深。也不知道,为什么声明一个数组,int a[10],为什么a就是数组的地址。
你可以这样理解,将a理解为指向数组头的一个指针,这样就好理解了。理解了之后确实好像豁然开朗的样子。这样a[5]就等于*(a+5),也就相当于将数组头指针向后推5个位置,然后取到该位置的数据了。仿佛一切都很完美。
可是当我对C++使用的越多的时候,就会发现这个理解越来越多纰漏。
我们知道,如果我们有一个int数组a[10],sizeof(a)会求出40。相信不少人都会写过以下的代码吧
int arraySize(int a[]) {
return sizeof(a)/sizeof(int);
}
我们想要求一个数组的长度,但是当我们用这个函数来求数组的长度的时候,会发现要么输出1要么输出2。为什么会这样呢?
我们在C++面试的时候会遇到这样的题目
int a[5] = {1,2,3,4,5};
int* p1 = (int*)(&a+1);
int* p2 = (int*)(a+1);
cout << *(p1-1) << " " << *(p2-1) << endl;
问输出什么?
大家都知道输出时5和1,那大家有没有尝试去理解一下为什么是这样呢?
为了解决这个问题,我写了一段代码进行测试:
#include<iostream>
#include <typeinfo>
using namespace std;
#define type(a) typeid(a).name()
int main() {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
cout << "a=" << a << " &a=" << &a << endl;
int* p1 = (int*)(&a+1);
int* p2 = (int*)(a+1);
cout << "*(p1-1)=" << *(p1-1) << " *(p2-1)=" << *(p2-1) << endl;
cout << "sizeof(a)=" << sizeof(a) << " sizeof(&a)=" << sizeof(&a) << endl;
cout << "TypeOf(a)=" << type(a) << " TypeOf(&a)=" << type(&a) << endl;
}
运行结果如下:
我们可以看到,一个数组a[10],a的值和&a输出的值是一样的。
但是对a+1和对&a+1却会得到不同的结果。
对他们分别用sizeof函数取大小,发现a占用了40个字节,&a占用了8个字节。
最后我们查看a和&a的类别,发现a是A10_i类型的,而&a是PA10_i类型的。
这说明了什么?
说明了数组名a并不是一个int型的指针,而是一个新的数据类型,是一个A10_i类型,代表大小为10的int型的数组。而A10_i这个数据类型是会在内存中连续占用10个int型的空间,所以sizeof(a)会返回一个10*4的结果。而&a是一个PA10_i类型,就是指向A10_i数据类型的一个指针,一个指针的大小当然为8了。(根据系统的位数不同而不同)。
那为什么a和&a的输出值相等呢?这是因为a是一个A10_i的数据类型,输出的时候会把里面的数组的头地址输出出来。而&a时指向A10_i的一个指针,A10_i的地址就等同于他里面包含数组的头地址,所以两者会相等。
而&a+1与a+1得到的结果不相等,是因为a相当于一个指向int元素的指针,a+1会加上sizeof(int)的大小。而&a是一个指向A10_i的指针,&a+1会加上sizeof(A10_i)的大小,而sizeof(A10_i)=40,所以就可以解释为什么两者不同了。
至于为什么我们想写一个函数来求数组的长度的时候会失败,原因是我们的函数接收参数是一个真真正正的int型指针,在传入参数时会进行类型转换,将PA_i类型转化为int型指针,对int指针进行sizeof当然求得指针本身的大小。只有对数组名这个数据类型进行sizeof求大小才能够求得数组本身的大小。
说到底,就是数组名并不等同于一个指针。数组名是一个我们平常不能显式声明的数据类型,只不过里面包含了一个指针,指向数组的头部。
如果你也想成为一名程序员那就关注我与我交流,不管是零基础还是入门小白学习,要有个相互监督的伙伴!关注小编的专栏,手把手教你如何实现!工作需要、感兴趣、为了入行、转行需要学习C/C++的伙伴可以跟我学习,技术大牛助你早日成为一名优秀的程序员!
程序猿zhuanlan.zhihu.com