写代码,分析结果
int main()
{
int a[4] = { 1, 2, 3, 4 };
int*ptr1 = (int*)(&a + 1);
int*ptr2 = (int*)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
我们对代码进行解析
首先,我们创建数组a,数组a的元素个数为4,元素为1,2,3,4
&a表示数组的地址,数组的地址+1表示跳过整个数组,处于数组末尾的地址
我们将数组末尾的地址强制类型转化为int型的指针 我们创建整形指针ptr1接收这个整形指针
ptr[-1]可以这样表示 *(ptr-1) 表示数组最后一个元素,为4
a在这里表示首元素的地址 将其强制类型转化为整型再+1 a是1 这时候我们要画出内存的图像
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 数组首元素的地址是01 00 00 00,我们将其强制类型转化为整型结果为1 整型+1就表示+1 我们将其转化为地址表示向后移动一个字节 所以(int)a + 1表示的元素为00 我们再将其强制类型转化为整形指针 赋给ptr2,*ptr2表示对ptr2解引用,向后访问四个字节,访问的地址是 00 00 00 02 因为是小端存储,所以对应16进位制实际上是0x 02 00 00 00,ptr1[-1]对应的16进位制的结果为0x4
#include<stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (3, 4) };
int*p;
p = a[0];
printf("%d", p[0]);
return 0;
}
我们首先要注意,二维数组的元素内部并不是用{}连接的 而是用(),这里表示逗号表达式,逗号表达式(x,y, n),逗号表达式的结果为最后一位a ,所以这里存进去的内容只有1,3,5,所以存进去的实际上是[1 3]
[5 0]
[0 0]
int*p表示p是整型指针,p=a[0], ,a[0]表示为第一行数组的数组名,但他既没有被sizeof修饰,又没有取地址,所以这里表示首元素的地址,也就是1,我们进行打印,打印 p[0],我们可以将它看成*(p+0),表示数组首元素,所以我们打印的结果就为1
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
我们创建一个二维数组,5行5列,表示为
x[() () () () () ] [() () () () () ] [() () () () () ] [() m() () l() () ] [() () y() () () ]
我们创建一个数组指针p,指针p指向的元素个数为4,类型为整型
a是数组名,数组名表示首元素的地址,首元素应该是第一行,第一行的地址位于x处,把这个地址赋给p,这时候会发生警告,原因是a和p的类型不同,a的类型用代码表示的结果int(*)[5] 而p的类型为int(*)[4],类型不同,所以产生警告 p的地址也在x处
a[4][2]表示第五列第三行,在y处 p[4][2]表示*(*(P+4)+2)首先对p+4 解引用,因为p是数组指针,p+1跳过四个字节,一共跳过16个字节,位于点m处,(p+4)表示数组首元素的地址,再+2表示向后移动两个字节,再解引用,到达l处
&p[4][2] - &a[4][2]两个地址相减,表示中间的元素个数,一共差四个,相减为-4,所以%d打印的结果为-4,%p打印的是地址,地址如何表示呢?我们首先写出-4的源码反码补码
10000000000000000000000000000100源码
1111111111111111111111111111111111011反码
1111111111111111111111111111111111100补码
因为地址是无符号数,不存在源码反码补码,所以我们用补码表示地址
我们用16进制将补码表示出来
四个1可以用一个F表示,所以结果为
FFFFFFFC
所以结果为FFFFFFFC -4
如图所示