前言
作者:小蜗牛向前冲
名言:我可以接收失败,但我不能接收放弃
如果觉的博主的文章还不错的话,还请点赞,收藏,关注支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。
目录
笔试题1:
笔试题2
笔试题3
笔试题4
笔试题5
笔试题6
笔试题7
笔试题 8
总结
下面我将为大家分享几道指针的笔试题,希望大家能有所收获。
#include
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数组元素的分布图
从图中我们可以看出指针ptr指向的是数组a之外的元素。
a是数组名-->首元素的地址。
那么我们(a+1)不就是从首地址跳过一个元素,指向下个元素的地址,*(a+1)就找到了元素2。
那么(ptr-1)左移动一个整形的大小,指向5这个元素,*(ptr-1)便找到这个元素。
所以我们的结果为2,5.
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x000000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
首先我们要明白p是什么,p是一个结构体指针,%p值的是打印出指针的地址,我们可以假设p的地址为0x000000,那么p+0x1又表示什么呢?其实就是将p+20-->0x000014。
其中(unsigned long)p,将指针p强制类型转化为整形,所以(unsigned long)p+0x1-->0x000001。
其次(unsigned int*)p,这影响的是指针+-跳过的字节数,其中ungsing int*的大小为4字节,所以 (unsigned long)p + 0x1-->0x000004。
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数组的内存分布图
这里我们先理解清楚,ptr1和ptr2都是int *类型的指针。
(&a + 1)表示跳过整个数组,指向数组后面的元素。
(int)a将a转化为整形,(int )a+1表示a的值加1,就指针跳过1个字节(如图的位置)。
%x指以十六进制打印。
好了我们理解清楚这些变量名的意义了,就开始解题吧。
ptr1[-1]- ->*((&a+1)-1),也就是说解引用指向数组最后位置的指针,就找到了元素0x4.
*ptr2,就是找到ptr2指针指向的元素,根据内存的存取规则,要倒这取出来-->02 00 00 00 ,所以屏幕中最终打印的值为2 00 00 00。
#include
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
a数组元素的分布图
这道题目其实是有个坑,大家误认为初始化为
0 1
2 3
4 5
这种形式,其实()是个,号表达式,输出的值右括号最后的值。所以根据上面的数组元素分布图,我们的出p[0]-->*(p+0)的值为。
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是什么?p又是什么?&p[4][2]和&a[4][2]表示什么?
其中a为二维数组,a的类型为int(*)[4],p为数组指针,p的类型为int(*)[4]。
&a[4][2],图中黄色方块为a[4][2]指向的元素。
p[4][2]-->&*(*(p+4)+2),首先P+4指向图中的位置,为什么呢?可能会人有有疑问,因为p认为自己指向的是4个int类型,所以每次+1都会跳过4个整形元素。其次,在(*(p+4)+2),*(p+4)就会访问4个整形的数组,数组名+就会跳过2个元素,指向第3个元素,在*(*(p+4)+2)就会找到第3个元素(图中绿色方块)。
所以, &p[4][2] - &a[4][2](指针-指针)=指针于指针之间的元素个数4,因为是第地址的指针-高地址的指针结果为-4.
-4
原码:10000000 00000000 00000000 00000100
反码:11111111 11111111 11111111 11111011
补码:1111 1111 1111 1111 1111 1111 1111 1100
十六进制:F F F F F F F C
%p打印FFFFFFFC。
%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数组的元素分布图
这道题和笔试题1及其相似的,把图画出来后就很好解题了。
ptr1-1-->指向aa[1][4],*(prt1-1)找到10。
ptr2-1-->指向aa[0][4],*(ptr2-1)z找到5。
#include
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
a与pa的内存分布
这里我们同样画好图,pa是个二级指针,a是个常量字符串,其中a的变量名表示首元素的地址,开始pa-->w,后来pa++-->a,所以&s打印出''at''。
下面正式进入我们的压轴大题,小伙伴们准备好接收挑战了吗?
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;
}
最初的内存布局
我们画出最初的内存布局后,就开始解题。
1**ccp,从图中我们可以很明显的看出指向的是字符串FIRST(cpp-->c+2).
2*--*++cpp+3(注意++--都是改变量的值),这里我们靠近变量的操作符先进行运算,++cpp,这使得cpp指向c+1,*(c+1)找到c+1,在--*++cpp指的是c+1-->c,*--*++cpp便找到字符串ENTER的首地址,然后,*--*++cpp+3,找到E的地址,打印ER。(cpp-->c+1,c+1-->c)。
3*cpp[-2]+3-->*(cpp-2)+3,这里cpp-2使得cpp指向c+3,*(c+3)找到FIRST的首地址,*(cpp-2)+3找到S的首地址,打印ST。(cpp-->c+3)
4cpp[-1][-1]+1-->*(*(cpp-1)-1)+1,cpp-1指向c+2,*(cp-1)-1-->(指向)c+1,*(*(cpp-1)-1)找到NEW的首地址,*(*(cpp-1)-1)+1找到E的地址,打印EW。
1在做指针类型的题目的时会画图分析很重要。
2p[1]可以等价于*(p+1),p[1][1]也可以等价于*(*(p+1)+1).
3要牢记数组名就是首元素的地址(二种特殊情况就不多说了)。
4指针-指针意义是表示二指针间的元素个数。
大家喜欢的话就点个赞支持博主吧!