int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1)); // 2 5
在*(a + 1)中a被隐式转成指向首元素1的指针,加1再解引用得到第二个元素2;&a得到一个int()[5],值为1的地址,加1跳过整个数组,值为5的地址加1,然后强转成int类型。所以*(ptr-1)得到最后一个元素5。
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
};
struct Test* p = (struct Test*)0x100000;
printf("%p\n", p + 0x1); // 00100014
printf("%p\n", (unsigned long)p + 0x1); // 00100001
printf("%p\n", (unsigned int*)p + 0x1); //00100004
加1后的值要看变量的类型。指针加1表示其值加上指向的类型在内存中占的字节数。struct Test在内存中占20个字节,所以其指针类型+1在数值上加了20.usigned long类型的p加1在数值上加了1,unsigned int*类型的p加1得到的数值为p+4
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf("%x,%x\n", ptr1[-1], *ptr2); // 4,2000000
第一个打印的结果与问题一中类似,&a得到一个数组指针,值为1的地址,加1地址为4后面的地址,强转成int*指向4后面的4个字节。ptr1[-1]就取到4.
(int)a + 1得到的是1的地址加上1.所以再解引用是,*ptr2从元素1的第二个字节开始去四个字节,由于字节序为小端序。所以取到的结果为02000000.
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]);
//FFFFFFFC,-4
p[4][2]相当于取到数组中第5行第三个元素,即第十九个元素,而a[4][2]取到第23个元素。所以两者之间相差4个元素。所以指针相减得到-4。
int aa[2][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10 }
};
//&aa 应该是一个数组指针 int(*)[2][5], 再 + 1 应该要跳过整个数组
int *ptr1 = (int *)(&aa + 1);
// aa 是二维数组名 再 + 1, 隐式转成 int(*)[5]
int *ptr2 = (int *)(aa[1]);
printf("%d,%d\n", *(ptr1 - 1), *(ptr2 - 1));// 10,5
这里&aa同前面得到数组指针,类型为int()[2][5],+1跳过了整个二维数组。因此(ptr-1)取到二维数组的最后一个元素10;aa[1]相当于*(aa + 1),aa隐式转成指向首元素的指针,类型为int()[5],+1跳过第一个一维数组,所以(ptr2-1)取到第一个一维数组的最后一个元素5。
char *a[] = { "work","at","alibaba" };
char**pa = a;
pa++;
printf("%s\n", *pa); // at
a是一个指针数组,数组元素的类型为char*,元素有三个,分别存放了三个字符串首字母的地址。pa=a,a隐式转成指向首元素的指针类型,即char**类型,将其值(work中w的地址地址)赋给pa,pa++得到字符串“at”中a的地址,打印得到字符串at。
7.
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
char**cp[] = { c + 3, c + 2, c + 1, c };
char***cpp = cp;
printf("%s\n", **++cpp); //POINT
printf("%s\n", *--*++cpp + 3);//ER
// cpp[-2] => *(cpp-2) 这个操作没有修改 cpp 的内容. 而上面的 ++ 操作修改 cpp
printf("%s\n", *cpp[-2] + 3);//ST
//printf("%s\n", cpp[-1][-1] + 1);// EW