作者主页:paper jie的博客_CSDN博客-C语言,算法详解领域博主
本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。
本文录入于《C语言》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将C语言基础知识一网打尽,希望可以帮到读者们哦。
其他专栏:《系统解析C语言》《算法详解》《C语言-语法篇》
内容分享:本期将用八大笔试题带你战胜指针,各位看官姥爷快搬好小板凳坐好叭。
-------- 不要998,不要98,只要一键三连,三连买不了吃亏,买不了上当
前言
上期关于指针的文章,我们用多个试题对指针与数组的关系进行了全面多方位的讲解。这期文章我们将用八道经典的指针笔试题来全面多方位来了解指针。
第一题
答案是多少呢?为什么是这个答案呢?
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是数组首元素的地址,而&a是取出的整个地址。所以a+1就是第二个元素的地址,解引用就是2。&a+1就是跳过整个数组,在5元素的后面,强制类型为int就意味着它后面地址加减的单位都是int类型。ptr就是&a+1的地址,所以ptr-1就是向前减一个int类型,就指向了5的地址,解引用就是5。
第二题
假设p 的值为0x100000。 如下表表达式的值分别为多少?
已知,结构体Test类型的变量大小是20个字节
struct Test
{
int Num;
char *pcName;
short sDate;
char 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;
}
分析
通过提示,我们知道他是一个结构体指针类型,大小为20个字节,地址为0x100000。0x1就是p+1就是加一个20大小的结构体类型,就是0x100000+20=0x100014。unsigned long p 就是将p转化为整型,整型加1就是加1.结果就是0x100000+1=0x100001 unsigned int* p就是将p转化为指针类型,所以p+1就是加了一个指针大小0x100000+4=0x100004
第三题
答案是多少?为什么是这样呢?
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}
分析
a是首元素的地址,&a+1取出的是整个数组的地址 int*(&a+1)就是将&a+1的类型转化为int*的类型,ptr[-1]可以理解为*(ptr-1),ptr就是&a+1,所以ptr-1就是减一个int*类型大小,所以就在元素4的地址,解引用就是4 int a就是将地址a转化为整型,整型加1就是加1 ,我们又知道,在内存中一个地址就是一个字节,这里加1,所以a+1指向的内容就是00到02 0x02000000
第四题
答案是什么呢?为什么呢?
#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;
}
解析
通过观察:我们可以发现,a数组里面是(),所以是逗号表达式,保留右边的值,所以()里的值是1,2,3未满就补0,后面都是0,所以数组中布局就是画图后的样子。
p是a[0]的地址,而a[0]是代表的第一行,我们可以把a[0]理解为第一行的数组名,所以a[0]是首元素的地址,解引用就是1
第五题
答案是多少呢?为什么是这样呢?
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;
}
解析
a数组是一个五行五列的二维数组 a是起始元素的地址 将a的地址赋给p 且q是一个数组指针 p的类型是int[4]。
所以p每加一跳过4个元素 所以p[4]就相当于*(p+4) p的地址就是画图后的地址 两地址相减结果就是中间元素的个数 所以&p[4][2]-&a[4][2]=-4
我们知道电脑中存的都是补码
原码10000000000000000000000000000100
反码11111111111111111111111111111011
补码11111111111111111111111111111100
以%P打印就直接把补码当做地址打印了
以%d打印还是-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", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
解析
aa是首元素的地址,就是第一行的地址 &aa取出的是整个二维数组的地址
ptr1=&aa+1 &aa+1被转化为int*类型 所以ptr-1,就是减去一个int*类型大小,这时ptr指向10元素的地址,解引用为10
aa+1就是第一行的地址加1到第二行的地址,我们发现aa+1的类型也是int*,前面的int*就没用了。就可以理解为:int*ptr=*(aa+1),我们又可以把*(aa+1)理解为aa[1],aa[1]为第二行数组名,就是首元素地址,又因为ptr==*(aa+1)==aa[1],所以ptr-1就是指向元素5,解引用就是5
第七题
答案是多少呢?为什么是这样呢?
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
解析
我们要知道数组a里面存的char*类型的元素,是work,at,alibaba首元素的地址
用二级指针存放a的地址,pa==a,pa++==a++,a是首元素的地址,pa++==a++就是第二个元素的地址。
*pa就是at首字母的地址,%s就是通过首字符地址打印这一串字符
第八题
答案是多少呢?为什么是这样呢?
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;
}
解析
c数组存放的是字符串首元素的地址,cp数组存放的是这些首元素的地址的地址,cpp存放的是cp的地址。这里我们还要注意一个点:++和--是直接改变了它们的值,会影响后面的计算的。