当前位置: 首页 > news >正文

【C语言】深度理解指针(下)

一. 前言💎

昨晚整理博客时突然发现指针还少了一篇没写,今天就顺便来补一补。上回书说到,emmm忘记了,没事,我们直接进入本期的内容:

本期我们带来了几道指针相关笔试题的解析,还算是相对比较轻松的。话不多说,让我们来看看吧👀

哦对了,如果对前两期有兴趣的话可以点击以下链接进行跳转:

【C语言】深度理解指针(上)
【C语言】深度理解指针(中)

二. 经典笔试题详解✨

1. 笔试题NO.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
  • 首先,在*(a+1)中,数组名a单独出现,代表首元素地址,则a+1为第二个元素地址,解引用后就是2。这相比大家都没有问题。

  • 关键在于第二个,&a是取出的是整个数组的地址,+1后指针就越过数组指向下一个位置。但是由于强转为整形指针赋给了ptr,因此ptr-1其实是移动了一个整形4个字节的大小而不是移动了整个数组的大小,因此(ptr-1)就回到了最后一个元素,解引用后即为5。

2. 笔试题NO.2

//程序的结果是什么?
struct Test{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
答案是:
10000014
10000001
10000004
  • 首先第一步:通过计算可以得出Test结构体类型的大小为20个字节(不会求的可以查阅鄙人上期相关内容)。

  • 然后看第一个:p是一个结构体类型的指针,0x代表16进制,因此p+1就是指针向后移动了一个结构体类型20个字节。这里可能会有疑问,移动了20个字节,那不应该是10000020吗?这里需要注意的是,%p打印出来的地址是以16进制的方式来表示的,而20=16+4,用16进制来表示正好就是14,所以答案是10000014而不是10000020。

  • 然后第二个:将p强制类型转换为无符号长整形。虽说进行了强制,但也只是强转,并没有改变变量p在内存中存放的数据。由于p变成了无符号长整形,所以p+1就不再是指针的加减了,而是普通的算术加减,p+1的值就为10000001。

  • 第三个也很好办,将p强转为无符号整形指针,p+1就向后移动了4个字节,也就是一个无符号整形的大小,最后的值为10000004。

3. 笔试题NO.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和2000000。这道题还是挺有意思的,不急,听我慢慢道来。
  • 第一个答案应该没有疑问:&a取出的是整个数组的地址,+1后越过数组指向下一位置,强转成整形指针后赋给ptr1,而ptr1[-1]就相当于*(ptr-1)。发现了没有,与我们第一道题一模一样,最后的答案就是最后一个元素4。

  • 有意思的是第二个:a为数组名,代表首元素地址,将a强转为整形然后+1后再强转为整形指针赋给ptr2,与上一题同理,最终ptr2实际上只偏移了1个字节,即指向第一个元素的第二个字节处。那么第一个元素1的第二个字节到底是什么呢?这就要取决于多字节数据在内存中的存储方式了,分为以下两种:

大端模式(big endian):将数据的低字节保存到内存的高地址处
小端模式(little endian):将数据的低字节保存到内存的低地址处
注:一般我们日常使用的计算机都是以小端模式进行存储

那么,根据题目的要求,我们可以画出数组在小端机器上内存的存储情况(数据的表示均为16进制):

  • 由于ptr2是整形指针,解引用就向后访问4个字节依次取出00,00,00,02。而由于我们是小端模式,低地址为数据的低字节位,因此最终*ptr的值就为02000000,与答案相符。

4. 笔试题NO.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。
  • 本题不难,就是要注意到数组初始化里面是小括号而不是花括号。初始化列表里面是三条逗号表达式,每个逗号表达式的值都是最后一个表达式的值,即(0,1)==1;(2,3)==3;(4,5)==5。因此整个数组其实就初始化了3个数,如下:

  • 由于p=a[0],因此p就表示第一个一维数组的数组名,因此p[0]就是这个一维数组的第一个元素1。

5. 笔试题NO.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;
}
答案是FFFFFFFC和-4。本题最好的解决方式是画图,通过画图我们可以很明显直观的看出答案:
  • 我们画出如上的示意图,其中&p[4][2]与&a[4][2]的位置如上图所示👆注意,p是个指向含4个整形元素的数组的指针,因此p每次+1都越过4个整形的空间。

  • 两个指针相减的结果就是两个指针之间的元素个数。我们看图发现&p[4][2]和&a[4][2]之间有4个元素,由于是低地址减去高地址,因此最后的结果就为-4,而-4用%p来打印就是FFFFFFFC(16进制)

6. 笔试题NO.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。
  • &aa为取出的是数组的地址,+1后越过整个二维数组指向下一位置。然后将其强转为int*指针赋给ptr,此时由于ptr是整形指针,-1偏移一个整形的大小指向数组的最后一个元素,即10。

  • *(aa+1)等价于aa[1],是第二个一维数组的数组名,数组名代表首元素地址,因此ptr2-1就偏移了一个整形的大小指向上一个数组的最后一个元素,即5。

7. 笔试题NO.7

//程序的结果是什么?
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;
}
答案是at
  • 字符串常量的字面值是其首元素的地址。因此a数组的元素实际上是三个char*类型的指针,每个char*指针指向对应的字符串,如下:

  • a是数组名,代表首元素地址,由于首元素是char*类型的指针,因此用二级指针pa接收。

  • pa是首元素地址,+1后即为第二个元素的地址,解引用后即为第二个元素。结合上图我们可以得出第二个元素就是字符串at的首元素地址,因此按照%s格式打印后结果为at。

8. 笔试题NO.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
  • 我的天,这是嘛呀,太吓人了吧这些表达式!不急,我们画个图先:

  • 根据题目我们画出了如上关系图👆。首先是第一个:cpp指向cp数组的第一个元素,++cpp即指向cp数组第二个元素,因此*++cpp值为c+2。而c+2又指向c[2],因此**++cpp最终就为c[2]。c[2]为字符串"POINT"的首元素地址,按照%s来打印即为POINT。

  • 然后是第二个:需要注意的是,前一条语句中cpp已经++自增一次了,自增后关系图如下:

  • 同理,++cpp即指向cp的第三个元素,解引用后即为c+1,而c+1指向c[1],因此再--后就为c[0],即*--*++cpp的结果为c[0],c[0]是字符串"ENTER"的首元素地址,+3后即指向字符E,用%s打印后结果为ER。

  • 接着是第三个:依旧要根据上条语句的自增自减语句对关系图进行更新:

  • cpp[-2]可以等价为*(cpp-2),即为c+3,再对其解引用后为c[3],c[3]为字符串"FIRST"的首元素地址,+3后就指向字符S,用%s打印后结果为ST。

  • 最后是第四个:由于上一步没有自增自减语句,因此关系图不变:

  • cpp[-1][-1]可以等价为*(*(cpp-1)-1)。cpp-1指向cp第二个元素,解引用后即为c+2。然后c+2指向c数组的第3个元素,-1并解引用后即为c数组的第2个元素c[1]。然后c[1]为字符串"NEW"的首元素地址,+1后即指向字符E,用%s打印后结果为EW。

三. 总结✈

做完这8道题目,不得不说,画图真的是一个非常好的解题方法。有些题目,尽管看似十分复杂,当我们把示意图画出来时,问题就迎刃而解,非常直观。因此我们在日常分析题目时要擅于画图。
通过这三期的学习,相信我们对指针有了较深的理解,赶紧下去尝试尝试吧,可千万不要一看就会,一写就废😁

以上,就是本期的全部内容啦🌸

制作不易,能否点个赞再走呢🙏

相关文章:

【C语言】深度理解指针(下)

一. 前言&#x1f48e;昨晚整理博客时突然发现指针还少了一篇没写&#xff0c;今天就顺便来补一补。上回书说到&#xff0c;emmm忘记了&#xff0c;没事&#xff0c;我们直接进入本期的内容:本期我们带来了几道指针相关笔试题的解析&#xff0c;还算是相对比较轻松的。话不多说…...

【树与二叉树】树与二叉树的概念及结构--详解介绍

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录1.树概念及结构1.1 树…...

Spring Boot集成RocketMQ实现普通、延时、事务消息发送接收、PULL消费模式及开启ACL | Spring Cloud 30

一、前言 在前面我们通过以下章节对RocketMQ有了基础的了解&#xff1a; docker-compose 搭建RocketMQ 5.1.0 集群&#xff08;双主双从模式&#xff09; | Spring Cloud 28 docker-compose 搭建RocketMQ 5.1.0 集群开启ACL权限控制 | Spring Cloud 29 现在开始我们正式学习…...

人人都能看懂的Spring源码解析,Spring如何解决循环依赖

人人都能看懂的Spring源码解析&#xff0c;Spring如何解决循环依赖原理解析什么是循环依赖循环依赖会有什么问题&#xff1f;如何解决循环依赖问题的根本原因如何解决为什么需要三级缓存&#xff1f;Spring的三级缓存源码走读Spring的三级缓存提前暴露getSingleton方法总结往期…...

Linux上搭建Discuz论坛

一.准备工作 1.下载php*&#xff0c;mariadb-server 2.上传Discuz3.5压缩包并解压 二.搭建过程 基于redhat 9 版本和Discuz3.5&#xff0c;php8.0&#xff0c;mariadb10.5演示 一.准备工作 1.下载php*&#xff0c;mariadb-server [rootredhat9 aaa]# yum install -y php*…...

【蓝桥杯专题】 树状数组(C++ | 洛谷 | acwing | 蓝桥)

菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 &#xff08;C | 洛谷 | acwing | 蓝桥&#xff09;什么是线段数组??1264. 动态求连续区间和数星星线段树AcWing 1270. 数列区间最大值PPPPPPP【蓝桥杯专题】 &#xff08;C | 洛谷 | acwing | 蓝桥&#xff09; 什么是…...

QCefView编译配置(Windows-MSVC)(11)

QCefView编译配置&#xff08;Windows-MSVC&#xff09; 文章目录QCefView编译配置&#xff08;Windows-MSVC&#xff09;1、概述2、准备工作3、添加环境变量4、更换cef源码版本5、CMake构建6、Visual Studio编译7、安装编译后的文件8、验证编译结果更多精彩内容&#x1f449;个…...

Token原理

Q&#xff1a;分布式场景下如何生成token以及使用token的流程&#xff1a; 在分布式场景下&#xff0c;可以采用以下方式生成 token 和进行权限认证&#xff1a; 1. 生成 token&#xff1a; 使用JWT&#xff08;JSON Web Token&#xff09;生成 token。JWT 是一种基于 JSON …...

③【Java组】蓝桥杯省赛真题 持续更新中...

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 蓝桥杯真题--持续更新中...一、错误票据题目描…...

linux实验之shell编程基础

这世间&#xff0c;青山灼灼&#xff0c;星光杳杳&#xff0c;秋风渐渐&#xff0c;晚风慢慢 shell编程基础熟悉shell编程的有关机制&#xff0c;如标准流。学习Linux环境变量设置文件及其内容/etc/profile/etc/bashrc/etc/environment~/.profile~/.bashrc熟悉编程有关基础命令…...

C语言小程序:通讯录(静态版)

哈喽各位老铁们&#xff0c;今天给大家带来一期通讯录的静态版本的实现&#xff0c;何为静态版本后面会做解释&#xff0c;话不多说&#xff0c;直接开始&#xff01;关于通讯录&#xff0c;其实也就是类似于我们手机上的通讯录一样&#xff0c;有着各种各样的功能&#xff0c;…...

写CSDN博客两年半的收获--总结篇

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;练习时长两年半的java博主 &#x1f39f;️个人主页&#xff1a;君临๑ ps&#xff1a;点赞是免费的&#xff0c;却可以让写博客的作者开心好几天&#x1f60e; 不知不觉间&#xff0c;在csdn写博客也有两年半的时间了&#x…...

中科亿海微FPGA应用(一、点灯)

1.软件&#xff1a; https://download.csdn.net/download/weixin_41784968/87564071 需要申请license才能使用&#xff1a;软件试用申请_软件试用申请_中科亿海微电子科技&#xff08;苏州&#xff09;有限公司 2.开发板&#xff1a; 芯片EQ6HL45&#xff0c;42.5k LUT。 3…...

ElasticSearch - SpringBoot整合ES:实现搜索结果排序 sort

文章目录00. 数据准备01. Elasticsearch 默认的排序方式是什么&#xff1f;02. Elasticsearch 支持哪些排序方式&#xff1f;03. ElasticSearch 如何指定排序方式&#xff1f;04. ElasticSearch 如何按照相关性排序&#xff1f;05. ElasticSearch 查询结果如何不按照相关性排序…...

IDEA的全新UI可以在配置里启用了,快来试试吧!

刚看到IDEA官方昨天发了这样一条推&#xff1a;IDEA的新UI可以在2022.3版本上直接使用了&#xff01;开启方法如下&#xff1a;打开IDEA的Setting界面&#xff0c;在Appearance & Behavior下有个被标注为Beta标签的New UI菜单&#xff0c;具体如下图&#xff1a;勾选Enable…...

第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移

文章目录第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移备份处于活动状态时自动进行故障转移备份不活动时的自动故障转移对各种中断场景的镜像响应响应主要中断场景的自动故障转移第九章 镜像架构和规划 - 备份处于活动状态时自动进行故障转移 备份处于活动状态…...

Barra模型因子的构建及应用系列七之Liquidity因子

一、摘要 在前期的Barra模型系列文章中&#xff0c;我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子、NonLinear Size因子和Book-to-Price因子&#xff0c;并分别创建了对应的单因子策略&#xff0c;其中Size因子和NonLinear Siz因子具有很强的收益能力…...

走进二叉树的世界 ———性质讲解

二叉树的性质和证明前言1.二叉树的概念和结构特殊的二叉树&#xff1a;二叉树的性质前言 本篇博客主要讲述的是有关二叉树的一些概念&#xff0c;性质以及部分性质的相关证明&#xff0c;如果大伙发现了啥错误&#xff0c;可以在评论区指出&#x1f618;&#x1f618; 1.二叉树…...

【SSM】Spring + SpringMVC +MyBatis 框架整合

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ SSM框架整合一、导入相关依赖二、配置web.xml文…...

【算法基础】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;算法、数据结构、Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: 算法 &#xff1b;该专栏专注于蓝桥杯和ACM等算法竞赛&#x1f525;近期目标&…...

第二十三天01MySQL多表查询与事务

目录 1. 多表查询 1.1 概述 1.1.1 数据准备 1.1.2 介绍 1.1.3 分类 1.2 内连接 1.2.1 语法 1.2.2 案例演示 1.3 外连接 1.3.1 语法 1.3.2 案例演示 1.4 子查询 1.4.1 介绍 1.4.2 标量子查询 1.4.3 列子查询 1.4.4 行子查询 1.4.5 表子查询 1.5 案例 1.5.1 介…...

TCP协议详解

1.TCP的准备条件在古代的时候&#xff0c;古人们经常写书信进行交流&#xff0c;写书信的前提是你要知道这份信是要寄给谁在网络中&#xff0c;我们通过ip端口号找对目标对象&#xff0c;但是现在网站一般会对ip端口注册一个域名&#xff0c;所以我们一般就是对域名进行查找&am…...

Activiti7与Spring、Spring Boot整合开发

Activiti整合Spring 一、Activiti与Spring整合开发 1.1 Activiti与Spring整合的配置 1)、在pom.xml文件引入坐标 如下 <properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version> </properties> <d…...

基于SpringBoot实现冬奥会运动会科普平台【源码+论文】

基于SpringBoot实现冬奥会科普平台演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#…...

一文吃透SpringBoot整合mybatis-plus(保姆式教程)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

C++ primer plus(第六版)编程练习答案 第4章 复合类型

一、程序清单 arrayone.cpp // arrayone.cpp -- small arrays of integers #include <iostream> int main() {using namespace std;int yams[3]; // creates array with three elementsyams[0] = 7; // assign value to first elementyams[1] = 8;yams[2] = 6;i…...

Kafka源码分析之Producer(一)

总览 根据kafka的3.1.0的源码example模块进行分析&#xff0c;如下图所示&#xff0c;一般实例代码就是我们分析源码的入口。 可以将produce的发送主要流程概述如下&#xff1a; 拦截器对发送的消息拦截处理&#xff1b; 获取元数据信息&#xff1b; 序列化处理&#xff1b;…...

springboot校友社交系统

050-springboot校友社交系统演示录像开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;e…...

python flask项目部署

flask上传服务器pyhon安装下载Anacondasudo wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.1-Linux-x86_64.sh可根据需要安装对应的版本https://repo.anaconda.com/archive/解压anaconda压缩包bash Anaconda3-5.3.1-Linux-x86_64.sh解压过程中会…...

常见排序算法(C语言实现)

文章目录排序介绍插入排序直接插入排序希尔排序选择排序选择排序堆排序交换排序冒泡排序快速排序递归实现Hoare版本挖坑法前后指针版本非递归实现Hoare版本挖坑法前后指针版本快排的优化三值取中小区间优化归并排序递归实现非递归实现计数排序排序算法复杂度及稳定性分析不同算…...