#include<stdio.h>
//int main()
//{
// int a[5] = { 1,2,3,4,5 };
// int* ptr = (int*)(&a + 1);//数组指针(&a+1)跳过整个数组,5后面的地址,(int*)()强制类型转换
// printf("%d\n", *(a + 1), *(ptr - 1));//打印结果为2,5
// //*(ptr-1)是跳过整个数组并-1,是5
// //*(a+1)为2
// return 0;
//}
//结构体大小是20,假设p的地址是0x100000
//指针+1,加的实际是多少,取决于指针的类型,结构体指针+1,加的是结构体大小,整形指针+1,加的是4
//字符指针,+1加的是1 整形+1,加的就是1
//struct test
//{
// int Num;
// char* pcName;
// short sDate;
// char cha[2];
// short sBa[4];
//}*p;
//int main()
//{
// printf("%p\n", p + 0x1);//指针名是首元素地址
// //0x100000+20(结构体类型是20)=0x100014(20转化为16进制为0x100014)
// printf("%p\n", (unsigned long)p+0x1);//整形+1,加的是4,即0x10001
// printf("%p\n", (unsigned int*)p + 0x1);//int型,+4,即0x10004
// return 0;
//}
//ptr被强制转换成int型,+1就是+1 %x是十六进制
//int main()//假设小端存储:为01000000 02000000 03000000 04000000(地位放在低地址,高位放在高地址)
//{
// int a[4] = { 1,2,3,4 };//int型,如1就需要占4个字节
// int* ptr1 = (int*)(&a + 1);//&a+1跳过整个数组,(int*)是强制类型转换为int*
// int* ptr2 = (int*)((int)a + 1);//数组名是首元素地址,a就是地址,(inta)+1就是+1
// //此时+1就只是+1个字节(int1的四分之一),此时指向的是00000002--->ptr2
// //(int*)表示将a强制类型转换为int*,并将其存储在ptr2中
// printf("%x,%x", ptr1[-1], *ptr2);//打印结果为4 20000000
// //%x是16进制,ptr1[-1]是*(ptr1+(-1)),即向左移动1个整形(int),
// // 4个字节是一个整型,指向04000000--->ptr1
// //打印时,倒着打印,为00000004 和20000000
//}
//int main()
//{
// int a[3][2] = { (0,1),(2,3),(4,5) };//(0,1)逗号表达式,可理解为1,3,5,
// //二维数组为 1 3(第一行) 5 0(第二行) 0 0(第三行)
// int* p;
// p = a[0];//数组名是首元素地址,吧首元素地址传给指针p,p指向1
// printf("%d\n", p[0]);//p[0]->*(p+0),是1
// return 0;
//}
//int main()
//{
// int a[5][5];//二维数组,5行5列
// int(*p)[4];//int(*)[4]
// p = a;//a是int(*)[5],p是int(*)[4],,,将a放入p中,p仍指向首元素的地址
// printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
// //打印结果为11111111111111111111111111111100,,,-4
// //&p[4][2]->*(*(p+4)+2),即4行2列
// //但是p是[4],p每次只前进4个字节,而a是5个字节,所以&p[4][2]只是a[3][2]
// //&a[4][2]就是&a[4][2],小地址-大地址=-4, -4的原码为10000000000000000000000000000100
// // 反码11111111111111111111111111111011
// // 补码11111111111111111111111111111100
// //在地址,直接打印%p为11111111111111111111111111111100,%d时需要吧补码再次改为原码仍为-1
// return 0;
//}
//int main()
//{
// int aa[2][5] = { 1,2,3,4,5,6,7,8,8,10 };
// int* ptr1 = (int*)(&aa + 1);//&aa+1,跳过整个数组,此时是数组,被(int*)强制类型转换
// int* ptr2 = (int*)(*(aa + 1));//数组名是首元素地址,aa+1第一行地址+1,是跳过二维数组的第一行
// //进入第二行,是指向6,*(aa+1)->aa[1],即第二行的数组名,首元素6的地址,此时就是int的6
// printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10 5
// return 0;
//}
//int main()
//{
// char* a[] = { "work","at","alibaba" };
// //a是指针数组,每个元素是指针,每个元素分别是(char*,char*,char*),分别存放,work,at,alibaba
// char** pa = a;//将a的三个指针的地址传给pa,二级指针,指向第一个char*的首元素地址
// pa++;//此时是第二个char*
// printf("%s\n", *pa);//at
// //%s打印字符串,解引用pa(此时是第二个char*)
// return 0;
//}
int main()//指针是连续存放的
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };//将这些元素依次存放在c指针中,
//c的指针分别用char*,char*char*,char*接收
char** cp[] = { c + 3,c + 2,c + 1,c };//c表示首元素地址,与*c的c对应
//把c的char*,char*char*,char*分别存放在c,c+1,c+2,c+3中(注意顺序)
char*** cpp = cp;//把cp放在指针ccp中,顺序是c,c+1,c+2,c+3
printf("%s\n", **++cpp);//POINT
printf("%s\n", *-- * ++cpp + 3);//ER
//优先级决定先算++cpp,刚刚的cpp指向c+2,++之后变为指向c+1,解引用变为c+1,
//c+1进行--,变为c,解引用是char*,char*指向的ENTER的E,再+3,变为E
printf("%s\n", *cpp[-2] + 3);//ST
//*cpp[-2]+3->**(cpp-2)+3,即为上一个打印时的c+1为cpp,
//-2变为c+3,两次解引用指向FINRST,+3后指向ST
printf("%s\n", cpp[-1][-1] + 1);//EW
// cpp[-1][-1] + 1-->*(*(cpp-1)-1)+1,cpp此时为c+1,-1变为c+2,解引用变为point的char*,
//-1变为new的char*,解引用变成new,+1为ew
return 0;
}