【C语言进阶篇】关于指针的八个经典笔试题(图文详解)


在这里插入图片描述

🎬 鸽芷咕:个人主页

 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》

⛺️生活的理想,就是为了理想的生活!

文章目录

  • 📋 前言
  • 💬 指针笔试题
    • 💭 笔试题 1:
      • ✅ 代码解析
      • ⁉️ 检验结果:
    • 💭 笔试题 2:
      • ✅ 代码解析
      • ⁉️ 检验结果:
    • 💭 笔试题 3:
      • ✅ 代码解析
      • ⁉️ 检验结果
    • 💭 笔试题 4:
      • ✅ 代码解析
      • ⁉️ 检验结果
    • 💭 笔试题 5:
      • ✅ 代码解析
      • ⁉️ 检验结果
    • 💭 笔试题 6:
      • ✅ 代码解析
      • ⁉️ 检验结果
    • 💭 笔试题 7:
      • ✅ 代码解析
      • ⁉️ 检验结果
    • 💭 笔试题 8:
      • ✅ 代码解析
      • ⁉️ 检验结果
  • 📝全篇总结

📋 前言

  🌈hello! 各位宝子们大家好啊,指针系列的讲解我们就全部讲解完毕了,那么接下来就是来检验成果的时候了?
  ⛳️今天来做一做指针的面试题到底是个什么难度!你真的学会了指针了嘛?这篇文章让你融汇贯通
  📚本期文章收录在《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;
}
//程序的结果是什么?

✅ 代码解析


printf( “%d,%d”, *(a + 1), *(ptr - 1));
其实没什么难的,我相信各位铁子们已经想出答案了!关于数组的笔试题我们做了那么多,&数组名就是拿出整个数组的数组名而+1就是跳过整个数组+1;

  • 所以 *(ptr-1)就是回到了数组的最后一个元素的位置

  • 在这里插入图片描述

  • 然后进行解引用 结果就是:5


  • *(a + 1) a 是首元素的地址,所以+1 就是指向第二个元素的地址

  • 在这里插入图片描述

  • 然后进行解引用 结果就是:2

⁉️ 检验结果:

📑图片展示:

在这里插入图片描述

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

🔥 注:本代码是在32位环境下测试的。

✅ 代码解析

printf(“%p\n”, p + 0x1);
这里就非常有意思了指针加一我们都知道是跳过指针类型的大小,整形指针跳过4个字节,字符指针跳过1个指针。而我们这里结构体的大小是20个字节,所以+1跳过的就是20个字节!

  • 但是要注意这里是以16进制输出的所以 20 的16进制就是 14
  • printf(“%p\n”, p + 0x1);
  • 的结果为 0x100014。

printf(“%p\n”, (unsigned long)p + 0x1);
而这里则强制转换成了整形,而强转成整形的话。那么 p 就是一个整数了。而整数+1就是 +1 没有什么变化!

  • printf(“%p\n”, (unsigned long)p + 0x1);
  • 的结果为 0x100001。

printf(“%p\n”, (unsigned int*)p + 0x1);
这里指针 p 被强制转换为了无符号整形,而无符号整形+1。就是跳过4个字节。

  • printf(“%p\n”, (unsigned int*)p + 0x1);
  • 的结果为 0x100004。

🌴 总结:

  • 这里运用了指针的运算和进制位的转换,这要这些知识掌握了。截图就非常easy了!
  • 注:指针运算的博客在这里《指针的运算详解》

⁉️ 检验结果:

在这里插入图片描述

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

✅ 代码解析

int *ptr1 = (int *)(&a + 1);
我们先来看一下,&a先把整个数组的地址拿出来然后进行+1然后强制转换为 int 类型的指针传给我们 ptr1。*

  • 那么 *ptr1,不就指向与数组相邻的那个元素了吗!
  • ptr1[-1] 就右回到了,数组的最后一个元素
    在这里插入图片描述

int *ptr2 = (int *)((int)a + 1);
🔥 注:这里需要用到 大小端存储的概念!不会的也去看看 这里只简单讲解哦!

这里就非常有意思了,a是数组首元素的地址。这里却把它强制转换为了整数,然后+1是在括号里面所以a+1,在转换为int* 类型的地址就只跳过了一个字节!

  • 然后再进行+1 跳过4个字节,进行解引用访问4个字节
    在这里插入图片描述

  • 所以int *ptr2 = (int *)((int)a + 1);

  • 🔥 *ptr2 的结果是 0x02000000

这里给大家解释一下大小端存储,就地址存低位,高地址存高位。所以拿出来的时候低地址就是低位,高地址当高位还原的。

  • 这里02是在高地址的所以拿出来的时候直接就放在高位了

⁉️ 检验结果

在这里插入图片描述

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

✅ 代码解析

int a[3][2] = { (0, 1), (2, 3), (4, 5) };
这里陷阱就比较多了,一定要注意二维数组的时候是用大括号进行赋值的。而这里使用括号说明他是逗号表达式。

  • 所以a[3][2] = {1,3,5};
  • a[0] = *(a+0) = *p 等于二维数组第一排首元素的地址

在这里插入图片描述

  • int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  • 结果为 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;
}

✅ 代码解析

这个题也是一个陷阱,我们首先要搞懂,数组的地址变化是由数组下标由低到高变化的而且数组还是一块连续的储存空间。

  • int(*p)[4]; p = a;这里要搞懂赋值给p的是什么,由于 aint (*)[5] 指针 pint (*)[4] 所以会发生隐式转换。到int (*)[4]

在这里插入图片描述

这里我们就可以看到p[4][2]a[4][2]之间相差了,4个整形的长度。

  • 我们知道指针运算里面 指针 - 指针 的=得到的是指针之间元素的个数!
  • printf( “%p,%d\n”, &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
  • 所以得到的是 -4 这个数值!

但是如果以地址打印的话得到的就是,-4 在内存中存储的数字。而 -4 在内存中是以补码的形式存储的。
在这里插入图片描述

  • 所以以 %p 打印结果就是 FFFFFFFC。
  • 以 %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 取出的是整个二维数组的地址。+1 就是跳过整个数组指向数组后一个元素。

  • **int *ptr1 = (int *)(&aa + 1); **
  • printf( “%d”, *(ptr1 - 1), );
  • 所以在进行 -1 的时候就访问到了数组的最后一个元素 10。

*ptr2 = (int *)(*(aa + 1));这里 aa 代表的就不是首元素的地址了,而是一维数组 aa[0] 整个一维数组的地址,所以+1 就跳到了 aa[1].

  • *ptr2 = (int )((aa + 1));
  • printf( “%d”, *(ptr2 - 1));
  • 所以在进行 -1 就又回到了aa[0] 的最后一个元素 5。

⁉️ 检验结果

在这里插入图片描述

💭 笔试题 7:

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

✅ 代码解析

这里要注意也是一个陷阱, char *a[] = {“work”,“at”,“alibaba”}; a[ ] 里面可以当成存放的是一维数组字符串首元素的地址。所以当我们把 字符指针 数组 *a[] 存放到 二级指针 pa 里面的时候他们的内存布局就应该是这样的!
在这里插入图片描述

  • pa++ 就指向 a[1] 而对一个地址进行解引用,得到的是a[1] 这个字符指针指向的字符串
  • 所以: printf(“%s\n”, *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;
}

✅ 代码解析

做这种题首先把图画出来就简单多了
在这里插入图片描述

printf(“%s\n”, **++cpp);
**++cpp指向的就是 cp[1] , 向前了一小步。这时看这我们上面画的图就简单多了!而这时又进行了俩次解引用不就找到 c[2]嘛!
请添加图片描述

  • printf(“%s\n”, **++cpp);
  • 的结果为 POINT。

printf(“%s\n”, *--*++cpp+3);
这个首先要把运算符的逻辑关系搞清楚,做这个题就简单多了 ++ -- 的运算符关系是比 + 号运算优先级要高的。

  • 但是这里要注意前面的 ++ 是会影响指针的指向的 。
  • 那么先++在解引用就找到了这里 *++
    在这里插入图片描述
  • 在 -- 在解引用就找到了这里 *-- , c这个首元素地址
    在这里插入图片描述
  • 但是这里还进行了 +3 那么就要跳过3个 char 字节在打印

在这里插入图片描述

  • printf(“%s\n”, *--*++cpp+3);

  • 所以结果为 ER


printf(“%s\n”, *cpp[-2]+3);
这里我们和上面一样, *cpp[-2]+3 = *(cpp-2)+3 , 我们把它简化一下就简单多了!

  • 这里依旧要注意前面是改变了 cpp的指向 。
  • 所以 cpp-2 然后再进行解引用指向的就是这里
  • 在这里插入图片描述
  • 然后再进行 +3 跳过3个字节进行打印
  • 在这里插入图片描述
  • printf(“%s\n”, *cpp[-2]+3);
  • 结果为 ST

printf(“%s\n”, cpp[-1][-1]+1);
诶这里大家千万不要进入误区了,使用下表引用是不会改变 指针的指向的,所以我们cpp 指向的还是 cp[2]。

  • cpp[-1][-1]+1 = ((cpp-1)-1)+1

  • 先 -1 然后再进行解引用,就找到了这里
    在这里插入图片描述

    • 在 -1 然后再进行解引用,就找到了这里
      在这里插入图片描述
  • 然后再进行 +1 打印出来就是从这个位置开始的!
    在这里插入图片描述

  • printf(“%s\n”, cpp[-1][-1]+1);

  • **结果为 EW **


⁉️ 检验结果

在这里插入图片描述

📝全篇总结

✅ 归纳:
好了以上就是关于经典的八个经典笔试题的详细解析,包含了个个方面的知识不知道大家做的怎么样呢!
  指针 - 指针的运算
  操作符的优先级
  ++ 对指针的影响
  [] *() 的理解
  指针的运算
☁️ 这些就是全部指针 and 数组的全部知识的总结了,不知道大家掌握的怎么样呢?
看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
拜托拜托这个真的很重要!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。
在这里插入图片描述

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

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

相关文章

Delphi Architect Crack,部署支持Swagger

Delphi Architect Crack,部署支持Swagger 单一代码库-用更少的编码工作为所有主要平台创建应用程序。写一次&#xff0c;到处编译。 Windows-使用最新的用户界面控件、WinRT API和HighDPI相关功能&#xff0c;使Windows的VCL应用程序现代化。 远程桌面-使用改进的VCL和IDE远程桌…

【ONE·Linux || 基础IO(二)】

总言 文件系统与动静态库相关介绍。 文章目录 总言2、文件系统2.1、背景知识2.2、磁盘管理2.2.1、磁盘文件系统图2.2.2、inode与文件名 2.3、软硬链接 3、动静态库3.1、站在编写库的人的角度&#xff1a;如何写一个库&#xff1f;3.1.1、静态库制作3.1.3、动态库制作 3.2、站在…

第一百二十二天学习记录:C++提高:STL-vector容器(上)(黑马教学视频)

vector基本概念 功能&#xff1a; vector数据结构和数组非常相似&#xff0c;也称为单端数组 vector与普通数组区别&#xff1a; 不同之处在于数组是静态空间&#xff0c;而vector可以动态扩展 动态扩展&#xff1a; 并不是在原空间之后续接新的空间&#xff0c;而是找更大的内…

【Spring Cloud 五】OpenFeign服务调用

这里写目录标题 系列文章目录背景一、OpenFeign是什么Feign是什么Feign的局限性 OpenFeign是什么 二、为什么要有OpenFeign三、如何使用OpenFeign服务提供者order-servicepom文件yml配置文件启动类实体ParamController 服务消费者user-servicepom文件yml配置文件启动类接口类Us…

vue3—SCSS的安装、配置与使用

SCSS 安装 使用npm安装scss&#xff1a; npm install sass sass-loader --save-dev 配置 配置到全局 &#x1f31f;附赠代码&#x1f31f; css: {preprocessorOptions: {scss: {additionalData:import "./src/Function/Easy_I_Function/Echarts/ToSeeEcharts/utill.…

嵌入式软件工程师和嵌入式硬件工程师的区别

嵌入式软件工程师和嵌入式硬件工程师的区别&#xff1a; 什么是嵌入式工程师&#xff1f;在我们生活中离不开电子产品&#xff0c;大件的比如冰箱、空调、洗衣机&#xff0c;到小件的比如音箱、剃须刀等。要设计这些电子产品除了外观设计之外还有一些核心的部件就是电路板&…

使用css和js给按钮添加微交互的几种方式

使用css和js给按钮添加微交互的几种方式 在现实世界中&#xff0c;当我们轻弹或按下某些东西时&#xff0c;它们会发出咔嗒声&#xff0c;例如电灯开关。有些东西会亮起或发出蜂鸣声&#xff0c;这些响应都是“微交互”&#xff0c;让我们知道我们何时成功完成了某件事。在本文…

大数据Flink(五十五):Flink架构体系

文章目录 Flink架构体系 一、 Flink中的重要角色 二、Flink数据流编程模型 三、Libraries支持

最全大数据毕业设计题目 - 100例

文章目录 0 前言1 如何选题1.1 选题技巧&#xff1a;如何避坑(重中之重)1.2 为什么这么说呢&#xff1f;1.3 难度把控1.4 题目名称1.5 最后 2 大数据 - 选题推荐2.1 大数据挖掘类2.2 大数据处理、云计算、区块链 毕设选题2.3 大数据安全类2.4 python大数据 游戏设计、动画设计类…

PyTorch代码实战入门

人这辈子千万不要马虎两件事 一是找对爱人、二是选对事业 因为太阳升起时要投身事业 太阳落山时要与爱人相拥 一、准备数据集 蚂蚁蜜蜂数据集 蚂蚁蜜蜂的图片&#xff0c;文件名就是数据的label 二、使用Dataset加载数据 打开pycharm&#xff0c;选择Anaconda创建的pytorch环…

深度学习(34)—— StarGAN(2)

深度学习&#xff08;34&#xff09;—— StarGAN&#xff08;2&#xff09; 完整项目在这里&#xff1a;欢迎造访 文章目录 深度学习&#xff08;34&#xff09;—— StarGAN&#xff08;2&#xff09;1. build model&#xff08;1&#xff09;generator&#xff08;2&#…

ORACLE常用基础

. 1.oracle开机启动流程 su - oracle lsnrctl start lsnrctl status sqlplus / as sysdba startup 2、如何查看数据库版本 select * from v$version; 3.如何查看用户从那个设备连接的数据库 SELECT DISTINCT machine , terminal FROM V$SESSION; 4.如何查看表结构 selec…

css实现水平居中

代码示例 <div class"box"><div class"box1"></div> </div>1.弹性布局&#xff1a;&#xff08;推荐&#xff09; display:flex&#xff1b; 这些要添加在父级的&#xff0c;是父级的属性 //父级添加display:flex; //父级添加jus…

docker安装MinIO

简介 Minio 是一个面向对象的简单高性能存储服务。使用 Go 语言编写&#xff0c;性能高、具有跨平台性。 Minio 官网为&#xff1a;https://min.io &#xff0c;有一个中文站点&#xff0c;单内容更新不是很及时&#xff0c;建议从原始官网学习。 本文采用 Docker 安装&…

Compose:从重组谈谈页面性能优化思路,狠狠优化一笔

作者&#xff1a;晴天小庭 前言&#xff1a; 随着越来越多的人使用Compose开发项目的组件或者页面&#xff0c;关于使用Compose构建的组件卡顿的反馈也愈发增多&#xff0c;特别是LazyColumn这些重组频率较高的组件&#xff0c;因此很多人质疑Compose的性能过差&#xff0c;这…

Filebeat+ELK 部署

Node1节点&#xff08;2C/4G&#xff09;&#xff1a;node1/192.168.8.10 Elasticsearch Kibana Node2节点&#xff08;2C/4G&#xff09;&#xff1a;node2/192.168.8.11 Elasticsearch Apache节点&#xff1a;apache/192.168.8.13 …

神码ai伪原创工具【php源码】

大家好&#xff0c;小编为大家解答python炫酷烟花表白源代码的问题。很多人还不知道html代码烟花特效python&#xff0c;现在让我们一起来看看吧&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 目录 前言 环境准备 代码编写 效果展示 前言 Python实现浪漫的烟花特效 现在…

HTTP协议 和 HTTPS协议的区别(4点) HTTPS的缺点 HTTP如何使用SSL/TLS协议加密过程 CA证书干啥的

&#xff08;一&#xff09;HTTP协议 和 HTTPS协议的区别&#xff08;4点&#xff09;&#xff1a; 1. HTTP协议的端口号是80&#xff0c; HTTPS协议的端口号是443 2. HTTP协议使用的URL是以 http:// 开头&#xff0c;HTTPS协议使用的URL是以https://开头 3. HTTP协议和HTTP…

PHP8的运算符-PHP8知识详解

运算符是可以通过给出的一或多个值&#xff08;用编程行话来说&#xff0c;表达式&#xff09;来产生另一个值&#xff08;因而整个结构成为一个表达式&#xff09;的东西。 PHP8的运算符有很多&#xff0c;按类型分有一元运算符、二元运算符、三元运算符。 一元运算符只对一…

ruby调试

如果下载 ruby-debug-ide gem install ruby-debug-ide vscode 下载 ruby扩展 1&#xff0c; ruby 2&#xff0c;修改launch.json