hello,everybody。
直接进入主题把。
现有一个二维数组 int a[5][5];
a, &a ,a[0], &a[0] 这四个都分别代表什么呢?
答: 首先在 二维数组里 数组名 始终代表该数组的行指针。为什么要这样说呢?
我给你从底层分析把,首先 a[1][1]是不是等价于*(*(a+1)+1) 对这个没有疑问把
然后呢... 这样是不是可以很明显的看到a是个行指针 对啊 已经和明显了 还不理解啊?好吧 那我再举个例子把。
a[2][3]等价于*(*(a+2)+3) 这样理解了吧 。 a 即就是a+0 代表着是第一行 ,那么 a+2 就移动到了第三行。
是的,我就是这样给你们证明出 对于二维数组来讲,数组名即就是行指针。那么a就是代表第一行的行指针了
(1)a代表什么
那么很好理解了 a+2代表第二行的行指针 看下列我给出的公式 那么 *(a+2)是不是就等于列指针了呢?对吧。
行指针 | 列指针 |
*行指针=列指针 | &列指针=行指针 |
(2)&a代表什么意义
说完了a ,接下来又是个&a ,刚才说a是行指针,那么&a又是什么鬼鬼?
&a几乎没啥意义 这里大家只要弄懂&a+1 跟 &(a+1)的区别就行了
eg: int a[2][2]
首先&a 是整个数组块的首地址 那么 &a+1 得到的内存地址就是 a[1][1]后面的地址了
然后 &(a+1)这样的写法就是错的 为什么说他是错的呢? a+1之后a跑到第二行了 这时他还是个行指针 之后 你再&行指针 就没有这种用法
必须先把(a+1)转化成列指针 即再前面加个* 号,然后才能取地址。说没有这种用法说的是不是有点牵强,是不是觉得接受不了,我也接受不了,可是编译器就是不认啊,就是认为他错了。好了 ,那再详细分析下把,为什么是错的呢?因为行指针已经是底层指针了啊 还要取地址 ,你要编译器上哪里给你取地址啊。 举个最简单的例子 int *p;这是一个指针变量吧,对,没问题
那么我可以&p 拿到指针变量自己的地址 ,那我还能再加个&符号吗? 比如这样&&p; 仔细想想 这样是不是很明显的错误了。已经到最底层了,没法取地址了。
看到我举得例子没 ,第一行数据是a的首地址转化为十进制的数据 ,第二行通过跟第一行比较 大了16个内存地址,刚好是4个int的大小。这样很直观的反应了 &a+1就是二维数组内存块最后的地址的下一个地址了。
用图片说明一下把~~~。
第三行是 a+1是第二行的地址 ,即为行指针 不能直接取地址,刚才解释的很清楚了,然后带个*,成了列指针,然后再& 即又是行指针。。哈哈~~变来变去 有意思 。其实还可以这么理解,因为 & 跟*抵消了。所以他还是个行指针。
(3)a[0] 又代表什么呢?
对没错了,首先它等价于*(a+0)那么很好理解了 ,他是个列指针 。
(4)&a[0]又代表什么呢?
由公式不难得到 &列指针=行指针 ,那么很简单了 &a[0]代表了一个行指针 ,他指向数组的第一行首地址。
最后介绍下单维度数组 eg; int a[5];
对于单维度数组,数组名等价于列指针 为什么?你可以把他看作一行,然后移动指针 比如 *(a+1)=>a[1],*(a+2)=>a[2] 是不是很明显觉得就是这样呢?为什么我要告诉大家这样子呢?因为 这样的话就很好理解对于单维度数组 &数组名 的意义了。 而且正好可以运用给的公式 &列指针=行指针;
如果你 int a【5】,然后执行代码 &a+1(用公式很容易得出这是个行指针) 编译器会提示你这段代码有警告为啥呢。因为它由首地址移动到第二行的行首地址了 ,而对于单维度数组,第二行没有的地址根本没有定义呢,所以会警告的。
对于单维度数组来讲,你也可以把他看作一个特殊的二维数组,把他的每个元素想象成一块内存地址,可以放好多值,但是它每个元素 的那一块内存地址只存了一个值。
为什么我要这么理解呢?其实我这样说时有根有据的,当你动态申请二维数组的时候,你现在回想下过程是不是很类似呢?
以下是动态申请二维数组c【5】【5】的大致过程
int ** c=(int**)malloc(sizeof(int*)*5);
for(int a=0;a<5;a++)
{
c[a]=(int *)malloc(sizeof(int)*5);
}
好了,对于数组就先分析到这里,如果以后还有补充的...
总结:
对于单维度数组:数组名等价于列
指针,
对于二维数组,数组名等价于行指
针。