数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)

指针进阶-TWO
屁话不多说,自接上题目

#include int main(void) { int a[] = { 1,2,3,4 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (int*)((int)a + 1); printf("%x,%x\n", ptr1[-1], *ptr2); return 0; }

这两个指针一看过去,相当令人头大,我们可以一步一步去化简。
a是一个有4个元素的一维数组,来具象化,也就是画图,更直观。
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

再来看题目
int* ptr1 = (int*)(&a + 1);
printf("%x\n", ptr1[-1]);
使用了一个指针来接受。来看(&a+1),这个 我们前两篇文字已经说了
除了
&数组名
sizeof(数组名)
这两种情况,表示整个数组,其余的情况都代表首元素地址。
而这个得到这个元素的地址后再加1,而且还说过代表整个数组是整个打包的意思包括内存。则&a+1直接跳一个数组的大小,看图吧。
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

现在够清楚了吧。在就是 (int*)(&a + 1)。
(int*)代表强制转换类型的意思。是将这个数据变量的类型转换成另一种类型。还有这虽然是整型数组,里面元素是整型。但是&a可不是元素,也不是整型指针。确切的说,是一个数组,而要一个指向数组的指针,应该是叫-----数组指针(int* p[]),这才是&a的指针类型。这和(int*)指针的访问权限可不一样,数组指针可以访问整个数组长度,而整型指针只能访问4个字节。
将其强转成(int*),改变了访问权限。
还赋给ptr1.
ptr1[-1]----(prt1-1)
是一样的。而ptr1又在&a+1的位置,ptr1-1因为指针是int
,所以只能访问4个字节,向左移动了4个字节,也就是一个元素,到了a[3]的位置,得到其地址,再解引用,得到地址上的元素,也就是a[3]==4,再以16进制打印还是4
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

下一个
int* ptr2 = (int*)((int)a + 1);
printf("%x\n", *ptr2);
【数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)】嘿嘿,这个就比上一个要复杂一点,不过也好理解。
要更深入理解在内存中怎么储存。
还要考虑大小端的存储模式,以小端为例
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

这里的(int)a是强转,不过是强转成了整数,而不是一个指针。又加1,再强转成了指针。
举个例子
如果这个地址是0x00000004,按照上面的形式,这个地址会变成4之后又加一得到5。又转换成地址为0x00000005。
就相当于增加了一个字节,也是0x00 00 00 04+0x00 00 00 01,是这个意思。搞清楚,是地址,而不是地址上的值,在内存中,地址都是独一无二的,而且,相邻的地址都是相差一个字节。
根据我们分析,这个题的意思就是地址向右移动了一个字节,
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

就是这样的样子,ptr2又解引用了,提取地址是储存的值,再来考虑指针的访问权限。又转换成了int类型的指针,而int* 是可以访问4个字节的权限,接下来就比较不可思议了。
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

每个这个就是一个字节,可以访问4个字节,再提取该地址上储存的元素。还有,我这是据了小端存储的模式,怎么存进去,就要怎么取出来。
数组与指针进阶|指针进阶-THREE(有对指针和数组的加深理解)
文章图片

再以16进制打印,在内存中本就是以16进制存储,直接打印2000000,本来前面有一个0,可省略,但要是打印地址前面的0就不能省略。不信可以试试。
这两道题代表两种题型,仔细琢磨,尤其是第2道。
好了应该就这些,如有问题,烦请大佬指点一二。

    推荐阅读