【c语言】指针 (完结)

一、sizeof和strlen的对比

1、sizeof

      前面我们在学习操作符的时候,我们学习了sizeof,知道其是计算变量所占内存的大小的,单          位是字节,如果操作数是数据类型的话,计算的就是这个类型的变量所占的内存空间的大小单        位也是字节。其计算的结果只与该变量的类型有关,与其存放的集体数据无关。

      还有就是对于要计算的是变量的大小,在语法的写法可以不写小括号,所以我们在阅读代码的        时候对于sizeof计算一个变量没有括号,这个写法也是可以的。当然我们在写代码的时候,建          议还是带上括号会更好一点,这样可以增加我们代码的可读性。

      下面我们通过代码来感受一下:

     
 

           运行结果如下:

             

2、strlen 

     strlens是C语言的库函数,功能是求字符串的长度。其函数原型如下:

    

     统计的是从strlen函数的参数str中的这个地址开始往后,遇到" \0 " 就结束统计,然后返回               " \0 "前面的字符个数,strlen函数会一直向后找" \0 "字符,直到找到为止,所以其可能会存在         越界的可能。

     下面我们通过代码来看其运行结果是咋样的:

    

       我们来分析一下上面的代码,我们先看前面两个strlen库函数,我们前面说到其会从传入的地         址往后找,直到找到第一个" \0 ",我们看到数组arr1和arr2的区别就是数组arr1就只存放了             abc三个字符,并没有\0,那么strlen函数并不会停止,而是会往后找,直到找到\0为止,那么         其返回的值我们也不知道是啥。

       而数组arr2是一个字符串,虽然其在代码上没有看到\0,但是其实际在末尾处是默认有一个\0         的,也就是arr2实际是这样的:"abc\0";所以strlen函数的返回值就是3。  

       下面我们来看后面两个sizieof,我们上面已经解释了两个数组之间的区别了,那么arr2数组就         是比arr1数组多了一个\0,所以对于arr1数组的结果是3,对于arr2数组的结果就是4.

       运行结果如下:

      

3、sizeof和strlen对比

      

二、数组和指针笔试解析  

1、一维数组

     我们先看一段代码:

     

       1、我们前面我们有说过这个情况,sizeof(数组名字),其中数组名代表整个数组,会计算整个               数组的大小,那么这个的计算结果就是16。 

       2、我们在前面的学习中知道数组名字可以是首元素地址,然后这里对首元素地址加上整数                   0,还是首元素地址,所以其是一个地址,其大小有应该是4或者8个字节。

       3、a在这边首先是首元素地址,我们讲过了只有第一种情况下才是整个数组的地址,然后这                里对a的首元素地址进行解引用,那么其就是数组的第一个元素,然后我们这个数组的元                素是整型类型,那么其大小为4字节。

       4、a是首元素地址,对其进行加1操作就是跳到下一个元素的地址,但是其本质还是地址,那              么其大小还是4或8字节。

       5、a[1]是数组的第二个元素,其是一个整型类型,那么其大小就为4个字节。

       6、这个是取整个数组的地址,那么其本质还是地址,那么其大小就还是 4或8字节

       7、对取数组地址,然后再解引用,那么可以这么理解。&和*号相互消除了,那么其可以化简              为sizeof(a)那么就是求整个数组的大小,那么其结果为16。

       8、其是取数组的地址然后跳过整个数组,那么其本质就是地址,那么其大小就是 4或者8。

       9、其是对数组的首元素进行取地址操作,那么其本质还是地址,所以其大小还是4或8字节。

      10、其首先对数组首元素进行取地址操作,然后其再进行加1操作,此时为后一个元素的地                    址,那么其本质还是个地址,那么其大小也还是4或8。

       下面我们看一下其运行结果(在64位的环境下):

        

2、字符、字符串数组和字符指针 

     通过上面的练习我们对于这部分的知识应该有了一定的理解了,下面我们来看看在字符和字符       串中是咋回事

     代码1

     

      1、sizeof(数组名),此数组名表示的是整个数组,那么其算的是整个数组的大小,那么其结果              应该是6字节。

      2、这里是对数组名+0操作,这里就不是代表整个数组了,其是代表数组首元素地址+0,那么              其本质是一个地址那么其结果是4或8字节。

      3、arr是首元素地址,然后对其解引用,那么就是整个元素了,其是一个字符类型,那么其大              小为1字节。

      4、arr[1]是数组的第二个元素,其也是一个字符类型,其大小也是1字节。

      5、&arr其到的是整个数组的地址,其本质是地址,那么其大小还是4或8字节。

      6、&arr+1就是跳过整个arr数组,但是其本质还是一个地址,那么其大小还是4或8字节。

      7、&arr[0]是取首元素地址,然后对其+1操作,就是跳到下一元素的地址,其本质还是地址,             那么其大小还是4或8字节。

           我们运行来看看:

      

   代码2 

       这段代码和代码1的区别就是将sizeof换成了strlen,前面我们也知道了他们两个的区别。

       1、strlen的计算方式是从传入的地址往后找字符串中的\0,没有遇到\0就会一直往后找,直到               碰到了\0,这里的arr数组是字符数组,并不是字符串,其结尾处是不会默认带\0的,那么               其就会一直往后面找,所以其计算的结果是啥我们也不知道。

       2、其原理和1是一样的,其返回值也是随机的。

       3、我们前面讲到strlen的时候,我们看到strlen函数的原型的从参数应该是一个字符指针,但               是现在的参数是对数组首元素地址解引用,得到的字符a,而不是一个地址,我们之前也                 说过字符在存储的时候是它的ascll码,那么这里strlen就是将字符a的ascll码当做一个地                   址,但是97这个编号的地址不一定是这个程序的,那么此时就造成了非法访问。

       4、同3一样此时给strlen传入的是字符a的ascll码,此时也还是可能会造成非法访问。

       5、这里的&arr得到的是一个类型为char(*)[6]的数组指针,但是strlen接收的是字符指针,所                 以这里的数组指针会被强制类型转换为字符指针,那么这里强制类型转换后,就是首元素               的地址,然后就从这个地址往后找,那么此时就和1、2的情况一样了,此时返回的为随机               值了。

       6、&arr+1还是一个数组指针,其作为strlen的参数后会强制类型转换为字符指针,然后从这                个位置开始往后找,直到碰到\0才结束,所以也是随机值。

       7、这里其实给strlen传入的是第二个元素的地址,此时从第二个元素开始找,直到找到\0,                所以其也还是个随机值。

       下面我们来看看其结果,这里要注意的是3和4可能会造成非法访问,所以我们不运行这两个:

        

代码3     

         后面就是对于字符串数组的练习:

         

         1、由于字符串中默认会包含一个\0,所以我们在计算整个字符串的大小的时候,要把这个                   \0也算上去,那么这个大小就是7。

         2、arr+0那么这是对首元素的地址进行+0操作,那么其本质上还是地址,那么这个大小就                   为4或8字节。

         3、这里对arr进行解引用,那么其是对首元素的地址进行解引用,那么这里求的就是数组                     首元素的大小,即为1。

         4、这里求的是数组第二个元素的大小,那么结果就为1。

         5 、这里对数组取地址,那么其本质就是是个地址,那么其大小就为4或8字节。

         6、这里对数组取地址后进行+1操作,跳过整个数组,但是其本质还是地址,那么其大小                     还是4或8。

         7、这里对第一个元素取地址后+1,那么此时就是拿到第二个元素的地址,那么其大小就                     还是4或8字节。

         下面我们看看其计算结果(在64位环境下):

            

代码4 

         

             1、在字符串数组中,由于其在末尾处会默认加上\0,所以函数strlen可以正常计算字符串                     数组的长度,结果为6。

             2、arr+0,此时的地址还是在首元素的地址,那么此时strlen的结果还是6。

             3、这里对数组解引用,此时给strlen传入的是字符a的ascll码,此时会造成非法访问。

             4、同理,这里给strlen传入的是字符b,此时也是造成非法访问。

             5、这里会把数组指针强制转换为字符指针,那么此时就会得到的是首元素的地址,那么                       在这里也可以正常计算出6 。

             6、这里对数组取地址再进行+1操作,此时就跳过了整个数组,那么此时不知道啥时候才                     可以遇到\0了那么此时的返回值就是一个随机值了。

             7、这里先对首元素取地址,再进行+1操作,得到的是第二个元素的地址,那么此时是从                     第二个元素开始往后找\0,那么此时的返回值为5 

             下面我们来看看代码的运行结果(64位环境下):

  

代码5
        
下面我们开始对字符指针进行练习

         

             1、我们前面刚刚开始学习指针的时候知道,把一个字符常量赋值给一个字符指针,实际                      上是将整这个字符常量的第一个字符的地址传给这个指针,那么变量p实际上也是一个                    地址,那么其大小就是4或 8字节。

             2、p+1得到的就是这个字符串的第二个字符的地址,那么其本质还是一个地址,那么其                       大小就是4或8字节。

             3、这里传入的是对p解引用,由于p实际上是字符串的首个字符的地址,那么其解引用就                      是第一个元素字符a那么其大小就是1。

             4、p[0]就表示拿到的是这个字符串的第一个字符,和字符数组类似,那么其大小就为1。

             5、p本身就是一个指针变量,再对其取地址就是二级指针,但是其本质上还是一个地址,                    那么其大小就还是 4或8字节。

             6、和上面的类似,对一个指针变量取地址为二级指针,再进行+1操作,此时还是个地                        址,那么大小还是4或8。

             7、这里就很简单了,这里首先是得到了字符串的第一个字符,然后对其取地址,然后进                      行+1操作,此时就到了第二个元素的地址了。

             下面我们来看看其运行结果

             

代码6 

          1、这里的p是字符串的第一个字符的地址,那么strlen函数就会从这个位置开始往后找,然                  后字符串在末尾处是会自带\0的那么其到末尾处就结束计算,返回字符串的长度,为6。

           2、p+1那么此时是在字符串的第二个字符的地址,那么此时是从第二个字符的位置出发往                  后找,那么此时的长度就是5。

           3、对p进行解引用,p是字符串的首字符的地址,那么此时对其解引用就是字符a了,那么                    此时给strlen函数传的是其的acsll码97,那么此时就可能造成非法访问了。

           4、和上面3的情况差不多,不一样的是这里是直接取的字符串的第一个字符,同样造成非                     法访问。

           5、这里是对指针p进行取地址,此时给strlen函数传入的是一个二级指针,这个二级指针指                   向的是一级指针p,但是这个p的地址我们也不知道在哪里,那么我们啥时候碰到\0也不                   确定,那么strlen在哪里停止也是不知道的,那么这次的计算值也是随机值。

            6、这里是对二级指针跳过一个一级指针p后面是啥我们也不知道,那么其啥时候碰到\0也                      是不情况的,那么此时也是返回一个随机值。

            7、这里的&p[0]相当于拿到了第一个字符的地址,那么再+1后就是第二个字符的地址,那                    么其计算的结果就是5了。

            下面我们来看看其运行结果:

             

3、二维数组             

     下面我们来进行对二维数组的练习

      

            

    1、  二维数组也是如此,sizeof(数组名)这里就是代表整个数组,计算的是整个数组的大小,那              么其大小就应该为3*4*4,结果为48字节。

    2、这里求的是整个数组的首个元素,那么其大小就为 4字节。

    3、这里的a[0]就相当于这个二维数组的第一行,那么这里就是求第一行的大小,那么其结果为           4*4=16字节。

    4、a[0]相当于第一行的数组名,那么其+1后就相当于第二个元素的地址了,那么其大小就为4             或8字节。

   5、这里先取得第一行第二个元素的地址,然后对其解引用,那么得到的就是第二个 元素了,那          么其大小就为4字节。

   6、这里的数字名字没有和sizeof单独放在一起,而是对数组名+1操作,那么此时得到的数组第            二行的地址,那么其大小为4或8字节

   7、这里就是先取到第二行的地址,然后对其解引用,那么就是求整个第二行的大小,那么结果           为16字节。

    8、这里先取得第一行的地址,然后对其进行+1操作,此时就跳过第一行到第二行,得到的是第            二行的地址,那么其本质就是地址,那么其大小就为4或8字节。

    9、这里先是取得第一行的地址,然后进行+1操作得到第二行的地址,然后对其解引用,那么其            就是求第二行的大小,那么其结果就是16。

    10、这里的a相当于二维数组的第一行,那么再解引用,那么就是求的第一行的大小,那么其大             小就是16。

     11、这里的话a[3]越界访问了,因为我们的二维数组是三行的,没有第四行,但是程序会帮我                们越界去访问,会计算出和第三行相同结构的数组,那么其计算出来的大小就和第三行一              样,那么其结果就为16。

      下面我们来看看其运行结果(64位环境下):

       

总结:

        1、sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

        2、&数组名,这里的数组名表示整个数组,取得的是整个数组的地址

        3、除此之外的数组名都表示的地址

三、指针运算的笔试题 

      代码1

      

        我们看整个代码主要是prt的部分比较难,那么我们先看这个指针到底是啥,首先其是先对a            取地址,然后进行+1操作,然后将其强制类型转换位(int*)类型,这个强制类型转换的目的          是啥呢?一开始其没转换类型的话,对其进行 +1操作的话是跳过整个数组的大小,现在对其          强制类型转换后,其+1操作跳过的空间就是一个int类型的空间了。

        然后我们看看*(a+1)a是首元素地址,那么对其+1就是第二个元素的地址了,再对其解引用那          么就是第二个元素了,那么第一个输出的就是第二个元素2。

        然后就是*(prt-1),此时的prt是指向的数组的后一个地址,也就是数组最后一个元素的下一个地          址,然后此时的prt的指针类型为(int*)型,那么其-1的话是往前移动一个int的位置,那么此            时其指向的地址就是数组的最后一个元素了。那么其输出的结果就是5。

        最后我们看看其运行结果:

       

        代码2    

       

      我们先看第一个p+1,首先可以看到p是一个结构体指针,而且其给赋为100000,然后+1后就        会跳过整个结构体,那么其结果就为100020。

      然后我们看第二个(unsigned  long+1)p+1,这里先对p进行了强制类型转换,其被转换为了无        符号长整型,那么此时p就是一个数字了,+1就是对其进行数字的加减法,此时就是100001            了。

      我们来看最后一个,其将p强制转换为(unsigned int *)类型的,这里其实就是将其转换为整          型指针了,那么对其+1就是跳过4个字节,那么结果就是100004。

      下面我们来看看其运行结果:

      

         代码3

           这里我们先看看这个数组中存放的是啥,一开始我们很多人可能会以为这是个点坐标,或               者是一行的两个元素,其实都不是,一行的元素我们也是用一个大括号{}放在一起的,其实             小括号里面的是一个逗号表达式,第一个的结果是1,第二个的结果是3,第三个的结果是               5。

           那么其二维数组是第一行的元素是1,3。第二行的是5,后面的元素是空的。

           然后再将a[0]也就是数组的第一行的数组名赋个指针变量p,那么此时的指针变量p就相当于             二维数组第一行的数组名 ,那么p[0]就相当于第一行的第一个元素1。

          下面我们看看其运行结果:

         

             代码4

             

               这里的p是一个元素个数为4个的整型数组指针,然后a是a这个数组的首元素地址,这里                 将a赋给p会发生强制类型转换。相当于p接收了a存放的地址,不过它的类型强制转换                     了,使得其一次只能跳过四个元素,,而我们的a可以一次跳过五个元素,下面我们通过                 画图来理解:

             

                 可以看到p[4][2]要比a[4][2]要前四个位置所以其减出来是-4,然后第一个我们是用的p占                   位符,所以其输出的是补码。,然后后面的那个就是-4了。

                 下面为其运行结果:

     

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Chromium 132 编译指南 Windows 篇 - 生成构建文件 (六)

1. 引言 在上一篇文章中,我们已经成功获取了 Chromium 的源代码并同步了相关的第三方依赖。本文将继续深入,指导您如何使用 GN 工具生成构建文件,为接下来的编译工作奠定基础。 2. 切换 Chromium 版本至 132 在开始正式构建之前&#xff0…

(12)springMVC文件的上传

SpringMVC文件上传 首先是快速搭建一个springMVC项目 新建项目mvn依赖导入添加webMoudle添加Tomcat运行环境.在配置tomcat时ApplicationContext置为"/"配置Artfact的lib配置WEB-INF配置文件(记得添加乱码过滤)配置springmvc-servlet文件&…

3D目标检测数据集——Waymo数据集

Waymo数据集簡介 发布首页:https://waymo.com/open/ 论文:https://openaccess.thecvf.com/content_CVPR_2020/papers/Sun_Scalability_in_Perception_for_Autonomous_Driving_Waymo_Open_Dataset_CVPR_2020_paper.pdf github:https://github.…

Mysql--运维篇--空间管理(表空间,索引空间,临时表空间,二进制日志,数据归档等)

MySQL的空间管理是指对数据库存储资源的管理和优化。确保数据库能够高效地使用磁盘空间、内存和其他系统资源。良好的空间管理不仅有助于提高数据库的性能,还能减少存储成本并防止因磁盘空间不足导致的服务中断。MySQL的空间管理涉及多个方面,包括表空间…

STM32之LWIP网络通讯设计-下(十五)

STM32F407 系列文章 - ETH-LWIP(十五) 目录 前言 一、软件设计 二、CubeMX实现 1.配置前准备 2.CubeMX配置 1.ETH模块配置 2.时钟模块配置 3.中断模块配置 4.RCC及SYS配置 5.LWIP模块配置 3.生成代码 1.main文件 2.用户层源文件 3.用户层头…

Gateway 网关

1.Spring Cloud Gateway Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态…

数据结构:栈(Stack)和队列(Queue)—面试题(二)

1. 用队列实现栈。 习题链接https://leetcode.cn/problems/implement-stack-using-queues/description/描述: 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty&a…

在 .NET 9 中使用 Scalar 替代 Swagger

前言 在.NET 9发布以后ASP.NET Core官方团队发布公告已经将Swashbuckle.AspNetCore(一个为ASP.NET Core API提供Swagger工具的项目)从ASP.NET Core Web API模板中移除,这意味着以后我们创建Web API项目的时候不会再自动生成Swagger API文档了…

双模充电桩发展前景:解锁新能源汽车未来的金钥匙,市场潜力无限

随着全球能源转型的浪潮席卷而来,新能源汽车行业正以前所未有的速度蓬勃发展,而作为其坚实后盾的充电基础设施,特别是双模充电桩,正逐渐成为推动这一变革的关键力量。本文将从多维度深入剖析双模充电桩的市场现状、显著优势、驱动…

Notepad++上NppFTP插件的安装和使用教程

一、NppFTP插件下载 图示是已经安装好了插件。 在搜索框里面搜NppFTP,一般情况下,自带的下载地址容易下载失败。这里准备了一个下载连接:Release v0.29.10 ashkulz/NppFTP GitHub 这里我下载的是x86版本 下载好后在nodepad的插件里面选择打…

Mysql--运维篇--备份和恢复(逻辑备份,mysqldump,物理备份,热备份,温备份,冷备份,二进制文件备份和恢复等)

MySQL 提供了多种备份方式,每种方式适用于不同的场景和需求。根据备份的粒度、速度、恢复时间和对数据库的影响,可以选择合适的备份策略。主要备份方式有三大类:逻辑备份(mysqldump),物理备份和二进制文件备…

在 Safari 浏览器中,快速将页面恢复到 100% 缩放(也就是默认尺寸)Command (⌘) + 0 (零)

在 Safari 浏览器中,没有一个专门的快捷键可以将页面恢复到默认的缩放比例。 但是,你可以使用以下两种方法快速将页面恢复到 100% 缩放(也就是默认尺寸): 方法一:使用快捷键 (最常用) Command (⌘) 0 (零…

LLMs之RAG:《EdgeRAG: Online-Indexed RAG for Edge Devices》翻译与解读

LLMs之RAG:《EdgeRAG: Online-Indexed RAG for Edge Devices》翻译与解读 导读:这篇论文针对在资源受限的边缘设备上部署检索增强生成 (RAG) 系统的挑战,提出了一种名为 EdgeRAG 的高效方法。EdgeRAG 通过巧妙地结合预计算、在线生成和缓存策…

探索网络安全:浅析文件上传漏洞

前言 在数字化时代,网络安全已成为我们每个人都需要关注的重要议题。无论是个人隐私保护,还是企业数据安全,网络威胁无处不在。了解网络安全的基本知识和防护措施,对我们每个人来说都至关重要。 网络安全 网络安全并非只是对网…

Therabody 与Garmin联手,共同推进运动恢复与健康科技新突破

本次合作以数据整合、人工智能驱动的数字教练与科学研究为重点,旨在更好地了解科学恢复对运动表现的影响 (2025年1月13日,中国上海)全球健康领导者Therabody宣布与智能手表品牌Garmin佳明建立战略合作关系,共同致力于…

Cloudflare中转Gemini API,国内免费爽用,Gemini编程,音视频,多模态能力测试

视频版: Cloudflare中转顶级大模型API,国内免费爽用,Gemini编程,音视频,多模态能力测试 谷歌Gemini是所有一线顶级大模型当中唯一一个API可以免费白嫖的。本期视频,我们借助互联网大善人Cloudflare来中转一…

腾讯云AI代码助手编程挑战赛-算法小助手

作品简介 一个可以帮助学习计算机各种算法的AI小助手,提升工作效率。 技术架构 使用Html语言完成图形化页面的样式,使用JavaScript语言来操作对应的逻辑代码。 实现过程 1、创建一个界面 2、获取数据 3、添加按钮与功能 4、程序优化调试 开发环境…

网络安全实验之钓鱼网站的制作及技巧

在红队攻击中,除漏洞以外最简洁高效的攻击方式无疑是钓鱼攻击,通过不同的钓鱼方式可达到不同的攻击效果,本次我会分享最常见的钓鱼手段之一的网站钓鱼技术,同时对可实现的攻击操作进行演示。 更多网站钓鱼实验科普,可…

用户注册模块用户校验(头条项目-05)

1 用户注册后端逻辑 1.1 接收参数 username request.POST.get(username) password request.POST.get(password) phone request.POST.get(phone) 1.2 校验参数 前端校验过的后端也要校验,后端的校验和前端的校验是⼀致的 # 判断参数是否⻬全 # 判断⽤户名是否…

linux-28 文本管理(一)文本查看,cat,tac,more,less,head,tail

之前提到过linux的几个重要哲学思想,使用纯文本文件保存软件的配置信息是其中之一,所以大多数情况下,我们对整个系统的操作,都是通过编辑它的配置文件来完成,那也就意味着,处理文本文件是我们作为系统管理员…