C语言(指针)3

                       Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~     

                        💥个人主页:小羊在奋斗

                        💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。 

                                5、指针运算

                                                5.1指针 +- 整数

                                                5.2指针 - 指针

                                                5.3指针的关系运算

                                6、野指针

                                                6.1野指针成因

                                                6.2如何避免野指针

                                7、assert 断言

                                8、指针的使用

                                                8.1strlen函数的模拟实现

                                                8.2传值调用和传址调用

5、指针运算

        5.1指针 +- 整数

        在 C语言(指针)1中,我们已经了解过了指针 +- 整数的情况,知道了指针 +- 整数的结果取决于它所指向的对象的类型,这里再来看一种指针 +- 整数的用法。

        我们知道数组内的元素在内存中的存储是连续的,所以我们就可以用指针 +- 整数的方法来遍历数组:

        上面几种写法实际上表达的是一个意思。 

         当然也能逆序打印:

        这里只演示了一种方法,其他方法都是一样的。

        我们知道,上述内容中的原理为:arr数组中的元素为int型,指针变量p的类型为int *型,所以指针变量p+1跳过4个字节,刚好访问到数组中的下一个元素。那如果我们将数组首元素的地址存到char *类型的指针变量p中,因为char类型大小为1个字节,所以我们给指针变量p一次+4,是否也能实现遍历数组呢? 

        可以看到确实实现了遍历数组的目的,那上面的方法就是正确的吗?答案是否定的。在上面的代码中能成功实现遍历数组是因为特殊情况

        当指针变量p是int *类型的时候, *p访问的是下面红色方框内的四个字节的内容,p+1是由第一个红色箭头跳到了第二个红色箭头的位置;

         当指针变量p是char *类型的时候,作为int型的数组,其内部的一个元素存储在下面的一个红色方框中,但是*p访问的只是下面蓝色方框内的一个字节的内容,不过p+4确实是从第一个蓝色箭头跳到了第二个蓝色箭头的位置。

        如上所说,当数组中的元素是更大的值的时候,它的值就会 “分布” 在一个红色方框内的几个小格子中,这时候作为char *类型的指针变量p在*p解引用操作的时候访问的还是一个蓝色方框内的内容,其它小格子中的值访问不到了。说到这里相信你就明白了上面所说的答案是否定的的原因

        5.2指针 - 指针

        我们这里直接说结论:指针 - 指针的绝对值是指针和指针之间元素的个数

        但前提是这两个指针指向的是同一块空间

        之所以要说指针 - 指针的绝对值,是因为数组内元素的地址随着下标的增大而增大,如果前面元素的地址 - 后面元素的地址,得到的值就是负数:

        那这有什么用呢? 

        我们可以用上面学到的东西来模拟实现strlen函数,关于strlen函数在之前的文章 —> C语言基础 中已经介绍过,strlen函数的作用是计算字符串的长度,统计的是字符串中 “\0” 之前的字符个数。

        先来复习一下strlen函数的用法:

        接着我们用指针来实现一下,做个铺垫:

        有了上面的铺垫后,我们就来用指针 - 指针的方式实现:

        既然有指针 - 指针,那有么有指针 + 指针的运算呢?没有,指针 + 指针是没有什么意义的。

        5.3指针的关系运算

         指针之间也是可以比较大小的,下面我们就用这个性质来实现遍历数组的效果:

6、野指针

        野指针就是指针指向的位置是不可知的、随机的、不正确的、没有明确限制的。

        6.1野指针成因

         (1)指针未初始化;

        如果将p中存放的值当作地址,解引用操作就会非法访问。 

        (2)指针越界访问;

          我们只申请了数组内10个元素大小的地址,当指针变量指向的地址超过了数组内下标最大元素的地址,此时指针变量就成了野指针。

        (3)指针指向的空间被释放。

         上面的代码是一个非常典型的例子,大家觉得上面的代码有什么问题?

        我们在自定义函数里定义了一个局部变量a,然后把a的地址作为函数返回值,在main函数中用指针变量p接收传过来的地址,在通过解引用打印变量a的值。表面看并没有什么问题,但是问题隐藏在我们看不见的地方。

        我们确实把a的地址当作函数返回值由指针变量p成功地接收了,但是不要忘了a是一个局部变量,之前的文章 static 和 extern 中说过:局部变量进入作用域变量创建,生命周期开始;出作用域变量销毁,生命周期结束。所以,当我们的自定义函数结束后,局部变量a就销毁了,向内存申请的空间就会释放还给内存,此时即使p中存了a的地址也没有用了,拿着这个地址找过去也找不到a,就像过期了一样。

        打个比方:我们今晚去住酒店,住下之后把酒店的位置和房间号告诉了我们的好朋友,好朋友记下后第二天就来了这个酒店找我们,但是我们并不知道他要来找我们,就把房给退了回家了,这时候好朋友来酒店找我们还找得到吗?他连酒店房门都进不去,如果他是一根筋非要进房间找我们并说我们明明告诉他我们就住在这个房间里,这时候酒店保安肯定会把他叉出去,并且报警。

        野指针在C语言中是非常可怕的,可能会导致内存泄漏、程序崩溃、安全漏洞、数据损坏等,我们一定要避免野指针的出现。 

        6.2如何避免野指针

        避免野指针的方法就是解决掉野指针的成因,对症下药。

        (1)指针初始化;

        如果明确知道指针需要指向哪里就直接赋地址值,如果还不明确指针需要指向哪里就先赋NULL。NULL是C语言中定义的一个标识符常量,值是0,0也是地址但这个地址(空指针)是无法使用的,读写地址会报错,但不会构成野指针。

        空指针是无法访问的,这么做是为了避免出现野指针,等我们需要给指针变量赋地址的时候再给它赋相应的地址。我们要养成给指针变量赋NULL的习惯,这叫防患于未然。 

         (2)小心指针越界;

        一个程序向内存申请了多大的空间,通过指针就访问多大的空间,千万不能超出范围访问,否则就是越界访问,是非法的。

        (3)指针变量不再使用时,及时置NULL,指针使用之前检查有效性; 

        (4)避免返回局部变量的地址。 

7、assert 断言 

         assert.h 头文件定义了宏 assert(),用于在运行时确保程序符合指定的条件,如果不符合,就报错终止运行。这个宏被称为 “断言”。

        assert()宏接受一个表达式作为参数,如果该表达式为真(非0),assert()不会产生任何作用,程序继续运行;如果该表达式为假(0),assert()就会报错终止程序,并且给出错误信息。

        使用 assert()有几个好处:它不仅能自动标识文件和出问题的行号,还有一种无需更改代码就能开启或关闭 assert()的机制。如果已经确定程序没有问题,不需要再做断言,就在#include <assert.h> 语句的前面定义一个宏 NDEBUG。如果还不知道宏是什么也没有关系,先理解本节的内容,后面会有相应的文章。 

        然后,重新编译程序,编译器就会禁用文件中所有的 assert()语句。 

        可以看到,在 #include <assert.h> 前面定义了宏NDEBUG后,再次运行程序就不会报错。 

         如果程序又出现了问题,可以移除 #define NDEBUG 这条指令(或者把它注释掉),再次编译,这样就重新启用了 assert()这条语句。

        assert()的缺点是,引入了额外的检查,增加了程序的运行时间,当然肯定是利大于弊的。

        一般在 Debug 中使用,在 Release 版本中选择禁用就行,不过在VS这样的集成开发环境的 Release 版本中,直接就优化掉了。这样的好处是不仅在 Debug 版本中有利于程序员检查问题,而且在 Release 版本中也不影响用户使用程序时的效率。

8、指针的使用

        8.1strlen函数的模拟实现

        前面我们已经实现过模拟strlen()函数,这里再来做一个优化版:

        来解读一下上面的代码:

        首先我们要搞清楚我们的目的,只是把一个字符串传过去求它的长度,因此并不想让这个字符串发生改变,所以我们用 const “训练” 了形参,让它变得抗造不会被改变(健壮性 / 鲁棒性),可以防止自己或别人不小心改变字符串; 然后我们还加了 assert 断言,确保指针不是空指针,提高了代码的可靠性。

        通过上面的代码我们不难发现,随着学习地不断深入,我们写出的代码质量会越来越高。 

        8.2传值调用和传址调用 

        对于传值调用相信大家都非常熟悉,没什么可说的。关于传址调用,在我之前的文章中已经介绍过,还请跳转阅读另一篇文章 —>  指针的简单应用。这篇文章是很早写过的,写的可能不是那么好,还请见谅。

        传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量。所以如果只是需要主调函数中的变量值来实现计算,就用传值调用;如果需要在函数内部修改主调函数中变量的值,就用传址调用。 

        如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。

                                          点击跳转下一节 —> C语言(指针)4

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

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

相关文章

YOLOv9改进策略 | 添加注意力篇 | 利用YOLO-Face提出的SEAM注意力机制优化物体遮挡检测(附代码 + 修改教程)

一、本文介绍 本文给大家带来的改进机制是由YOLO-Face提出能够改善物体遮挡检测的注意力机制SEAM&#xff0c;SEAM&#xff08;Spatially Enhanced Attention Module&#xff09;注意力网络模块旨在补偿被遮挡面部的响应损失&#xff0c;通过增强未遮挡面部的响应来实现这一目…

链表第4/9题--翻转链表--双指针法

LeetCode206&#xff1a;给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例…

鸿蒙OpenHarmony开发板解析:【特性配置规则】

特性 特性配置规则 下面介绍feature的声明、定义以及使用方法。 feature的声明 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 在部件的bundle.json文件中通过feature_list来声明部件的feature列…

生信技能45 - 基于docker容器运行生信软件

1. 获取docker镜像 以运行xhmm CNV分析软件为例。 # 搜索仓库镜像 sudo docker search xhmm# 拉取镜像 sudo docker pull ksarathbabu/xhmm_v1.0# 启动镜像,非后台 sudo docker run -it ksarathbabu/xhmm_v1.0 /bin/bash # -i: 交互式操作。 # -t: 终端。 # ksarathbabu/xhmm…

爆爽,英语小白怒刷 50 课!像玩游戏一样学习英语~

重点!!!(先看这) 清楚自己学英语的目的, 先搞清楚目标&#xff0c;再行动自身现在最需要的东西&#xff1a;词汇量&#xff1f;口语&#xff1f;还是阅读能力&#xff1f;找对应的书籍,学习资料往兴趣靠拢&#xff1a;网上有大量的推荐美剧学习、小说学习&#xff0c;不要被他…

机器学习算法应用——K近邻分类器(KNN)

K近邻分类器&#xff08;KNN&#xff09;&#xff08;4-2&#xff09; K近邻分类器&#xff08;K-Nearest Neighbor&#xff0c;简称KNN&#xff09;是一种基本的机器学习分类算法。它的工作原理是&#xff1a;在特征空间中&#xff0c;如果一个样本在特征空间中的K个最相邻的样…

【一刷《剑指Offer》】面试题 17:合并两个排序的链表

力扣对应题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 核心考点&#xff1a;链表合并。 一、《剑指Offer》内容 二、分析题目 这道题的解题思路有很多&#xff1a; 可以一个一个节点的归并。可以采用递归完成。 三、代码 1、易于理解的…

Linux-基础命令第三天

1、命令&#xff1a;wc 作用&#xff1a;统计行数、单词数、字符数 格式&#xff1a;wc 选项 文件名 例&#xff1a; 统计文件中的行数、单词数、字符数 说明&#xff1a;59代表行数&#xff0c;111代表单词数&#xff0c;2713代表字符数&#xff0c;a.txt代表文件名 选项…

c语言查找字符串中指定字符串的个数

目录 一、测试思路二、方式1三、方式2 一、测试思路 使用C语言来查找一个字符串中指定数量的子字符串&#xff0c;使用 strncmp 函数或者 memcmp 函数&#xff0c;遍历主字符串并计数子字符串出现的次数。或者使用 strstr 函数&#xff0c; strstr 函数是 C 语言标准库 <str…

Java 集合-List

集合主要分为两组(单列集合, 双列集合) Connection 接口有两个重要的子接口LIst 和 Set, 它们的实现子类都是单列集合, Map 接口的实现子类是双列集合, 存放的是 K-V Connection 接口 Collection 接口和常用方法 下面以 ArrayList 演示一下 add: 添加单个元素remove: 删除指…

基于GIS地理技术+智慧巡检解决方案(Word原件)

传统的巡检采取人工记录的方式&#xff0c;该工作模式在生产中存在很大弊端&#xff0c;可能造成巡检不到位、操作失误、观察不仔细、历史问题难以追溯等现象&#xff0c;使得巡检数据不准确&#xff0c;设备故障隐患得不到及时发现和处理。因此建立一套完善的巡检管理系统是企…

【C语言】——联合体与枚举

【C语言】——联合体与枚举 一、联合体1.1、联合体类型的声明1.2、联合体的特点1.3、相同成员的结构体和联合体对比1.4、联合体的大小计算1.5、联合体的应用举例 二、枚举2.1、枚举类型的声明2.2、枚举类型的优点 一、联合体 1.1、联合体类型的声明 联合体也叫做共用体   与…

TLF35584 Windows Watchdog

1、相关寄存器 1&#xff09;WWDCFG0 - Protected Window watchdog configuration request 0 *R2 offset Address&#xff1a;09H&#xff1b;Reset Value&#xff1a;06H&#xff1b; 窗口看门狗关窗口的周期默认值&#xff1a;350wd cycles 350ms。 2&#xff09;WWDCFG1…

国产银河麒麟V10SP1系统下搭建TiDB数据库操作步骤图文

开发目的&#xff1a;在国产银河麒麟系统中搭建TiDB数据库运行环境。 开发工具&#xff1a;银河麒麟系统V10SP1TiDBMySql数据库8.0。 具体步骤&#xff1a; 1、在VmWare虚拟机中安装好国产银河麒麟V10Sp1操作系统。 2、打开终端命令&#xff0c;安装TiDB相关软件&#xff1…

调试记录 CPU PCIE 找不到设备,AC 耦合电容的问题

1. 问题 现象&#xff1a; 1. 国产CPU的主板&#xff0c;主板内的PCIE 设备找的到&#xff0c;但是另一块板子上连接的PCIE 设备找不到。 2. 排查问题在哪里的计划 1. 检查原理图先排除信号定义的问题&#xff0c; TXRX是否反接。 2. 示波器检查PCIE 的时钟频率是否正确。 3. …

ESLint: Unexpected ‘debugger‘ statement.(no-debugger)(debugger报红)

ESLint: Unexpected debugger statement.(no-debugger) 解决办法&#xff1a; 找到.eslintrc.js文件中rules的no-debugger更改为0即可

队列的实现(使用链表)

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 目录 1、队列的概念2、队列的链表实现方法2.1 前言2.2 正文2.2.1 队列的初始化2.2.2 队列的销毁…

苹果公司因iPad广告争议而道歉,承认“未达标”|TodayAI

周二&#xff0c;苹果公司发布了一则新的iPad Pro广告&#xff0c;引起了广泛争议&#xff0c;该公司随后发表道歉声明&#xff0c;承认这则广告“未达标”。这则名为“压碎&#xff01;”的广告意图展示全新的M4芯片iPad Pro的创意潜力&#xff0c;但却因其表现方式而备受批评…

服务器直连电脑(盒子直连电脑)电脑需要设置为固定ip才能访问盒子

文章目录 现象盒子设置为固定ip&#xff0c;pc设置成固定ip&#xff08;以太网网卡&#xff0c;realtak那个&#xff0c;不是tap-windows那个&#xff0c;tap-windows不用管&#xff09;&#xff0c;在pc上用ip搜索工具搜索&#xff0c;可以搜到盒子ip。盒子设置为固定ip&#…

phpstudy靶场访问显示404 Not Found

涉及靶场 upload-labd sqli-labs pikachu dvwa 以及所有部署在phpstudy中的靶场 一、检查phpstduy设置 localhost——管理——修改 1、根目录&#xff08;默认设置&#xff0c;不要改&#xff09; localhost这个域名必须保留&#xff0c;并且把根目录设置为phpstudy的WWW文…
最新文章