(番外篇)指针的一些相关习题讲解(速进,干货满满)(2)

前言:

  小编感觉最近有点太堕落,于是我开始从事这篇文章的撰写,现在也是进入七月份了,我现在文章开头定一个小目标,我决定在七月份发布至少十篇文章,希望我可以说到做到(我前面就口头欠了不少文章),好了,不多废话了,下面进入今天的主题,对于指针习题的演练,这些题都是小编在上课时听到的题,为了加强自己的记忆,于是我将此作为文章的主题,下面进入正文喽

目录:

1.题目一

2.题目二

3.题目三

4.题目四

5.题目五

6.题目六

7.题目七

 正文:

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函数,里面第一个元素是*(a + 1),此时a是数组名,它不是那两种特殊情况,所以此时数组名代表的就是数组第一个元素,加1后对应着数组第二个元素的地址,在进行解引用操作后,会直接呈现第二个元素,那么就是2了;之后是第二个元素,此时涉及到了ptr,所以我们先看ptr这个指针,它代表着进行整型强制类型转换以后的(&a + 1),不难发现,此时数组名符合了第一种特殊情况,所以代表着整个数组的地址,加1后是数组最后一个元素下行的地址,此时指针指向的应该是5后面元素的地址,此时减去1后,又回到了数组第五个元素代表的地址,所以进行解引用操作后,变成了5,为了让读者更好的理解这个题目,小编特意的给了图例进行解释:

 

  通过上图可以清晰的看出小编在文字解释中所解释的内容,下面小编展示这个代码的运行图:

  可以看出小编解释的是正确定,下面废话不多说,进入下一个题的训练:

2.题目二 

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

    老规矩,大家先思考几秒,然后给出解释,下面开始解释环节:首先映入我们眼帘的是一个结构体,由于结构体的大小如何计算小编还没有设计到,所以这里直接给大小了(后面小编会着重强调它的对齐方式的在结构体的文章中),这里我们已经给出了结构体的地址,不过这个地址得强制类型转换,不然就不是结构体的地址了,下面我们正是看看函数部分,首先是第一个printf函数,这个函数内部是结构体指针加1,记住这个加的1是0x开头的,所以应该是16进制的方式进行操作的,此时p是指针,指针加数的话代表着它的地址是要加它本身大小倍数的数,所以此时应该加20个字节,并且由于这是16进制储存的,所最后的结果应该是0x100014;对于第二个printf函数,首先我们先看括号内容,此时括号内容是unsigned long,所以此时的p已经强制类型转换成无符号的长整型了,此时p可以看作一个整数,对于整数加1的话,那就是真的加1,所以结果应该是0x100001;对于第三个printf语句,此时括号里面的内容是unsigned int*,代表着强制类型转换成无符号整型的指针,所以此时指针每次加的大小已经改变了,此时加1代表着加4个字节的空间,所以结果应该是0x100004,这个问题小编认为不需要图来了解,因为这没有牵扯到指针的迁移,仅仅就牵扯到了指针运算,下面来看看此代码的运行图:

   读者朋友无需关注前面是什么,光看末尾数字就好了,此时说明小编解释没有错误,那么我们加快步伐,直接开始看下一个题的讲解!

3.题目三 

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

  老规矩,各位先看会题目,我等会做出解释,下面开始解释:首先这个题定义的二维数组,然后设置了一个整型指针,此时指针指向二维数组第一行的地址,然后printf函数里面的是p[0],此时其实有第二种写法,就是*(*p + 0),此时不难看出,这个是指向数组第一个元素的地址,那么我们回头看看这个二维数组,可能有些读者会脱口而出,答案是0,但是其实这个说法是错误的,仔细看,数组里面每两个元素用什么围起来的,是括号,而不是大括号!所以此时我们对于括号里面的内容,其实是逗号表达式,逗号表达式的逻辑是,从左往右依次计算,不过最后的结果是右边的数,所以其实这个数组在内存中的存放是如下图所示的:

  所以可以知道打印出来的结果应该是1,那么很多读者可能忘记了我们想要规定二维数组行和列具体数应该怎么做,其实这里是要用大括号的,下面是代码展示:

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

  下面是在调试界面此数组的存放:

  所以各位在做相关习题的时候一定要瞪大双眼,防止出题人给你设置成一个大坑让你跳进去,我们要做到看到坑直接绕过去,下面不多废话直接上运行页:

   可以看出小编并没有说错,大家一定要在做题不要看题目过于简单而痛失分数。下面不多废话,调整心态,下个题来喽:

4.题目四

//假设环境是x86环境,程序输出的结果是啥?
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数组的存放图文来帮助大家去感受a数组内容:

   下面我们来正式开始观看这个代码,首先我们看到一个老朋友:int (*p)[4],读者朋友如果已经学完了指针部分,那么很容易看得出这个是数组指针,p代表的是数组,而[4]则代表着里面存放着四个元素,下面我们可以接着看,此时把a首行的地址给了p,此时读者朋友可能会想,a每个里面存放着5个元素,而p里面却存放着4个元素,它们如何建立起联系呢?其实这里不用多考虑,首先,p其实在这里我们可以看做成地头蛇,有句老话这么说,在我的地盘,是龙只能盘着,是虎也得趴着,所以此时每个p里面都存放每个a所对应的四个元素,此时小编也将p在内存中的存放也放到下面了:

  下面我们已经画好了a和p的图,此题其实已经完成了大半部分了,下面我们来看看printf函数里面的内容,这两个元素是一样的,只不过是两种形式表示着,一个是地址,一个是整型,下面我们先来看看元素是什么,分别是p[4][2]和a[4][2],如果没有画图,可能很难看出来这个具体表示着什么,但是现在我们有了图,这就好办了,下面是小编利用图来表示这两个元素 

  此时printf里面存放着是这两个数的地址,小编之前说过,指针和指针相减,得出来的结果是两个指针之间相差的元素的个数,这个小编之前写过的文章说过,下面放上链接,感到兴趣的读者朋友可以看一下:深入理解并打败C语言难关之一————指针(1)-CSDN博客,回归正题,这两个数之间相差的个数是4个,但这个是前者减去后者,所以得出来的结果应该是-4,不过现在的重点是第一个元素是要取到它的地址,所以这里牵扯到了原码反码补码的知识,这些知识小编也会在以后的文章说的(欠的文章+1),所以下面通过代码页来展示-4的反码:

//10000000000000000000000000000100  //原码
//11111111111111111111111111111011 //反码  (原码取反)
//11111111111111111111111111111100   //补码(反码 + 1)

  所以的出来结果应该是下面源码4个为一起通过16进制位数表示出来,应该是0xFFFFFFFC,下面这个题已经讲解完毕,下面进入此题目的运行环节:

  可以看出小编这里并没有说错,这个题有点复杂,读者朋友们如果理解不了的话一定要多看一遍,下面趁热打铁,进入下个题目喽!

 5.题目五

int main()
{int a[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)(*(a + 1));printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}

  如果会了上一个题的话,这个题也是会迎刃而解的,老规矩,读者朋友先思考下这个题,等会小编做出解释,三,二,一,下面给出解释:

  首先,印入我们眼帘的还是一个二维数组,下面小编先来画一下二维数组的储存图来帮助各位取理解:

  这个二维数组的存放就是如图所示的(为了直观小编直接展开成一行了),我们开始看代码页,首先我们先看到的是两个指针,ptr1和ptr2,首先第一个是先对数组名进行取地址操作,此时涉及到了小编之前提到过的特殊情况,所以此时是取到了整个数组的地址,在进行加1就是去到了10以后元素的地址,此时还对他强制类型转化成了整型指针(可能很多读者朋友会很奇怪,认为二维数组不也是整型指针吗,其实二维数组实质是一个数组指针,小编以前可能提到过,如果没提到过大家记住就好),在看ptr2,此时这个指针同样也是对括号里面的内容强制类型转化成整形指针了,下面我们再来看看括号里面的内容,此时是先对a进行加1操作,我们知道,二维数组数组名代表着第一行的地址,所以这个进行加1操作以后直接变成了a[1],在进行解引用操作以后直接变成了第一个元素所代表的地址了,下面为了让读者朋友更好的理解这个题目,直接上图:

  之后我们继续往下看,我们来看看printf函数,此时里面同样也是有两个元素,第一个是对ptr1 - 1,此时ptr已经是整形指针了,所以减1后对应着10这个元素的地址,然后解引用后会变成10;第二个是ptr2 - 1 ,此时ptr2也是整形指针,减去1后代表着5的地址,解引用后是5,下面我们先用图文解释,在来放运行图:

 

  可以看出小编并没有说错,大家在写题目的时候一定要画图,画图可以保证大家做题目时更有思路,提高正确率,下面我们进入下一道题:

6.题目六

 

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

  这个题可能会有一点难度,读者朋友一定要先仔细看看这个题,画出相应的图这个题就好;理解多了,下面小编放上这个题的解析:

  首先,我们看到了一个数组我,这个数组的类型是char *,所以很显然这个数组是个指针数组,下面我们图解这个指针数组:

  通过上图可以清晰的看出这个指针数组的具体内容,之后我们接着看代码,后面的代码是又设置了一个二级指针pa,这个二级指针储存着此指针数组首元素地址的地址,接着看下面的代码,此时是pa++,代表着pa + 1,所以此二级指针变成了储存第二个元素的地址的地址,然后我们继续看下面代码,看出其元素是对二级指针进行解引用,我们知道,二级指针解引用后就变成了其储存元素的地址,此时由于储存着字符串,对字符串的打印我们需要获取字符串的地址,此时正好是第二个元素的地址,所以应该打印出的是"at",下面小编先给图解,然后给运行图:

 

  以上便是运行结果和图解,所以小编这里又一次得强调下,对于这种题一定要画图,画图可以帮助我们解决大部分我们无法解决的问题,下面我们趁热打铁,迎接本篇文章最后一个习题,此习题与本习题同一个做法,大家一定要理解好这个题的做法: 

题目七

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语句里都有什么元素,首先看第一个printf里面的元素,里面是 ** ++ cpp,首先我们知道++操作符运算级是很高的,所以此时是cpp先 加 1,然后此时指向了cp[1]的地址,之后二次解引用操作后,变成指向了c[2]的地址,所以是打印了c[2]所代表的字符串,也就是"POINT",下面小编给上图解:

   下面我们再来看看第二个printf函数里面的元素,这个更是复杂:*-- * ++cpp + 3,此时我们一个一个的看,此时是先进行 ++ cpp的操作,经过上面的printf里面cpp进行加1后,此时在进行加1,cpp指向了cp[2]的地址,此时进行解引用操作后就会变成cp[2],之后我们在进行--操作,此时是代表着cp[2]所指向的内容减1,所以此时cp[2]变成了指向c[0]的地址,再次进行解引用操作以后,此时就是变成了c[0],此时再次进行 + 3操作,代表着数组里面的元素加3,所以我们打印数据就开始从E进行打印,所以最后打印的结果应该是“ER”,下面给上图解:      下面我们继续来看看下一行的代码,此时里面的元素是 : *cpp[-2] + 3 ,我们一九从左往右看,此时是先对于cpp进行解引用操作,由于上面进行了两次 ++ 操作,所以解引用cpp以后里面的元素变成了cp[2],此时有一个[]操作符,其实这个就是再次对cp进行解引用,不过是减2后再解引用,所以此时变成了cp[0],进行解引用后就指向了c[3],此时再次加3代表着里面元素地址加3,所以是从“S”开始打印,最后打印出来的应该是:"ST",下面依旧给上图解来帮助大家理解:

  下面我们再来看最后一个printf函数里面的元素,里面是:cpp[-1][-1] + 1 ,我们依旧从左往右看,此时cpp[-1]其实实际代表着* cpp - 1,所以此时是代表着cp[1],之后的[- 1],代表着 * cp[1] - 1,也就是说最后指向的是c[1],此时在进行 + 1操作后,就代表着从“E”开始进行打印,最后呈现的结果是 “EW”,下面我们依旧用图文进行解释:

   下面我们来放运行结果:

     可以看出雄小编这个题并没有说错,这个题大家一定要好好的去了解,难度系数还是比较大的,这个题也是同样彰显了画图的重要性,大家在做题时一定要好图,这样才不容易出错,也好找到自己的错误。

总结:

  小编也是干完了这篇文章,这也是指针部分的强化篇,指针讲解部分到这里就彻底的结束了,相信各位读者朋友看到小编写过的指针篇幅,大概也知道了指针的重要性,大家一定要好好掌握指针,到现在开始,我们已经返过了C语言的一座大山,希望各位已经明白了指针。最后,如果文章有什么错误,请大家一定在评论区指出,小编会改正自己错误的,那么,我们下篇博客见啦! 

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

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

相关文章

OpenSSL的一些使用案例

目录 一、介绍 二、基本使用 1、Shell (1)文件加解密 (2)生成密钥文件 2、API (1)md5sum (2)AES256加解密 一、介绍 本篇博客重点不是详细描述 OpenSSL 的用法,只…

什么是校园气象站

在科技日新月异的今天,气象观测不仅局限于专业的气象机构,它已经走进了我们的校园,成为了学生们探索自然、学习科学知识的重要平台。 校园气象站是设置在学校内部,用于进行气象观测、数据记录和科学实验的设施。它通常由气象传感器…

常见锁策略之可重入锁VS不可重入锁

可重入锁VS不可重入锁 有一个线程,针对同一把锁,连续加锁两次,如果产生了死锁,那就是不可重入锁,如果没有产生死锁,那就是可重入锁. 死锁 我们之前引入多线程的时候不是讲了一个加数字的案例么,我们今天以它来举例 当我们这样写的时候会出现什么问题? 分析:第一个synchron…

前端基础--Vue3

Vue3基础 VUE3和VUE2的区别 2020年9月18日,Vue.js发布版3.0版本,代号:One Piece 于 2022 年 2 月 7 日星期一成为新的默认版本! Vue3性能更高,初次渲染快55%, 更新渲染快133% 。体积更小 Vue3.0 打包大小减少41%。 同时Vue3可以更好的支持T…

基于微服务智能推荐健康生活交流平台的设计与实现(SpringCloud SpringBoot)+文档

💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

解决使用monaco-editor编译器,编译器展示内容没有超过编译器高度,但是出现滚动条问题

前言: 最近在完成项目时,有使用编译器进行在线编辑的功能,就选用了monaco-editor编译器,但是实现功能之后,发现即使在编译器展示的内容没有超过编译器高度的情况下,编译器依旧存在滚动条,会展示…

计算机网络--网络层

一、网络层的服务和功能 网络层主要为应用层提供端对端的数据传输服务 网络层接受运输层的报文段,添加自己的首部,形成网络层分组。分组是网络层的传输单元。网络层分组在各个站点的网络层之间传输,最终到达接收方的网络层。接收方网络层将运…

如何在 Java 应用中使用 Jedis 客户端库来实现 Redis 缓存的基本操作

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

堆与栈的概念(RTOS)

目录 #堆在RTOS的概念 #相关代码表示 #堆相关特点 #栈在RTOS中的概念 #栈的代码表示 #栈的相关特点 #为什么每个RTOS任务都要有自己的栈 前言:本篇参考韦东山老师的RTOS,连接放在最后 #堆在RTOS的概念 本文所指的堆与栈并不是数据结构中&#xff…

【unity实战】在Unity中使用有限状态机制作一个敌人AI

最终效果 文章目录 最终效果前言有限状态机的主要作用和意义素材下载逻辑图敌人动画配置优雅的代码文件目录状态机代码定义敌人不同状态切换创建敌人效果更多的敌人参考源码完结 前言 有限状态机以前的我嗤之以鼻,现在的我逐帧分析。其实之前我就了解过有限状态机&…

2.(vue3.x+vite)调用iframe的方法(vue编码)

1、效果预览 2.编写代码 (1)主页面 <template><div><button @click="sendMessage">调用iframe,并发送信息

【udp报文】udp报文未自动分片,报文过长被拦截问题定位

问题现象 某局点出现一个奇怪的现象&#xff0c;客户端给服务端发送消息&#xff0c;服务端仅能收到小部分消息&#xff0c;大部分消息从客户端发出后&#xff0c;服务端都未收到。 问题定位 初步分析 根据现象初步分析&#xff0c;有可能是网络原因导致消息到服务端不可达&a…

【C语言】文件的顺序读写

©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 前言字符输入输出函数 - fgetc和fputc文本行输入输出函数 - fgets和fputs格式化输入输出函数 - fscanf和fprintf 前言 对文件数据的读写可以分为顺序…

Seal^_^【送书活动第8期】——《ChatGLM3大模型本地化部署、应用开发与微调》

Seal^_^【送书活动第8期】——《ChatGLM3大模型本地化部署、应用开发与微调》 一、参与方式二、本期推荐图书2.1 作者建语2.2 编辑推建2.3 图书简介2.4 前 言2.5 目 录 三、正版购买 大模型领域 既是繁星点点的未知宇宙&#xff0c;也是蕴含无数可能的广阔天地&#xff0c; 正…

idea创建自定义的maven spark scala archetype脚手架

一&#xff1a;先创建一个Maven项目net.alchim31.maven&#xff08;选该模板&#xff0c;得要等一会儿才能加载出来&#xff09; 之后将自己的目录结构建立好&#xff0c;最好不要有空目录&#xff0c;可能会因为没有文件在install的时候编译不进去 pom中内容也按照自己的需要改…

Stable Diffusion web UI 插件

2024.7.3更新&#xff0c;持续更新中 如果需要在linux上自己安装sd&#xff0c;参考&#xff1a;stable diffusion linux安装 插件复制到 /stable-diffusion-webui/extensions 目录下&#xff0c;然后重新启动sd即可 一、插件安装方法 每种插件的安装方法可能略有不同&#xf…

苹果p12证书最简单最新申请流程

使用uniapp打包&#xff0c;在ios上打正式包需要苹果的p12证书和证书profile文件&#xff0c;点进去uniapp的ios证书申请教程&#xff0c;通篇就是使用mac电脑申请的教程&#xff0c;假如没有mac电脑就无法继续了。 因此&#xff0c;假如没有mac电脑的同志们&#xff0c;可以参…

Pytest+Allure+Yaml+PyMsql+Jenkins+Gitlab接口自动化(五)Jenkins配置

一、背景 Jenkins&#xff08;本地宿主机搭建&#xff09; 拉取GitLab(服务器)代码到在Jenkins工作空间本地运行并生成Allure测试报告 二、框架改动点 框架主运行程序需要先注释掉运行代码&#xff08;可不改&#xff0c;如果运行报allure找不到就直接注释掉&#xff09; …

鸿蒙应用开发-时间屏幕

点击下载源码&#xff1a; https://download.csdn.net/download/liuhaikang/89509449 做一个时间屏幕&#xff0c;可以点击切换白色和黑色&#xff0c;有渐变效果&#xff0c;使用到了鸿蒙的动画效果。 在这个设计中&#xff0c;我们首先引入了通用能力包&#xff0c;以实现功…

Kubernetes 离线安装的坑我采了

Kubernetes 离线安装的坑我采了 一、Error from server: Get "https://xx.xx.xx.xx:10250/containerLogs/kube-system/calico-node-8dnvs/calico-node": tls: failed to verify certificate: x509: certificate signed by unknown authority二、calico 或 pod 启动正…