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

【答案】在x86环境下运行

【解析】

&a是取出整个数组的地址,&a就表示整个数组,因此 &a + 1就是跳过一整个数组指向数组后方,因为这是一个数组的地址,不能够直接赋值给整型指针,所以需要将该地址强制转换为整型指针,才能给指针ptr接收,此时指针ptr就指向了数组后方。

因此*(a+1)就等于a[1]自然是2,而*(ptr-1)就是向前挪动一个整型指向5


 

 笔试题2:

struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
//0x开头的数组是16进制的数字
int main()
{p = (struct Test*)0x100000;printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

【答案】在x86环境下运行

【解析】

%p:把要打印的数以地址的形式来打印。

  • p是结构体指针,p + 1 就是跳过一个结构体的大小即20个字节,又因为%p是以16进制地址形式打印,10进制的20等于16进制的14,因此结果为00100014。
  • p是结构体指针,被强制类型转换成unsigned long,整数+1就是+1,因此结果为00100001。
  • p是结构体指针,被强制类型转换成unsigned int*,在x86环境下,只要是指针大小就为4,那么指针+1就是跳过4个字节,因此结果为00100004。

 

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

【答案】在x86环境下运行,小端存储

【解析】

该题涉及到大小端存储的问题,往期博客中有进行探讨,这里就不多赘述,如有兴趣或者不懂的可前往:点击前往

&a是取出整个数组的地址,&a就表示整个数组,因此 &a + 1就是跳过一整个数组指向数组后方,因为这是一个数组的地址,不能够直接赋值给整型指针,所以需要将该地址强制转换为整型指针,才能给指针ptr接收,此时指针ptr1就指向了数组后方。

ptr1[-1]等价于*(ptr1-1),表示ptr1向前挪动一个整型指向4,结果就为4

a被强制转换成int,即首元素地址被转换成int,整型+1就是+1。假设a的地址是0x100000,此时+1就等于0x100001,然后再强制类型转换为整型指针并赋值给ptr2。

*ptr2整型指针访问四个字节(即红框所框处),此时为内存存放的图解,需要转成真实值即0x02000000。


 

笔试题4:

int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int* p;p = a[0];printf("%d", p[0]);return 0;
}

【答案】

【解析】

此题为细节题,过程不难。需要注意的是题中的是小括号,( , )即逗号表达式。a[3][2]中实际存储的是{1,3,5}。将a[0]赋值给p指针,即p指向数组第一行地址,再通过p[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;
}

【答案】 

【解析】

a的类型是int (*) [5] ——— 即a指针指向一个大小为5的数组

p的类型是int (*) [4] ——— 即p指针指向一个大小为4的数组

当把a所指的地址赋值给指针p之后,a p指向同一地址,但是由于a认为自己指向的是5个元素,而p认为自己指向的是4个元素,这就会导致它们就算下标相同时访问到的内容也是不一样的,如图所示。

随着数组下标的增长,地址是由低到高的变化,并且指针和指针相减的绝对值得到的是指针之间的元素个数,而当取出p[4][2]和a[4][2]的地址之后相减,就是小地址减去大地址,得到一个负数,就是-4。

%p是打印地址,会认为内存中存储的补码就是地址,所以就是打印-4的补码

原码:10000000 00000000 00000000 00000100

反码:11111111  11111111  11111111   11111011

补码:11111111  11111111  11111111   11111100

以%p地址的形式打印补码转成16进制表示:FF FF FF FC

而-4以%d形式打印就是-4

对于原码反码补码的内容,往期博客有所提及,感兴趣的可以前往:立即前往


 

笔试题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表示整个数组的地址,&aa+1跳过一整个二维数组,指向数组之后,再强制类型转换成整型指针赋值给ptr1。此时*(ptr1-1)就等于ptr1向前挪动一个整型并解引用找到10。
  • aa不是单独放在sizeof()内,因此aa表示首元素地址,aa又是二维数组,因此aa的首元素地址就是一个大小为5的数组,*(aa+1)等价于aa[1],表示aa跳过一个大小为5的数组指向下一个大小为5的数组再解引用找到该数组再赋值给整型指针ptr2。此时*(ptr2-1)就等于prt2向前挪动一个整型并解引用找到5。


 

 笔试题7:阿里巴巴笔试题

int main()
{char* a[] = { "work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;
}

【答案】

【解析】

a是一个字符指针数组,每个元素的类型都为char*。

pa是一个指向char*字符指针的指针,即二级指针。

pa++即是向前跳一个char*的大小,即指向a[1]的地址,*pa就是找到a[1]指向的元素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;
}

【答案】

【解析】

本题是该篇博客中最难的一题,因为涉及到三级指针,并且还使用指针自增1自减1的方法去永久改变指针指向,会导致如果一步错,就会步步错的结局,因此需要非常仔细的去画图理解。

cpp存放char**类型的数据。 【** ++cpp】,cpp先自增1,跳过一个char**类型指向下一个元素的地址,如下图。

此时再对cpp进行解引用,找到cp[1],再解引用,找到c[2]即P的地址。此时%s打印出来就是POINT

 【* -- * ++cpp + 3】,加号优先级是最低的,所以最后算。cpp先自增1跳过一个char**大小指向下一个元素的地址,如下图。

此时再对cpp进行解引用,找到的是cp[2]即指向了c+1这块空间,再自减1则指向了c这块空间,再解引用找到了c[0]即ENTER中第一个E的地址,此时+3跳过三个char,最后指向ENTER中第二个E的地址,此时用%s打印出来就是ER

*cpp[-2] + 3】等价于【* *(cpp-2)+3】。与前面的cpp自增自减不同,cpp-2只是表达式并不会改变cpp的指向。

cpp[-2]指向cp[0],再解引用找到c[3],c[3]存放的是FIRST中F的地址,此时+3跳过三个字母指向FIRST中S的地址,再用%s打印出来就是ST

【 cpp[-1][-1] + 1】等价于【*(*(cpp-1) -1) + 1】。

*(cpp-1)找到c+2,c+2再-1就是c+1的地址,再进行解引用找到NEW中N的地址,再+1找到E的地址,此时用%s打印出来就是EW

 


 到此,这几道企业笔试题就讲解完成,希望能对你们有所帮助,也欢迎大家在评论区进行讨论。

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/85573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Biome-BGC生态系统模型与Python融合技术

Biome-BGC是利用站点描述数据、气象数据和植被生理生态参数,模拟日尺度碳、水和氮通量的有效模型,其研究的空间尺度可以从点尺度扩展到陆地生态系统。 在Biome-BGC模型中,对于碳的生物量积累,采用光合酶促反应机理模型计算出每天…

使用Chatgpt编写的PHP数据库pdo操作类(增删改查)

摘要 将PDO封装成PHP类进行调用有很多好处,包括: 1、封装性和抽象性: 通过将PDO封装到一个类中,您可以将数据库操作逻辑与应用程序的其他部分分离开来,提高了代码的组织性和可维护性。这样,您只需在一个地…

soildwork2022怎么恢复软件界面的默认设置?

1.点击菜单中的” 视图” 2.在弹出的子菜单中选择”工作区” 3.选择工作区中的”默认” 4.点击默认后软件界面就恢复了默认设置。

FPGA 图像缩放 千兆网 UDP 网络视频传输,基于B50610 PHY实现,提供工程和QT上位机源码加技术支持

目录 1、前言版本更新说明免责声明 2、相关方案推荐UDP视频传输--无缩放FPGA图像缩放方案我这里已有的以太网方案 3、设计思路框架视频源选择IT6802解码芯片配置及采集动态彩条跨时钟FIFO图像缩放模块详解设计框图代码框图2种插值算法的整合与选择 UDP协议栈UDP视频数据组包UDP…

二叉树层序遍历及判断完全二叉树

个人主页:Lei宝啊 愿所有美好如期而遇 目录 二叉树层序遍历: 判断完全二叉树: 二叉树层序遍历: 层序遍历就是一层一层,从上到下遍历,上图遍历结果为:4 2 7 1 3 6 9 思路: 通过队列来实现层序…

发送实时音频数据到udp服务

由于浏览器不能直接连接udp服务,所以需要搭建一个websocket服务做中转,让websocket服务连接udp服务 1、vue开发获取实时音频数据并按4096分包后添加rtp协议头发送到websocket服务(连接websocket自行编写连接到127.0.0.1:8889) da…

购物H5商城架构运维之路

一、引言 公司属于旅游行业,需要将旅游,酒店,购物,聚合到线上商城。通过对会员数据进行聚合,形成大会员系统,从而提供统一的对客窗口。 二、业务场景 围绕更加有效地获取用户,提升用户的LTV&a…

Python线程和进程

1、深度解析Python线程和进程 一篇文章带你深度解析Python线程和进程 - 知乎使用Python中的线程模块,能够同时运行程序的不同部分,并简化设计。如果你已经入门Python,并且想用线程来提升程序运行速度的话,希望这篇教程会对你有所帮…

stm32之看门狗

STM32 有两个看门狗,独立看门狗和窗口看门狗,独立看门狗又称宠物狗,窗 口看门狗又称警犬。可用来检测和解决由软件错误引起的故障。两个看门狗的原理都是当计数器达到给定的超时值时,产生系统复位,对于窗口型看门狗同…

FL Studio21.2中文版数字音乐制作软件

现在的FL也可以像splice一样啦,需要什么样的声音只需在fl里搜索,就会自动展示给你! FL Studio 简称FL,全称:Fruity Loops Studio,国人习惯叫它"水果"。软件现有版本是 FL Studio 21,已全面升级支…

如何利用播放器节省20%点播成本

点播成本节省的点其实涉及诸多部分,例如:CDN、转码、存储等,而利用播放器降本却是很多客户比较陌生的部分。火山引擎基于内部支撑抖音集团相关业务的实践,播放器恰恰是成本优化中最重要和最为依赖的部分。 火山引擎的视频团队做了…

“智慧”北京,人工智能引领“新风尚”

原创 | 文 BFT机器人 北京时间,9月15日,北京人工智能产业峰会暨中关村科学城科创大赛颁奖典礼在北京中关村举行,同时惠阳还举行了“中关村人工智能大模型产业集聚区”启动建设的揭牌仪式。 此次大会围绕北京AI产业的建设与发展,各…

大模型时代,探人工智能发展的新动向

导语 | 今年以来大模型的热度居高不下,人工智能成为国内外各大厂商争相布局的新赛道。那么近期 AI 领域有哪些值得关注的新趋势,它又将为软件开发带来哪些影响呢?今天,我们特邀了微智云科技 CEO、腾讯云 TVP 张虎老师,…

不用addEventListener(‘resize‘, this.resize),用新的Web API ResizeObserver监听DIV元素尺寸的变化

响应式设计指的是根据屏幕视口尺寸的不同,对 Web 页面的布局、外观进行调整,以便更加有效地进行信息的展示。我们日常生活中接触的很多应用都遵循响应式的设计。 响应式设计如今也成为 web 应用的基本需求,而现在很多 web 应用都已经组件化&a…

分布式运用之Filebeat+Kafka+ELK 的服务部署

一、Kafka 架构深入了解 1.1 Kafka 工作流程及文件存储机制 Kafka 中消息是以 topic 进行分类的,生产者生产消息,消费者消费消息,都是面向 topic 的。 topic 是逻辑上的概念,而 partition 是物理上的概念,每个 par…

LinkedList相较于Arravlist的特点/优化

Arravlist底层是内存空间连续的数组,可以根据下标进行随机访问,效率比较高,因为在根据下标访问某一个元素时,并不是一个一个去查,而是算出来这个下标的地址,直接根据这个地址的指向去获取的,因为…

Linux 创建 终止线程(thread)

进程线程区别 创建线程 #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -功能&#xff1a;创建一个子线程&#xff0c;一般情况下main函数所在的线程称为主线程&#xff0c;…

Unity的AB包相关

1、打包 在这个界面左边右键&#xff0c;CreateNewBundle 将要打包的模型制作成预设体 在下面勾选 选好平台路径&#xff0c;点击Build 2、加载AB包 public class ABTest : MonoBehaviour {// Start is called before the first frame updatevoid Start(){//加载AB包AssetB…

mysql集群使用nginx配置负载均衡

参考链接&#xff1a;https://mu-sl.com//archives/mysql%E9%9B%86%E7%BE%A4%E4%BD%BF%E7%94%A8nginx%E9%85%8D%E7%BD%AE%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1 配置文件nginx_tcp.conf 示例 load_module modules/ngx_stream_module.so;stream{upstream tcpssh{hash $remote_…

【c#-Nuget 包“在此源中不可用”】 Nuget package “Not available in this source“

标题c#-Nuget 包“在此源中不可用”…但 VS 仍然知道它吗&#xff1f; (c# - Nuget package “Not available in this source”… but VS still knows about it?) 背景&#xff1a; 今日从公司svn 上拉取很久很久以前的代码&#xff0c;拉取下来200报错&#xff0c;进一步发…