C语言面试必看-指针笔试题详解

指针你真的学会了吗!来试试下面这八道面试的笔试题吧!

笔试题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;
}

解析:
&a,得到的是整个数组的地址,向后加一之后跳到了数组的末尾,如下图:
在这里插入图片描述
将(&a+1)强制类型转换为(int*),(因为(&a+1)的类型是一个数组指针)。
*(a+1)是首元素+1,指针指向了2,再解引用,打印的就是2
*(ptr - 1),原本ptr指向的是上图位置,现在减一,指向5的位置,所以打印出来的就是5

笔试题2

题目:

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

解析:
p+0x1,因为题目给出了结构体的大小是20个字节,所以这里指针p加一的时候是向后跳过了20字节的大小,那么0x100000加20就是0x100014(20转换为16进制就是14)。
(unsigned long)p + 0x1这里把p强制类型转换为unsigned long类型之后,p就是一个无符号长整形的一个数据,加1就是0x100001。
(unsigned int*)p + 0x1这里将p强制类型转换为unsigned int*的决定了指针p加一向后跳过4个字节的空间,所以是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;
}

解析:
第一个ptr1和第一题是一样的道理,只不过这里是用ptr1[-1]打印的,ptr1[-1]和*(ptr1 - 1)是一样的道理。
a是首元素的地址,强制类型转换为一个int类型的数据之后再进行加1,就跳过了一个字节的空间,那么数组首元素1,(int类型的数据是4个字节,在VS中数据采用小端存储)在内存中的存放实际上是01 00 00 00 接着是02 00 00 00…如下图
在这里插入图片描述
这里我只画出了1和2在内存中的存储情况,回到题目中的(int)a + 1,将a强制类型转换为int的类型的数据,然后加1跳过一个字节,指向01 后面的第一个00字节,再强制类型转换为(int*)的指针,后面在解引用ptr2的时候就会向后访问4个字节的空间也就是00 00 00 02,那么打印出来的时候就是2000000(打印地址的时候前面的0会省略),所以第一个打印4,第二个打印2000000

笔试题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;
}

这道题目的坑是注意二维数组a的初始化,逗号表达式的值是最后一个表达式的值,所以a的初始化是

int a[3][2] = { 1, 3, 5};

笔试题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;
}

大家要注意的是数组指针p的访问大小是4个字节,而我们a的初始化是5行5列的。
&p[4][2] 找第5行第3个元素,&a[4][2]找第5行第3个元素
在这里插入图片描述
那么指针相减得到的是指针之间的个数,而&p[4][2] 和 &a[4][2]之间差了四元素的大小,所以&p[4][2] - &a[4][2]的值是-4,那么-4要以%p地址的形式打印的话就是fffffffc,因为:
-4的补码是11111111111111111111111111111100,转换位16进制就是fffffffc,地址不存在正负

笔试题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;
}

解析:
&aa得到整个二维数组的地址,+1向后跳过整个二维数组的大小,再减一,指向的就是10,所以第一个打印的就是10
aa是二维数组的数组名,代表的就是第一个数组的地址,+1跳到第二个数组(假设第二个数组名位arr),再解引用得到第二个数组的第一个元素的地址(*&arr就是arr,数组名代表首元素(6)地址),所以ptr2-1之后指向的就是5的位置,打印出来就是5

笔试题7

题目:

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

这题还是很简单的,a是一个字符串指针数组,pa是一个二级指针,指向a数组的第一个指针(第一个指针指向第一个字符串的首字符地址),pa++之后指向指向第二个指针(第二个指针指向第二个字符串的首字符地址),所以打印的结果就是第二个字符串" at "。

笔试题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;
}

要理解这道题目我们要首先知道c cp cpp分别是什么?
c是一个指针数组,存放了四个字符串
cp是一个二级指针数组,存放的是四个一级指针
cpp是一个三级指针,存放的是cp数组的首元素地址

那么我们来看一下第一个 * *++cpp
1.前置++cpp指向c+2解引用之后cp数组的第二个元素即c+2(三级指针解引用一次得到的是二级指针的内容), 而c+2是只指向的“POINT”的首字符P的地址,那么再解引用就能找到P,%s就会打印出 POINT

2.* - - *++cpp+3在这个表达式中,加法的优先级是最低的,所以先进行++cpp,由于上一次cpp已经++过一次了,所以这次再++的时候指向的就是c+1的地址了,解引用之后就得到了c+1,那么c+1再进行- -之后再解引用之后指向的就是 "ENTER"字符串的首字符E的地址(二级指针解引用得到的是一级指针的地址),再加3指向的就是’E‘,所以打印出来就是ER注意这里的(c+1)已经进行了一次- -,所以c+1指向的地址不再是“NEW”而是“ENTER”

3.*cpp[-2]+3,通过前面cpp的两次++,我们知道cpp已经是指向c+1的了,那么cpp[-2]就是得到了c+3,那么再解引用 得到的就是“FIRST”字符串的首字符地址,再加3指向的就是S,所以打印出来就是ST

4.cpp[-1][-1]+1,cpp[-1]找到的是c+2,c+2[-1]找到的是"NEW"字符串的首字符地址,再加1的话就是指向E,那么打印出来之后就是EW

运行结果如下:
在这里插入图片描述
希望能帮助你对指针有更深入的了解!

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南山忆874

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

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

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

打赏作者

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

抵扣说明:

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

余额充值