一、程序求解
int main()
{
int a[5] = { 1,2,3,4,5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
解析:2,5
对&a + 1:
- &a 表示整个数组的地址
- &a+1 表示数组后面的空间的地址,类型为
int(*)[5]
即指向长度为 5 的数组的指针- 然后强制类型转换为
int(*)
类型即整型指针对第一个问题
*(a+1)
:a 为数组首元素地址,a+1 为数组第二个元素的地址,解引用后表示数组第二个元素即 2
对第二个问题
*(ptr - 1)
:ptr-1 为数组第五个元素的地址,解引用后表示第五个元素即 5
二、程序求解
指针类型决定了指针走一步有多大
//假设p为0x100000
//已知,Test 类型的结构体变量大小是 20 个字节
struct Test
{
int Num;
char* pcName;
short cha[2];
short sBa[4];
}*p;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
解析:0x100014,0x1000001,0x1000004
对第一个问题
p + 0x1
:由已知得,结构指针变量 p 加1就是加一个结构体指针的大小即 20
对第二个问题
(unsigned long)p + 0x1
:强制类型转换成整型类型,加 1 就是加 1
对第三个问题
(unsigned int*)p + 0x1
:强制类型转换成整型指针类型,加 1 就是加 4
三、程序求解
int main()
{
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);
return 0;
}
解析:4,2000000
对整形指针 ptr1:
- &a+1就是数组后面的空间的地址,类型为
int(*)[4]
即指向长度为 4 的数组的指针- 然后强制类型转换为
int(*)
类型即整型指针对整形指针 ptr2:
- (int)a 表示数组名 a 即首元素的地址被强制类型转换为
int
型- 然后 +1 就是加1,即地址加了1,在内存上就是加 1byte
- 最后强制类型转换为
int*
型- 总的来说就是,数组的首元素地址向后偏移了 1byte,类型为
int*
(整型指针 +1 就是跨4字节,这里是转换成整型变量+1)对第一个问题
ptr1[-1]
:
ptr1[-1] == *(ptr1+(-1)) == *(ptr1-1)
,见下图对第二个问题
*ptr2
:见下图
四、程序求解
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;
}
解析:FFFFFFFC,-4
p 的类型为
int(*)[4]
a(即二维数组数组名)表示第一行的地址,类型为
int (*)[5]
p[4][2]
可以看作*(*(p+4)+2)
对第二个问题
&p[4][2] - &a[4][2]:
差值为 -4
对第一个问题
&p[4][2] - &a[4][2]:
就是在内存中 -4 的写法,即 -4 的补码,打印出来就是 FFFFFFFC
五、程序求解
int main()
{
int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* ptr1 = (int*)(&arr + 1);
int* ptr2 = (int*)(*(arr + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
解析:10,5
对整型指针变量 ptr1:
&arr+1
就是整个二维数组 arr 后面的空间的地址,类型为int(*)[2][5]
即指向2行5列的数组的指针- 然后强制类型转换为
int(*)
类型即整型指针对整型指针变量 ptr2:
*(arr+1)
可以看成 arr[1],即二维数组 arr 第二行的数组名即二维数组 arr 第二行第一个元素的地址- 总的来说,整型指针 ptr2 指向二维数组 arr 第二行第一个元素即 6
对第一个问题
*(ptr1 - 1)
:就是二维数组 arr 最后一行最后一个元素即 10
对第二个问题
*(ptr2 - 1)
:就是二维数组第一行最后一个元素即5
六、程序求解
int main()
{
char* a[] = { "work","at","aalibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
解析:at
对二级指针 pa:
- pa 指向字符指针数组 a 的首元素字符串 abc
对 pa++:
- pa 加 1 后指向字符指针数组 a 的第二个元素字符串 hello
对问题
*pa
就是字符指针数组 a 的第二个元素,按 %s 打印就是 hello
七、程序求解
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *-- * ++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}
解析:POINT,ER,ST,EW
- cpp 指向 cp 的第一个元素 c+3,c+3 为字符指针数组 c 的第四个元素的地址
对第一个问题
**++cpp
:++cpp 表示 cp 的第二个元素 c+2 的地址,而 cp 的第二个元素指向 c 的第三个元素,因此
**++cpp
为字符指针数组 c 的第三个元素即字符串 POINT
- 经过第一次打印后,cpp 变为指向 cp 的第二个元素 c+2 的指针
对第二个问题
*-- * ++cpp + 3
:在上一个问题之后,又一次 ++cpp,表示 cp 的第三个元素 c + 1 的地址,解引用后表示 cp 的第三个元素 c+1
接着是自减,结果为 c,即 c 首元素的地址
然后解引用,表示 c 的首元素(指向字符串"ENTER"首字母的字符指针)
最后 +3,表示字符串"ENTER"的第四个字母’E’的地址
按 %s 打印就是 ER
- 经过第二次打印后,cpp 变为指向 cp 的第三个元素 c+1 的指针
对第三个问题
*cpp[-2] + 3
:在上一个问题之后,先看 cpp[-2],cpp[-2]可以看成
*(cpp+(-2))
即*(cpp-2)
即 cp 的第一个元素 c+3然后解引用,表示 c 的第四个元素(指向字符串"FIRST"首字母的字符指针)
最后 +3,表示字符串"FIRST"的第四个字母’S’的地址
按 %s 打印就是 ST
对第四个问题
cpp[-1][-1] + 1
:此时,cpp 为指向 cp 的第三个元素 c+1 的指针
cpp[-1][-1]+1
可以看成*(*(cpp -1) -1)+1
首先,
*(cpp-1)
表示 cp 的第二个元素 c+2接着 -1 得 c+1
然后解引用得 c 的第二个元素(指向字符串"NEW"首字母的字符指针)
最后 +1,表示字符串"NEW"的第二个字母’E’的地址
按%s打印就是EW