植物百科网
当前位置: 首页 农业百科

学c语言指针注意什么(苦C语言指针久矣)

时间:2023-07-20 作者: 小编 阅读量: 2 栏目名: 农业百科

有的则是程序员警惕性不足,缺少对异常情况的判断与保护。这使得指针操作数据具备极高的效率,但缺少语言层面的保护,由程序员负全部责任。通过指针变量访问内存中包含的值,称为间接访问或者解引用指针。要避免出错,安全是第一位的,我们先从一个特殊的指针变量说起。这就意味着,一个指针变量被赋予NULL值时,那么就不能对它进行间接访问,否则会产生不可预料的后果。这期间服务不可避免地会暂停。

引言

对于 C 程序员来说,最头痛的莫过于操作指针出现问题,导致程序数据错乱、甚至崩溃退出。其实还有更严重的情况,就是留下程序漏洞,被恶意攻击,造成更大的损失。

造成这些问题的原因,有的是程序员对于指针的技术原理和运行时机制掌握不到位,以为可以这么用,结果却埋下隐患。有的则是程序员警惕性不足,缺少对异常情况的判断与保护。

可以说,天下 C 程序员苦指针久矣。逃避肯定不是办法,那就勇敢地直面它吧。幸好,C 程序员们不用在黑暗中独自摸索,把《C 和指针》这本书的内容融汇贯通,就可无敌了。

掌握好指针,其实只要循序渐进走好三步就可以,就是首先能够 Hold 住指针的运算,保证怎么算都不会出错;然后是构建抽象数据类型(ADT),这是实现复杂处理逻辑的基础;最后是存乎一心,自由妙用。

不过,我觉得还是有必要先从修炼 C 语言基本功说起。

想要飞得高,先要站得稳

C 语言本身历史悠久,且更靠近系统底层,可以看作是高级语言与低级语言之间的“中级语言”。这意味着它拥有更多的自由,但使用不当也容易造成难以预料的破坏。

指针作为 C 语言中的一种特性,拥有直接访问程序内存的能力。这使得指针操作数据具备极高的效率,但缺少语言层面的保护,由程序员负全部责任。

因此,要搞明白指针,就必须先要对 C 语言有通盘掌握,想要展翅高飞,一定要立足先稳。

《C 和指针》的内容就涵盖了 C 语言的必备知识。包括语法规则、数据类型说明、操作符表达式等。拿着这本书,作为 C 语言的入门教程也完全没问题。

打牢了基础,再进入到书中对指针的讲解中,就水到渠成了。那么,指针到底是什么?

先明确关于内存的两个特点:

  1. 内存中的每个位置,由一个独一无二的地址标识;
  2. 内存中的每个位置,都包含一个值。

指针型变量,它存储的是内存地址标识值。通过指针变量访问内存中包含的值,称为间接访问或者解引用指针。

用代码来说话:

int a = 100;int *b = &a; // 定义整型指针 b 指向整型变量 a*b = 10; // b 以间接访问方式,修改变量 a 的值

第一步:Hold 住指针的运算

指针的运算可以分为两种,一类是算术运算,另一类是关系运算。其实它们的规则还是比较简单的,但却是实际编程中出错最多的地方。

要避免出错,安全是第一位的,我们先从一个特殊的指针变量说起。

C 语言标准里定义了一个关键词:NULL。它的含义是空指针,即不指向任何内存地址。这就意味着,一个指针变量被赋予NULL值时,那么就不能对它进行间接访问,否则会产生不可预料的后果。

所以一个指针变量,它在初始化时如果没有明确地赋值,或者它在使用完毕之后,都必须赋予NULL值。判断指针是否为NULL,这是保证指针运算安全性的前提。

有了安全保障,我们先来看算术运算,就是指针变量加减一个整数值:

int *a = NULL;int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};a = array; // 整型指针变量 a 指向数组第一个元素 array[0] 的地址a; // a 向后移动,指向 array[1] 的地址a--; // a 向前移动,指向 array[0] 的地址

指针类型变量自增的结果,是在一段连续内存区域进行偏移,而其跨过的长度,就是sizeof(指针变量类型) * 跳变量字节。以上例来说,a等同于偏移sizeof(int) * 1个字节,正好是整型数组的下一个元素位置。

对于初学者来说,会容易将a理解成指针仅偏移一个字节,这是最大的坑,所以此处千万要理解透。

指针的关系运算,就是可以在指针变量之间以关系运算符>, <, =, !=进行比较。大小的比较,可以判定两个指针在连续内存区域上的位置关系。但如果是两段不相干的内存区,则关系运算没有意义。

关系运算可以用来实现连续内存区的循环处理,还有更多用法以及注意事项,可以在书中慢慢细品。

第二步:构建抽象数据类型

指针的运算能够拿下,那就要考虑更高层次的使用了。对于复杂问题的求解,仅是 C 语言内置类型和容器,显然是不够的。那么,基于结构体与指针,构建抽象数据类型,是 C 程序员的必备功底。

《C 和指针》一书中面向初学者还是非常友好的,以链表的实现作为示例,进行充分讲解。有了这个基础,再实现更复杂的哈希表、字典、队列、树、图等结构时,就有章可循了。

让我们先来学习一下在构建单链表的过程中,指针应当如何使用。

首先是定义链表节点:

typedef struct NODE {struct NODE *link; // 结构成员的自引用指针,用来存储下一个节点的地址int value;} Node;

在结构体中使用自引用指针成员,是关键之处,它是 C 语言中实现动态构建数据结构的基本。

那么在表头插入节点的过程,如下伪代码所示:

Node *head = HEAD(); // 获得链表表头节点Node *new = NEW(); // 生成待插入新节点Node *temp = NULL; // 临时节点指针temp = head->link; // 将表头节点的下一节点地址临时保存head->link = new; // 将新节点置为表头节点的下一节点new->link = temp; // 将暂存节点置为新节点的下一节点temp = NULL;

看代码觉着有些抽象是吗?书中实现了完整的有序单链表插入功能,作者精心绘制了数据插入分解图,可以说是一目了然。话说有图有真相,如此学习起来怎能不事半功倍呢。

摘自《C 和指针》有序单链表插入分解图

如果链表的实现已经掌握了,那就可以放心学习书中第17章,关于经典抽象数据类型的内容。它包括了堆栈、队列,以及二叉搜索树的实现。

第三步:自由妙用

在掌握了指针的运算与如何构建抽象数据类型之后,C 程序员们就可以向更高境界出发,即存乎一心,自由妙用。

这时候会发现,所谓程序,不过就是指令、数据与存储地址。那么,凡是存放着指令与数据的内存区域,都可以通过指针来运算,设计出高妙的用法。

以网络通信开发的一个场景为例,其中对于应用协议的多版本兼容是硬性要求。那么一种简单的办法就是每个协议版本对对应一个函数。例如Protocol_v1(); protocol_v2(); ……。

但这样做在程序升级的时候,就会给运维工作带来麻烦。因为必须先停止老程序运行,然后再启动新程序。这期间服务不可避免地会暂停。

基于书中介绍的函数指针,就可以平滑升级的方式解决这个问题。步骤是先将协议解析功能置于动态库中,然后用回调的方式,从动态库中获得对应版本的处理方法。

使用函数指针的伪代码示例:

int protocol_v1(char *data); // 老版本协议解析方法int protocol_v2(char *data); // 新版本协议解析方法void protocol_work(int version, char *data) {int (*pProtocol)(char *) = NULL; // 定义函数指针变量,它必须与待调用函数的形参列表一致switch(version) { // 根据不同协议版本,将对应的处理方法赋予 pProtocol 变量case V1:pProtocol = protocol_v1;break;case V2:pProtocol = protocol_v2;break;}pProtocol(data); // 实现了对不同版本协议的兼容处理}

协议版本有更新时,只需要将动态库进行替换即可,主程序只要实现动态库注入与热更新功能,就能在不影响业务运行的情况下实现平滑升级。

当然,以上仅是以一例说明,指针与指令结合,可以实现怎样的妙用。其实 C 程序员们可以从书中获得更多的启示,再与实际业务相结合,创造出简明高效的用法。

结语

《C 和指针》的作者 Kenneth Reek 是罗彻斯特理工大学的计算机科学教授,同时也是多家公司的技术顾问。在学术研究与 C 语言编程实践上,都兼具了相当丰富的经验。

Kenneth Reek

所以在这本书中,不仅能看到翔实的 C 语言理论知识,还有解决实际问题的干货。我从书中总结出三条使用指针的安全注意事项,帮助大家避免掉坑。

  1. 在动态分配内存之后,第一件事就要判断是否为NULL,不要假设它会永远成功;
  2. 一定要保证在连续内存区的边界之内操作,任何一个越界判断都不是多余的;
  3. 指针指向的动态内存不再使用时,一定要第一时间释放。

无论是刚入行的菜鸟还是摸爬滚打多年的老鸟,都需要在案头摆上这本《C 和指针》。对于菜鸟来说,这本书就是破解恐惧,迅速提升功力的捷径;对于老鸟来说,则是升级思维,通向更高境界之路。

愿天下 C 程序员们征服指针,无敌开挂!

    推荐阅读
  • 突触名词解释(突触是什么意思)

    突触名词解释突触是指一个神经元的冲动传到另一个神经元或传到另一细胞间的相互接触的结构。突触是神经元之间在功能上发生联系的部位,也是信息传递的关键部位。在光学显微镜下,可以看到一个神经元的轴突末梢经过多次分支,最后每一小支的末端膨大呈杯状或球状,叫做突触小体。这些突触小体可以与多个神经元的细胞体或树突相接触,形成突触。从电子显微镜下观察,可以看到,这种突触是由突触前膜、突触间隙和突触后膜三部分构成。

  • 《守望先锋》对战局影响大招top一览 守望先锋对局战绩

    今天小编要为大家带来的是玩家“黑呦酱”分享的《守望先锋》对战局影响大招top一览,感兴趣的玩家赶紧一起来看看吧!守望先锋大招分为四类,控制类,自身BUFF类,辅助类以及伤害类,由于伤害类大部分使用大招时,本体无法进行有效杀伤,且控制类及自身BUFF类需要其他技能的配合,so,此间因素也要加入考量。

  • 运动后喝黑咖啡还能燃脂吗 运动时喝黑咖啡会加快燃脂吗?

    2、运动过程中身体脂肪会加速燃烧,从而具有一定减肥作用;而黑咖啡热量比较小,加上其中含有大量的咖啡因以及维生素、纤维素物质,适量喝可以促进人体肠胃蠕动,加速脂肪代谢分解,对减肥具有促进作用。

  • 斯威汽车质量怎么样(斯威质量好不好)

    2018年6月起,斯威“品质特工队”以四大火炉的重庆作为起点,途径海南、吐鲁番、格尔木三地,历时近一年进行了数十万公里极限环境适应性试验。极端干燥高温环境下,常见车内温度往往会狂飙到60℃以上,而在斯威G01的车厢里,却始终能够保持清新凉爽的状态。一整套严酷考验下来,斯威G01的性能表现完全得以充分认证。这样一算,斯威G01差不多完成了近百万公里的专业级严酷考验。

  • 春天兰花怎么养 春天兰花怎么养浇水

    白墨兰花哪个品种最好白墨兰花是墨兰的珍贵变异品种假鳞茎椭圆形,已有数百年栽培历史,流传至今,不下十数个品种,它叶色莹润、体态优雅、幽香静远、且抗病,白墨兰花比较好的品种一般分企剑和软剑两个品系。什么兰花开花最香兰花品种很多,按花香来排,在兰花界春兰居首,惠兰次之,随后便是建兰、墨兰和寒兰,春兰的花香味最正宗,持久性也极强。

  • 奔驰e300l前进挡总共有几个(你看了奔驰22款E300L升级这套原厂HUD抬头显示效果觉得怎么样)

    从行车安全的角度来考虑,加装一台HUD是非常有必要的。HUD的全称是HeadUpDisplay,中文翻译过来就是抬头显示器。今天星骏汇小陈通过以上的产品配件图了解,我们看到这台奔驰22款E300L升级HUD抬头显示所需要更换的配件有,抬显仪器,高配仪表盖板,高配仪表电脑,雨量传感器,空调管升级HUD抬头显示把仪表台上的那一块盖板换掉,换成高配的预留好显示器孔位的盖板,装上显示器,从而使仪表显示的内容投射到挡风玻璃上面。

  • 儿童葫芦丝表演(通城千人共奏葫芦丝)

    儿童葫芦丝表演香城都市报讯 10月27日,通城县隽水中学参加湖北省“黄鹤杯”美育节节目视频录制现场,七、八年级千名学生,同奏乐曲《龙的传人》。该校相关负责人介绍,本学期,每天下午预备铃响5分钟,七、八年级各班集体合奏葫芦丝。丝竹声声,已渐成校园一道靓丽的风景线。近年来,该校贯彻落实社会主义核心价值观,注重未成年人思想道德建设,坚持开设中华传统和特色民族特色教育课程,促进学生“德智体”全面发展。

  • 鸡娃时代孩子的成长之道(与其1岁就开始鸡娃)

    出生时大脑发育已经完成25%,1岁完成了50%,3岁完成了60%,6岁达到90%。现在小学虽然是零基础入学,取消了统一考试,但是它对学生的要求并没有降低。吃够了佛系养娃的亏,橙子家的老二断然不肯再佛系养了。北京卫视于2018年摄制的纪录片《起跑线》中,有一个7岁的北京女孩令人印象深刻。她的家庭,在北京三环内有一套房,一辆车。妈妈认为,孩子从小培养兴趣,靠的是父母的指引。

  • 环氧树脂的作用与用途(环氧树脂有什么作用与用途)

    环氧树脂的作用与用途具有优良的物理和电绝缘性能,强度高、收缩性低,耐腐蚀以及有高绝缘的优势,所以被称为万能胶。电器、电机绝缘封装件的浇注。从常压浇注、真空浇注已发展到自动压力凝胶成型。长时间接触胶水时,有人会有细微的皮肤过敏和细微瘙痒疼痛的情况,建议在运用时戴上防护手套,如果出现了这样的情况,需要用酒精擦洗,然后用清水冲洗干净。

  • 明月曾照江东寒剧情(明月曾照江东寒剧情介绍)

    明月曾照江东寒剧情剧情简介:美少女战清泓是武林副盟主战破敌之女,从小被父亲禁止涉及江湖事。十年一期的武林大会即将来临,战清泓瞒着家人偷跑下山,立志夺取武林盟主之位。战清泓与温宥也开始互生情愫,奈何最终被世俗礼法所阻碍。与此同时,江湖上风起云涌,战清泓发现自己自幼背诵的家训竟是人人趋之若鹜的第一神功《鹤羽剑法》。