目录
编辑
1. 题目一
(1)代码
(2)分析
2. 题目二
(1)代码
(2)分析
3. 题目三
(1)代码
(2)分析
4. 题目四
(1)代码
(2)分析
5. 题目五
(1)代码
(2)分析
6. 题目六
(1)代码
(2)分析
7. 题目七
(1)代码
(2)分析
四. 完结散花
悟已往之不谏,知来者犹可追
创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟
1. 题目一
(1)代码
//题目一
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)分析
再分析题目之前,我们需要知道:
1. 对于数组名来说,一般情况下,数组名代表首元素地址~
2. 然而,有俩个特例:其一,sizeof(数组名)计算的是整个数组的大小,该数组名代表整个数组。其二,&(数组名)也是代表整个数组~
接下来这个题目就显得非常简单了~
&a我们拿到整个数组的地址,再加一就是跳过整个数组
注意这里我们把(&a+1)强制类型转换成了int*,所以ptr-1相当于往后跳过一个整形,
所以*(ptr-1)=5.
*(a+1)这里a代表首元素地址,类型为int*,所以加一跳过一个整形(即*(a+1)=2)
实际上*(a+1)==a[1];
2. 题目二
(1)代码
//题目二
//在X86环境下
//下面结构体的⼤⼩是16个字节
//程序输出的结构是啥?
struct Test
{
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
(2)分析
首先我们定义了一个类型是结构体指针的变量p,并且我们给了他一个地址为0x100000。所以,(P+0x1)就相当于该指针向后跳过了一个该结构体类型,该结构体的大小为16个字节,所以在16进制下%p打印的结果应该为0x100010
(unsigned long)p + 0x1,首先p被强制类型转换成了无符号的长整型,再加一就相当于普通的算术运算,所以结果应该为0x100001
(unsigned int*)p + 0x1,同理,p被强制类型转换成了无符号的普通整形指针,所以加一就相当于跳过了一个无符号的普通整形的大小,所以结果应该为0x100004
3. 题目三
(1)代码
//题目三
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
(2)分析
这个题目有两种理解方法:
1. p[0]可以理解为a[0][0],这是二维数组的访问,我们通常将其简单的理解为访问第一行的第一个元素~
2. p=a[0]我们可以分两步理解,a[0]=*(a+0)即是我们拿到了第一行的地址相当于第一行的数组名,而第一行的数组名又相当于该行首元素的地址,然后,p[0]==*(p+0),首元素地址加一再解引用访问到该行的第一个元素~
到这里,相信大多数人都会觉得答案是0,然而,请注意(0,1)使用的括号而不是大括号,该表达式等价于int a[3][2] = { 1 ,3,5 };
所以结果应该为1
4. 题目四
(1)代码
//题目四
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
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;
}
(2)分析
&a[4][2]我们可以很简单的理解到就是拿到第四行第二个元素的地址啦~
p=a,可以分两步来理解,a=代表首元素的地址,也就是第一行的地址,我们用一个数组指针来接收第一行的地址,不过他的元素个数是4而不是5,也就是意味着,但我们跳过一行时实际上只跳过了4个整形,那这道题就显得很简单了~
我们都知道两个地址相减(即指针减指针)的绝对值的结果是两个指针之间的元素个数,所以%d打印的就是-4,但%p打印的是地址,地址没有负数,所以在编译的过程中就会发生算数转换~
5. 题目五
(1)代码
//题目五
#include <stdio.h>
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", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
(2)分析
这题相对来说就很简单了,这里就不多做解释了~
6. 题目六
(1)代码
//题目六
#include <stdio.h>
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
(2)分析
char* a[] = { "work","at","alibaba" };是一个字符指针数组,char** pa = a;用一个二级指针来指向“work",pa++,则pa指向”at“
7. 题目七
(1)代码
//题目七
#include <stdio.h>
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;
}
(2)分析
这个题目可能相对来说较为复杂一些,不过把图画出来也是简单啦~
四. 完结散花
好了,这期的分享到这里就结束了~
如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~
我们下期不见不散~~