本文内容来源于b站 程序员老秦
首先开胃菜,看一道一维数组例题
#include<stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int* ptr = (int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
×
比较笨的小伙伴(我)会认为数组a指向的是首位,&a取址也是指向的是数组的首位,那么&a+1就是第二位2,认为最终的结果是2,1。
√
a和取址&a指向的是首地址没错,但是对取址&a而言,无论a是几维数组,&a+1一定是整个数组的跨度(放在例题中指向的就是5后面的一个元素),所以最终的输出是2,5
再来一道三维数组的例题
#include<stdio.h>
int main()
{
int a[2][2][3] = {{{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};
int* ptr = (int*)(&a + 1);
printf("%d,%d",*(int*)(a+1),*(ptr-1));
return 0;
}
首先,对于&a而言,几维数组带来的影响不大,因为&a+1一定是整个数组的跨度,因此第二项输入同样是数组的最后一个值12。但是对于三维数组而言,a+1,降维后的二维指针*a+1,再次降维后的一维指针**a+1,他们这个加1的跨度是不一样的。
具体怎么去看呢:
- a+1就相当于在a[2][2][3]的第一个2上做加法,他的跨度就是2×3=6。
- *a+1就相当于在a[2][2][3]的第二个2上做加法,他的跨度就是3。
- **a+1就相当于在最后一维做加法,跨度就是1。
因此,本例的输出为1+6=7和12。
升级一下难度,char*
#include<stdio.h>
int main()
{
static const char* s[] = {"black","white","pink","violet"};
const char** ptr[] = { s + 3, s + 2, s + 1, s }, ***p;
p = ptr;
++p;
printf("%s", **p + 1);
return 0;
}
首先,s是二级指针(数组+char*),s指代的black的地址。
ptr是三级指针(数组+char**),***p也是三级指针,做相等后,***p指代的是s+3的地址,做自加后,***p指代的是s+2的地址,即pink这一元素的地址。
(**p)是对(***p)指代的地址进行取值,取出来也是一个指针,指的是pink的第一个字母p,+1后指到第二个字母i,所以本例的输出是ink。
三维数组和二维数组指针的结合
#include<stdio.h>
int main()
{
int a[3][4]={{1,2,3,4},{2,3,4,5},{3,4,5,6}};
int b[3][4]={{10,11,12,13},{11,12,13,14},{12,13,14,15}};
int(*aa[2])[4] = {a, b};
int* p1[3] = {a[0], a[1], a[2]};
int* p2[3] = {b[0], b[1], b[2]};
int** pp[2] = {p1, p2};
int*** p = pp;
printf("%d\n",(*(*p+2))[1]);
printf("%d\n",aa[1][2] - aa[1][0]);
}
首先,p是三级指针,pp也是三级指针,aa也是三级指针(*加两个框),p1,p2都是二级指针,所以*p
指的就是p1对应的地址(也就是a对应的地址),*p+2
指的就是a[2]对应的地址,*(*p+2)
就是a[2],所以第一个printf就是a[2][1]=4。
aa是三级指针,aa[1][2]其实就是b[2]对应的地址,aa[1][0]就是b[0]对应的地址,是两个指针相减,因此结果是8。
赋值之后指针指向内容突变
#include<stdio.h>
int main()
{
const char* ptr[] = {"Welcome","to","Beautiful","Edoyunnn"};
const char** p = ptr + 1;
ptr[0] = (*p++) + 2;
ptr[1] = *(p + 1);
ptr[2] = p[1] + 3;
ptr[3] = p[0] + (ptr[2] - ptr[1]);
printf("%s\n",ptr[0]);
printf("%s\n",ptr[1]);
printf("%s\n",ptr[2]);
printf("%s\n",ptr[3]);
}
首先,二级指针ptr指向的是ptr[0]对应的地址(“Welcome”),二级指针p指向的是ptr[1]对应的地址(“to”),(*p++) + 2
注意这里是后置++,所以相当于先执行*p + 2
在对p自加,*p
即“to”,加2后没有内容,所以第一个输出空。此时,p自加完成,p指向了ptr[2]对应的地址(“Beautiful”),*(p + 1)
即取ptr[3]的内容,所以第二个输出“Edoyunnn”。p[1] + 3,也即是ptr[3]的内容右移三位,即“yunnn”。最后,ptr[2]-ptr[1]是两个指针相减,差应该为3(一个指向E,一个指向y)。p[0]是ptr[2],也就是此时的“yunnn”,+3后得到“nn”。
多级指针多维数组的指针偏移运算
#include<stdio.h>
const char* c[] = {"Welcome","to","Beautiful","Edoyun"};
const char** cp[] = {c+3, c+2, c+1, c};
const char*** cpp = cp;
int main()
{
printf("%s\n",**++cpp);
printf("%s\n",*-- *++ cpp + 3);
printf("%s\n",*cpp[-2] + 3);
printf("%s\n",cpp[-1][-1] + 1);
printf("\n");
return 0;
}
答案:
Beautiful
come
yun
o
留给读者自测用~如果有不懂的欢迎一起讨论,或者可以从本文开头超链接去原视频收听讲解!