指针题目特训(答案加解析)走进大厂笔试

作者:旧梦拾遗186

专栏:C语言编程----小比特成长日记

 

每日励志:

生活总是遍体鳞伤,可是后来,那些受伤的地方一定会变成我们最强壮的地方——海明威

前言:

为了巩固我们所学的指针知识,今天小编带大家做几道,大厂的笔试题。

目录

前言:

题目:

笔试题 1:

笔试题 2:

笔试题 3:

笔试题 4:

笔试题 5: 

笔试题 6: 

笔试题 7:

 笔试题 8:

总结 


前言:

为了帮助小伙伴们更好的降服指针,小编特地为小伙伴们总结了八道指针的笔试题目,并有本人的详细解析,希望同学们仔细阅读,如有不懂的可以私信小编哦。

题目:

笔试题 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  5

答案:2 5

解析:

        在本题中a是数组名代表数组首元素的地址,此时可将a看为指针,a+1,代表指针后移一位,此时再对a+1解引用*(a+1),得到第二个元素的值,所以*(a+1)的答案为2。

        &a代表整个数组的地址,故在进行(&a+1)的操作中跳过了整个数组,而&a带表的是整个数组的地址其指针类型为int(*)[5](数组指针),而ptr的指针类型为int*(整型指针),所以此时在进行赋值操作时,需要将(&a+1),强制转换为整型指针(若不转化编译器会报警告,在编译时还是会以ptr的类型为准),故ptr-1代表整型指针向前移动以为再进行解引用*(ptr-1),得到结果为5。细则如图。


笔试题 2:

//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
 int Num;
 char *pcName;
 short sDate;
 char cha[2];
 short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体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; }

答案: 0x100014    0x100001     0x100004

解析:

可以先给p进行赋值p=(struct Test*)0x100000

在本题中0x代表16进制,而0x1代表1,由于p是指针类型,指针类型+1代表跳过此类型的大小既:

1)一个整形指针+1代表跳过一个整形的大小

2)一个结构体指针+1代表跳过一个结构体的大小

3)一个字符指针+1代表跳过一个字符的大小

故:p+1代表跳过一个结构体类型大小(20字节),化简为16进制为14再加上0x100000结果为0x00014;

(unsigned long)p代表普通整型类型,故此时的运算部位指针运算而为普通的整数运算结果为0x100001;

(unsigned int*)p把结构体指针类型强制转化为整型指针类型,此时为指针运算挑过的是一个整型类型的大小结果为0x100004;


笔试题 3:

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; 
}

答案: 4   20000000

解析:

&a代表整个数组的地址,故在进行(&a+1)的操作中跳过了整个数组,而&a带表的是整个数组的地址其指针类型为int(*)[5](数组指针),而ptr的指针类型为int*(整型指针),所以此时在进行赋值操作时,需要将(&a+1),强制转换为整型指针(若不转化编译器会报警告,在编译时还是会以ptr的类型为准),又因为ptr1[-1]可转化为*(ptr1-1),故可看为ptr1-1代表整型指针向前移动以为再进行解引用*(ptr-1),得到结果为4。细则如图1。

因为a为数组名为首元素地址,可假设为0x0012ff40,而(int)a把a转化为整型类型,此时的a可表示为0x0012ff40,之后再进行+1,可表示为0x0012ff41,再强制转化为(int*)赋值给ptr2,相当于指针向后移动了一个字节(细节如图2),由于采取的是小端存储,再进行转化时需要从高地址向低地址读取,最后打印结果为20000000

图1:

图2:


笔试题 4:

#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;
}

答案: 1

解析:

做这道题的时候千万不要掉到坑里,数组这样初始化int a[3][2] = { (0, 1), (2, 3), (4, 5) };和这样初始化int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };是不同的,前者为逗号运算,逗号运算(从左向右一次运算,取最右边的值),所以此时数组被初始化为int a[3][2] = { 1,3,5};如图1。

a[0],代表数组第一行首元素的地址即为&a[0][0],而p[0],可表示为*(p+0),所以p[0]=&a[0][1]。


笔试题 5: 

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; 
}

答案:ff ff ff fc      -4

解析:

由题我们可以知道p的的类型为数组指针即为int(*)[4],而a为数组首元素地址又因为a[5][5],为二维数组,则a代表的是第一行的地址相当于&a[0],很明显两者的类型不同,故赋值时会报错,但是仍可以运行,通过绘图我们可以找到a[4][2]和p[4][2]的具体位置,而地址(指针)减地址(指针),求出来的是地址之间元素的个数,故%d打印出来的结果为4.(如图1)

当以%p打印时我们可知-4的原反补

原码:1000 0000 0000 0000 0000 0000 0000 0100

反码: 1111 1111  1111 1111  1111 1111  1111 1011

补码: 1111 1111  1111 1111  1111 1111  1111 1100 

可化为ff ff ff fc 

图1:


笔试题 6: 

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; 
}

答案:10  5

解析:本题和前集体类似,在画图的时候注意化成一行即可;


笔试题 7:

#include <stdio.h>
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;
 printf("%s\n", *pa);
 return 0;
}

 答案:at

解析:

char *a[]说明此为指针数组,里面存储的类型为char*,所以此时需要用二级指针来存储一级指针的地址,char**pa可以这样理解,char*(说明了pa指向了char*类型)*(说明了pa为指针类型)pa

所以本题中pa++跳过得是一个char*类型的大小指向at所以结果为at

%s打印只需要一个地址即可


 笔试题 8:

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; 
}

答案:POINT   ER   ST    EW

解析:

首先我们要用清楚指针间的关系图如下:

 a)当我们执行++cpp,则cpp指向了cp[1],故此时第一次解引用找到了c[3]的地址,再解引用找到了“POINT”的首地址,进行打印结果为POINT。

b)第二个打印值时我们先进行++cpp运算指针指向cp[2]的地址再解引用得到c[1]的地址再--得到c[0]的地址此时解引用得到“ENTER”的首地址,在+3得到E的地址此时打印的结果为ER

c) 当执行第三个打印值时,可变化为

*cpp[-2]+3-->*(*(cpp-2))+3

即cpp-2为cp[0]的地址解引用得到cp[0]的地址,再解引用得到c[3]里的内容即为F的地址,为“FIRST”的首元素地址+3为s的地址故结果为ST

d) 当执行最后一个时和上边的类似得到ER

cpp[-1][-1]+1-->*(*(cpp-1)-1)+1

总结 

以上八到题如果能够熟练掌握,说明了我们已经对指针有了深入的了解,也知道了画图时做出指针难题的最大利器,希望小伙伴们真正看懂这些题。

如有收获希望三连哦嘿嘿嘿

 

  • 39
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧梦拾遗186

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值