写在前面
这是指有关指针的小题
正文
练习一
int main()
{
int a[5][5];
int (*p)[4];
p=a;
printf("%p,%d", &p[4][2]-&a[4][2], &p[4][2]-&a[4][2] );
return 0;
}
解析:
- a[4][2]为如图粉色部分,p[4][2]为如图蓝色部分。
- a的类型是int (*)[5] ,p的类型是int (*)[4],直接p=a,编译器会出警告,但p仍指向a的首元素地址
- &p[4][2]-&a[4][2] 两地址相减,差值为两指针间的元素个数,在本题中元素个数为-4(低地址减 高地址=负数),%p打印内存中中的值,使用补码,%d打印-4
结果:FFFFFFFC,-4
练习二
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf("%d,%d\n",*(ptr1 - 1),*(ptr2 -1));
return 0;
}
解析:
- &aa为整个数组的地址,+1后指向了数组后面的地址,aa是数组第一行元素首元素的地址,+1后指向第二行元素的首元素的地址
- ptr1-1意义是指针向前移动一个位置,那么就指向了10
- ptr2-1意义是指针向前移动一个位置,那么就指向了5
结果:10,5
练习三
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;
}
解析:
- 第一个printf,++cpp指向c+2的地址,解引用后拿到c+2(一个地址),再解引用后,拿到POINT的首地址,结果打印POINT
- 第二个printf,在上一个的基础上再次++cpp后指向c+1的地址,解引用后拿到c+1(一个地址),在此基础上自减后指向c的地址,解引用后拿到ENTER的首元素地址,+1指向N,+2指向T,+3指向E,即从E开始打印字符串,结果就是ER
- 第三个printf,*cpp[-2]+3 ⇔ * *(cpp-2)+3,cpp在两次自增的基础上-2后,指向c+3的地址,解引用后拿到c+3,再次解引用后指向FIRST的首元素地址,+1指向I,+2指向R,+3指向S,即从S开始打印字符串,结果就是ST
- 第四个printf,cpp[-1][-1]+1 ⇔ *(*(cpp-1)-1) +1, cpp在两次自增之后指向c+1(注意cpp加减整数不影响其本身的值),cpp-1后指向c+2的地址,解引用后拿到c+2,再-1解引用后指向NEW的首元素N的地址,+1指向E,即从E开始打印字符串,结果就是EW
结果:
POINT
ER
ST
EW
练习四
int main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
return 0;
}
解析:
- &a+1,表明取出a数组的地址,+1就跳过了数组的地址,指向了数组地址后面的地址,并将其存入ptr中
- a是首元素1的地址,+1变为2的地址,解引用后就是2
- ptr-1指向5的地址,解引用之后就是5
结果: 2,5
写在最后
👍🏻点赞,你的认可是我创作的动力!
⭐收藏,你的青睐是我努力的方向!
✏️评论,你的意见是我进步的财富!