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

指针 (八)例题深度解析

有关于指针的基本知识点我们都已经讲解完了,不出意外的话,这一篇就是我们指针的最后一期了,今天我们就来看一看一些有关于指针运算的例题:

每一道题诸君都应该有着自己先独立思考的能力,咱们不要怕面对,不管分析的对不对,努力去迈出那第一步,咱们就已经成功了一半了,加油加油加油!

题目一:

解析:

第一行咱就不说了昂,整数数组嘛,我相信能看到这一期的诸君已经能够一瞬间理解第一行了。第二行:先取出 a 的地址,这个时候数组名 a 表示的是整个数组的地址,再 + 1 就是跳过整个数组,这个时候地址指向的就是紧接着数组后面的这个位置。(int*)的含义就是强转,将数组第二个元素的地址强制类型转换为 int 类型,然后再将其赋给我们的指针变量—— ptr,接下来就是打印了

(1)*(a + 1):这里的数组名 a 就表示首元素地址,+ 1 就是第二个元素的地址,再解引用,打印的就是 2

(2)*(ptr - 1):上面分析了指针变量 ptr 里存放的是整个数组后面这个位置的地址,- 1 自然就是向后移一位,对其解引用自然就是 5

题目二:

解析:

上面这个结构体的最后,是将这个地址—— 0x100000 先强转为 struct test 类型,再赋给我们创建的指针变量 *p 

第一个打印: p 是我们的指针变量,里面放着我们赋值的 0x100000,加一个0x1,虽然这个数是16进制位,但 16 进制的 1 依旧是 1 ,又由于我们的指针变量 p 是一个结构体指针,我们这里设定的这个结构体大小为 20 字节,+ 1 跳过的是一整个结构体,也就是 20 字节,那么 20 字节在16进制中的表示是什么呢?是 14,所以这里的打印结果应该是 0x100014

第二个打印:将我们的 p 强制类型转换为 “ unsigned long ” 类型。这是整型类型,我们再加 0x1 也是整型,所以直接相加。打印结果为 0x100001

第三个打印:将我们的 p 强制类型转换为 “ unsigned int* ” 指针类型。这里的加 0x1 的意思是加上一个整型类型,打印结果为 0x100004

题目三:

解析:

创建了一个二维数组,再创建一个指针变量 p ,将数组首元素地址赋值给我们的变量 p ,再将其打印出来。这道题大家可以先思考一下,可能很多人得出的答案都是:0,心想这么简单的的题,一下就算出来了。众所周知昂,越是简单的题越是藏着坑,这题也有一个小坑,那就是关于二维数组内元素的表现形式,我们二维数组元素内,是可以使用括号来更明显的分段帮助理解的,但是呢,我们应该用大括号——{},而不是小括号——(),我们小括号的运算逻辑是从左向右依次运算,如果有多个运算结果,那么只取最右端为结果,所以我们二维数组内实际的元素只有三个:1、3、5,那么我们的首元素自然就是 1 了

我们所想的真正的二维函数是这样的:

题目四:

解析:

这里创建了一个二维数组,紧接着创建一个数组指针,将二维数组名(首元素地址,也就是这个二维数组第一行的地址)先强转为指针数组类型,再赋值给我们的数组指针变量 p ,且 p 每行是 4 个整型大小。接着就是打印,前一个为地址打印,后一个就是普通打印

我们的二维数组在内存中实际上是连续储存的,所以为了更好的理解,我们可以将其看做是一个一维数组的格式。我直接在图上给大家演示:

有图可知,我们找出了p [4] [2] 和 a [4] [2] 所指向数组中的位置

我们再来看需要打印的:&p [4] [2] - &a [4] [2] = - 4(地址相减得到的是地址之间的元素个数)

由于第一个打印是地址,那么我们 - 4 的地址是什么呢?这个就要涉及到我们的原、反、补了

综上所述,我们最终的打印结果应该是:

题目五:

解析:

首先给出一个二维数组 aa [2] [5] ,然后设立了两个指针变量 ptr1、ptr2,我们分别来看

ptr1:&aa,取出二维数组aa的地址,这里取出的就是整个二维数组的地址,+ 1 自然就是跳过整个数组,也就是说此时我们的 ptr1 指向的是我们二维数组后的那个位置

ptr2:单独出现数组名,没有sizeof,所以这里就是我们的首元素地址,就是 aa [0],在二维数组中的第一行地址,再 + 1 自然就是 aa [1] 咯,也就是第二行第一位元素的地址

有细心的小伙伴可能发现了,在赋值给指针变量的时候还有一个 int * 的强转,不过这个强转没啥用哈,这个数组本身就是 int 整型的

最后我们来看一下打印结果:

题目六:

这里编译器报警告了昂,这是因为我使用的是C++文件,程序审核比较严格,我们题目是将三个字符串放进这个指针数组里面,原则上这是不被允许的

解析:

这个题涉及到二级指针,我们干看着不太容易理解,我直接在图上为诸君解析一下:

我们将这字符串强行赋给指针数组中,实际上是存放的这三个字符串首字符地址,类型都是 char*,然后再将数组 a 赋值给我们的二级指针 pa ,a 是数组名,也就是首元素地址,所以这里 pa 里存放的是 a 中下标为 0 的地址,pa++ = pa+1,也就是跳过一个字节,此时指向了我们下标为 2 的位置,对其解引用得到了第二个字符的首元素地址,再将其打印,又因为我们的字符串的末尾是隐藏着一个 '\0' 的

所以最终的打印结果就是:at (这里因为编译器会报错,所以我就不打印了)

题目七:

解析:

对于题目中各个指针数组的解析,上面那题讲解的很清楚了,咱就不过多赘述了

* * + + CPP:这里是前置 ++ ,也就是先做 ++ 运算,再对其解引用,本来的 cpp,应该是指向的指针数组 cp 中的首元素,++ 过后,跳过一个字节,此时指向的第二个元素,也就是 C + 2 的下标,对其一次解引用就是 cp 中的 C + 2 ,二次解引用就是 c 中的第三位元素的地址 —— p 的地址,所以打印结果应该为:POINT

* - - * + + C P P + 3:这一个运算就比较复杂了,涉及到我们 C 语言运算符的优先级考虑,之前出过两期操作符详解,感兴趣的小伙伴可以去回顾一下哈:C语言中操作符详解(二)-CSDN博客

言归正传,首先,我们的三级指针 cpp 在第一个打印中已经经过了一次运算:++ cpp,这个运算是会保留的哈,并不是说只是走个过程,所以我们在第二个打印这里的 cpp 已经是指向了 C + 2 的位置,然后考虑我们的运算符优先级,++、-- 的优先级是最高的,然后是解引用 *,再是普通的+。按照这个顺序我们来思考。先做 ++ ,此时指针来到我们的 C + 1 位置,对其解引用,找到这个元素: C + 1,再进行 - - ,这不就是 C 了么。再对其解引用找到字符串 “ ENTER ” 首字母 E 的地址,最后 + 3 就是跳过三个字节来到倒数第二这个 E ,然后打印,所以最后的打印结果就是:ER

* C P P [ -2 ] + 3:这个就更有意思了,下标出现了一个 - 2,大家可能看的一头雾水,心想,这是什么啊?哪还有下标为 - 2 的道理哦。其实道理嘛,万变不离其宗,咱们得透过表相看本质,只要我们来举个简单的例子,聪明的诸君立马就会如醍醐灌顶般理解了:

arr [ 0 ] 是不是就等于 * (arr + 0),同理,arr [ 1 ] == *(arr + 1)

那么 arr [ -2 ] == *(arr - 2)

诸君是不是一下就明白了

OK,咱们继续,由于经过上面的两次计算,此时我们的 cpp 已经指向了 C + 1 的位置,在这个基础上 - 2 也就是回到了 C + 3 的位置,对其解引用也就是找到了我们 c 中 F 的位置,再 + 3 就是向后跳过三个字节,所以最终的打印结果为:ST

C P P [ -1 ] [ -1 ] + 1:这里又出现了二维数组的形式,不过不要怕,咱们一层一层地来剖析它。有的小伙伴看到二维数组的形式就怕了,不要怕嘛,这些都是纸老虎,经过我们上一道题的解析,再来看这个不也是一样的原理么:c p p [ -1 ] [ -1 ] == *(*(c p p - 1)- 1),我们此时的 c p p 可还是指向的 C + 1 的位置,因为第三次打印不是自加或自减的形式,其运算过程并不会对其本身造成改变,所以先 - 1 指向了 C + 2 的位置,再 - 1 得到 C + 1,然后再解引用找到我们 c 中 N 的地址,再 + 1 跳过一个字节,所以最终打印结果为:EW

OKK,咱们有关于指针的知识点到此就告一段落啦,这部分很难理解,文字毕竟是生硬的,大家应该多找一些网课看一看,并且自己多加练习,我也会继续努力,咱们一起加油!好了,那咱们闲话少说,下期再见吧,与诸君共勉!!!


http://www.mrgr.cn/news/46607.html

相关文章:

  • EE213 Lab virtuoso final project SRAM designlayout
  • c++ haru生成pdf输出文本实例
  • GARCH指导的神经网络在金融市场波动性预测中的应用
  • Java Stream流操作List全攻略:Filter、Sort、GroupBy、Average、Sum实践
  • VMWARE linux LVM 扩容磁盘分区
  • Pytorch通信算子组合测试
  • 【093】基于SpringBoot+Vue实现的精品水果线上销售系统
  • Python 入门教程(6)函数 | 6.1、函数定义
  • ICE/TURN/STUN/Coturn服务器搭建
  • 多线程—— Thread 类及常见用法(详解)
  • 【测开】接口路由分类与技巧,GraphQL,WebSocket,RESTFUL方法(PUT、PATCH、OPTIONS、HEAD、TRACE)
  • 如何在IDEA使用git上传代码的时候过滤掉非.java文件
  • Chatgpt 原理解构
  • 用于图像识别的判别图正则化技术
  • std::packagedtask概念和使用方法
  • JUC高并发编程8:读写锁
  • 算法:双指针系列(一)
  • 车载SerDes历史和发展概述
  • 【C++】面向对象之继承
  • 图的最短路径算法
  • llama3 implemented from scratch 笔记
  • 解决触摸屏屏幕乱动的问题:E: 无法定位软件包 libinput
  • k8s的pod的管理
  • Python基础之List列表用法
  • 有趣的队列
  • 云服务器使用