分清 C++的指针、引用和数组

C++ 里面的指针常常使初学者感到困惑,尤其是和引用,常量,数组等组合起来的时候,一个变量是数组,还是指针,指针是常量,还是所指对象是常量就显得更模棱两可了,例如下面这些代码:

如果你也有类似的困惑的话,希望在读完本文之后,会有一个清晰的概念。

热身

一个内存位置,保存一个值,内存位置也可以作为值,这就叫做指针。在事情变得复杂之前,我们可以确定两件事:一个变量保存的要么是地址,要么是值。现在,我们从最简单的概念开始:

  1. 指针保存的是地址,解引用得到对象的值
  2. 引用类型是真实对象的“绑定”,可以当做这个对象的另一个名字来使用,对引用类型的操作,就是对真实对象的操作(引用必须初始化!)。取地址得到的是对象的地址
  3. 解引用 * ,取地址 & 具有双重含义:在表达式中作用如1 2 粗体所示;在声明中,它们用来组成复合类型。注意:int *p = i;

举个栗子:

那么问题来了:改变的是指针指向的对象呢?还是对象的值呢?

法则一:改变的永远是等号左侧的对象。

比如,第2行,等号的左侧是定义,r 是 int 类型的引用,引用“绑定”了 i;第4行,等号左侧是指针,那么改变的就是 指针的值,也就是所指的对象;第7行,等号左边是指针解引用,那么修改的就是指针指向的对象,即 i;最后一行,等号左侧是引用类型取地址,是一个地址,额,对一个地址赋值,很显然这一行是错误的……

注意:虽然上文说了某些符号在定义式中有另一种含义,但这还是常常使人混淆——*p不应该是变量的值吗? 我有个小技巧,将在定义式中的*理解成为类型的一部分,将它看成和 int 的组合就好了,像这样:int * p = i;

复合类型

上面的概念是不是很简单?接下来要将指针和引用相互组合,产生更复杂的类型了。

指向指针的指针

首先,指针先指向了一个对象。这个对象保存的是个地址,对这个地址解引用,可以得到令一个对象的值。

在内存中,是这个样子的:

pointer

指向指针的引用

由于引用不是真实的对象,所以不存在“指向引用的指针”,但却可以有“指向指针的引用。”这时,上文的规则同样适用,即作为指针的别名使用。

现在就有点复杂了,r 到底是指针还是引用呢?法则二:从右向左读。例如第三行的 r ,左边是 &,所以它是个引用类型,再向右,* 表示引用的这个类型是一个指针,再向右 int 表示,这个指针的类型是int,综合,r就表示“一个指向 int 型的指针的引用。

const限定符和constexpr

当 const 涉及指针的时候,可以分为两种情况:

  1. 顶层const:指针本身是个常量,不能改变所指的对象。
  2. 底层const:指针指向的对象是一个常量,不能改变或者通过指针改变这个对象的值。

不要慌,这里法则二依然适用:从右向左。对于 p1,右侧是 const ,表示 p1 是一个常量,向右,p1 是常量指针,再右,常量指针 p1 指向了 int 型。

小试牛刀:解释一下p2和p3吧!

constexpr

这是 C++11 的新规定,允许将变量声明为 constexpr 类型以便由编译器来验证变量的值是否是一个常量表达式。

“变量的值”,就是左值,说白了就是基本类型是不是一个常量。比如 a 基本类型是 int ,constexpr 就指定 int 型为常量。 p 是一个指针,constexpr 指定指针 p 是一个常量。由此,我们可以得到法则三:constexpr 声明中如果有指针,那么constexpr 只对指针有效,而与对象无关。

类型别名

类型别名顾名思义,就是将复杂的变量名起一个好听好记的名字。可以参考1-3行,这是类型别名的常用的例子(其实最常用的时候,是给长长的结构体取“外号”)。

看完了前3行之后,你可能觉得“就是个别名,那我理解的时候,替换成原来的名字就好了!”所以你就会像 p_c_str 那样,去解释 c_p_str :按照我们的从“右向左法则”,它首先是一个指针,然后指向 char 型,这个 char 型是 const 的,所以这是一个“指向char 型常量的指针”。

这是完全错误的!是我们的“从右向左”法则出错了吗?不是的,要相信,从右向左在任何时候都是对的,如果它错了,那么一定是你错了——你错就错在,将 typedef 指定的别名拆开理解了。正确的理解很简单,对于 typedef,你要从心底认为这是同一个类型的别名,pstring 是“指向 char 型的指针”,永远都是。对于 c_p_str,从右向左的时候,第一步是“它是一个指向 char 型的指针”,而不是“它是一个指针”。第二步理所应当的是“这个指针的类型是 const 的”,综合,c_p_str 就是“指向 char 类型的常量指针”。

法则四:typedef 定义的类型别名不要替换成原来的名字去理解!

小试牛刀,解释一下 ps 吧!答案是:“ps 是一个指针,它指向了一个对象,这个对象是一个指向 char 的常量指针。”

decltype 类型指示符

这也是 C++11 的新标准,编译器分析表达式并返回其类型,要注意的是,不会计算表达式的值。这点非常重要,因为上文说过,引用从来都是作为所指对象的同义词出现,但只有在deltype 的时候是个例外。原因如下:

第三行因为编译器阶段并不会对 *p 求值,所以直接返回一个引用类型。这个地方,引用就和所绑定的对象有区别了。(事实上,第三行是错误的,因为定义引用的时候没有初始化。)

法则五:在(且仅在)deltype 处,引用不是对象的同义词!

数组

引用可以绑定数组,指针可以指向一个数组,数组可以存放指针,但是唯独不存在引用的数组!参考下面的例子:

很显然,这里不能再用从右向左了,不然的话,”[ ]”永远也读不到了。对于负责的数组声明,要由(内)向外阅读——法则六。

例如 p_array ,首先,它是一个指针(内指的是括号内),然后类型修饰符从右向左再依次绑定:指向的是一个数组,这个数组是int型。 再复杂的数组,也可以以此类推。

Summary

  1. 改变的永远是等号左侧的对象。
  2. 从右向左读(类型修饰符依次绑定)。
  3. constexpr 声明中如果有指针,那么constexpr 只对指针有效,而与对象无关。
  4. typedef 定义的类型别名不要替换成原来的名字去理解!
  5. 在(且仅在)deltype 处,引用不是对象的同义词!
  6. 对于复杂的数组声明,要先从内向外读,再按照从右向左。

不是 So easy 呢?你会读了吗?

 

笑话三则

昨天在隔壁宿舍讨论算法的时候,一个室友大喊了一声:“卧槽,老子就是更新了个 QQ 而已,这 QQ 浏览器和 QQ 音乐是哪里来的!”

说起来,我昨天从一个网站上下载了一些扑克牌的素材图片,过了一会儿……打字的时候,输入法已经默默地变成了百度输入法……

不过还是另一位朋友更惨,他说:“有次回宿舍,手机顺手插在电脑的 USB 上就上厕所去了,回来的时候,手机已经装好了360……。”

形成鲜明对比的是,最近收到一封广告邮件,于是发回去问他们是怎么知道我地址的。竟然真的收到了礼貌的回复:

emailreplay

 

自由比皇帝更伟大——《悲惨世界》笔记

在第三部《马吕斯》第四卷 ABC 朋友会中的第五章 “开阔视野”中,马吕斯和他在 ABC 的朋友们有一段精彩的辩论。ABC 的青年象征了年青一代,思想进步,热爱自由,热血,激进。读这段的时候,我和他们产生了强烈共鸣。

即使没读过《悲惨世界》,也能从中感受到这些青年人思想碰撞的火花,这段对话发生的时候,马吕斯刚加入 ABC 朋友会。在此之前,追随拿破仑的生父去世,马吕斯知道了父亲的事迹,由此产生了对拿破仑皇帝狂热的崇拜,和对共和国复辟的坚定信仰。因为这个政治观点和外公不和,大叫着“达到波旁王朝,打倒肥猪路易十八”离家出走,加入了 ABC 朋友会。 这一章,摘抄如下:

五 视野的扩展

青年们的相互接触有那么一种可喜的地方,那就是人们在其中无法预见火星,也无法预测闪电。过一会儿将会爆发什么?谁也不知道。温婉的交谈常引起一阵狂笑。人在戏谑时又常突然转入严肃的话题。偶然一个字能使人冲动。每个人都被激情所主宰。一句玩笑话已够打开一个意外的场面。这是一种山回路转、景物瞬息万变的郊游。偶然是这种交谈的幕后操纵者。

那天,格朗泰尔、巴阿雷、勃鲁维尔、博须埃、公白飞和古费拉克一伙谈得起劲,你一言,我一语,混战正酣,不料从唇枪舌剑中突然出现了一种奇怪的严肃思想,穿过喧杂的语声。

一句话怎样会在言谈中忽然出现的?它又怎么会突然吸引住听者的注意力?我们刚才说过,这是谁也不知道的。当时,在喧嚷哄闹声中,博须埃忽然对着公白飞随便说出了这个日期:

“一八一五年六月十八日:滑铁卢。”

马吕斯正对着一杯水,一手托着腮帮,支在一张桌子边上坐着,听到”滑铁卢”这三个字他的手腕便离开了下巴,开始注视在座的人们。

“上帝知道,”古费拉克喊着说(在当时,”天晓得”已经不大有人说了),”十八这个数字是个奇怪的数字,给我的印象非常深。这是决定波拿巴命运的数字。你把路易放在它的前面,雾月放在它的后面,这人的整个命运便全显现在你面前了。这里又还有这么一个耐人寻味的特点,那就是开场是被结局紧跟着的。”

安灼拉一直没有说过一句话,这时他才开口,对着古费拉克说了这么一句:

“你是要说罪行被惩罚紧跟着吧。”

马吕斯在突然听见人家提到”滑铁卢”时,他已很紧张了,现在又听人说出”罪行”这种字眼,那就更超出他所能接受的限度了。

他站起来,从容走向那张挂在墙上的法兰西地图,地图下端,原有一个隔开的方格,方格里有个岛,他把手指按在那方格上,说道:

“科西嘉。一个使法兰西变得相当伟大的小岛。”

这是一股冰冷的风。大家全不说话了。大家都觉得要发生什么事了。

巴阿雷正在摆出他常爱用的那种正襟危坐的姿势来和博须埃对驳,他也为了要听下文而放弃了那种姿态。

安灼拉的蓝眼睛并没有望着谁,仿佛只望着空间,这时他眼睛虽不望马吕斯,嘴里却回答说:

“法兰西并不需要科西嘉来使它自己伟大。法兰西之所以伟大,只因为它是法兰西。’因为我的名字叫狮子。'”

ABC

马吕斯绝没有退却的意思,他转向安灼拉,他那出自肺腑的激越的声音爆发出来了:

“上帝惩罚我要是我有贬低法兰西的意思,但是把它和拿破仑结合在一起,这并不贬低它一丁点。真怪,我们来谈谈吧。我在你们中是个新来的,但是老实说,你们确使我感到奇怪。我们是在什么地方?我们是谁?你们是谁?我是谁?让我们就皇帝这个问题来谈谈各自的见解吧。我常听见你们说布宛纳巴,象那些保王党人一样,强调那个’乌’音。老实告诉你们,我那外祖父念得还更好听些:他说布宛纳巴退。我总以为你们都是青年。你们的热情究竟寄托在什么地方?你们的热情究竟要用来作什么?你们佩服的是谁,如果你们不佩服皇上?你们还要求什么?如果你们不要这么一个伟大的人物,你们要的又是些什么样伟大的人物?他是一个全才。他是一个完人。他的脑子包含着人类种种才智的三乘。他象查士丁尼那样制定法典,象恺撒那样独理万机,他的谈吐兼有帕斯加尔的闪电和塔西佗的雷霆,他创造历史,也写历史,他的战报是诗篇,他把牛顿的数字和穆罕默德的妙喻糅合在一起,他在东方留下了象金字塔那样高大的训谕;他在提尔西特把朝仪教给各国帝王,他在科学院里和拉普拉斯争鸣,他在国务会议上和梅尔兰辩论,他经心整饬纪律,悉力排难解纷,他象检察官一样了解法律,象天文学家一样了解天文;象克伦威尔吹灭两支蜡烛中的一支那样,他也到大庙①去为一粒窗帘珠子讨价还价;他见到一切,他知道一切,这并不妨碍他伏在他小儿子的摇篮上笑得象个天真烂漫的人;突然,惊骇中的欧洲屏息细听,大军源源开拔了,炮队纷纷滚动了,长江大河上建起了浮桥,狂风中驰聘着漫山遍野的骑兵,叫喊声,号角声,所有的宝座全震动了,所有的王国的国境线全在地图上摇晃起来了,人们听到一把超人的宝剑的出鞘声,人们看见他屹立在天边,手里烈焰飞腾,眼里光芒四射,霹雳一声,展开了他的两翼,大军和老羽林军,威猛天神也不过如此!”

大家全不言语,安灼拉低着脑袋。寂静总多少有那么点默许或哑口无言的味儿。马吕斯,几乎没有喘气,以更加激动的心情继续说:

“我的朋友们,应该公正些!帝国有这么一个皇帝,这是一个民族多么辉煌的命运啊,而这个民族又正是法兰西,并且能把自己的天才附丽于这个人的天才!到一国便统治一国,打一仗便胜一仗,以别国的首都为兵站,封自己的士卒为国王,连连宣告王朝的灭亡,以冲锋的步伐改变欧洲的面貌,你一发威,人们便感到你的手已握住了上帝的宝剑的柄;追随汉尼拔、恺撒和查理大帝于一人;作一个能使每天的曙光为你带来响亮的前线捷报的人的人民;以残废军人院的炮声为闹钟,把一些彪炳千古的神奇的词抛上光明的天际,马伦哥、阿尔科拉、奥斯特里茨、耶拿、瓦格拉姆!随时把一些胜利的星斗罗列在几个世纪的天顶,使罗马帝国因法兰西帝国而不能专美于前,建大国,孕育大军,象一座高山向四方分遣它的雄鹰那样,使他的百万雄师飞遍整个大地,征服,控制,镇压,在欧洲成为一种因丰功伟绩而金光灿烂的民族,在历史中吹出天人的奏凯乐,两次征服世界,凭武功,又凭耀眼的光芒,这真卓绝,还能有什么比这更伟大的呢?”

“自由。”公白飞说。

这一下,马吕斯也把头低下去了。这个简单冰冷的词儿象把钢刀似的插进他那激昂慷慨的倾诉里,登时使他冷了半截。当他抬起眼睛时,公白飞已不在那里了。他也许因为能对那谀词泼上一瓢冷水而心满意足,便悄悄地走了,大家也全跟着他一道走了,只留下安灼拉一个人。那厅堂变成空的。安灼拉独自待在马吕斯旁边,闷闷地望着他。马吕斯这时已稍稍理了一下自己的思绪,但仍没有认输的意思,他心里还剩下一股未尽的热流在沸腾着,正待慢条斯理地向安灼拉展开争论,忽又听到有人在一面下楼梯一面歌唱,那正是公白飞的声音,他唱的是:

恺撒如给我

光荣与战争,

而我应抛弃

爱情与母亲,

我将对伟大的恺撒说:

收回你那指挥杖和战车,

我更爱我的母亲,咿呀嗨!

我更爱我的母亲!

公白飞的既柔婉又粗放的歌声给了那叠句一种雄伟的气势。马吕斯若有所思,呆望着天花板,几乎是机械地跟着唱:

“我的母亲!”

这时,他觉得安灼拉的手在他的肩头上。

“公民,”安灼拉对他说,”我的母亲是共和国。”

 

Git 10 周年访谈:Linus 讲述背后故事

十年前的这一周,Linux 内核开发社区正面临严峻的挑战:他们不能继续使用 BitKeeper 了(伯乐在线注:原因是当时Bitkeeper 著作权所有者决定收回授权,内核开发团队与其协商无果),而又没有其他的 SCM (Software Configuration Management)可满足他们的分布式系统的需求。Linux 之父 Linus Torvalds 接受了这个挑战,决定开发一个新的版本控制系统。周末他消失了,新的一周,Git 问世了。今天,Git 已经成为上万个项目的版本控制系统,并且在程序员中引发了开源热潮。

为了庆祝里程碑式的一刻,Linux 基金会邀请了 Linus 来分享 Git 背后的故事,以及他对 Git 在软件开发中的影响的观点。

Linus-Torvalds-LinuxCon-Europe-2014

你为什么要开发 Git?

Torvalds:我从来没有想过去做版本控制软件,因为在我看来那是计算机世界里最无聊的事了(如果数据库除外的话 ;^),我天生就不喜欢 SCM。但是 Bitkeeper 的诞生改变了我对版本控制的认识。BK 在大多数方面是正确的,在本地保存一个仓库的副本,分布式合并确实是一大创新。这个分布式版本控制的创新完美地解决了 SCM 的通病:“谁可以修改代码”的难题。BK 告诉我们,你只要给每个人一个仓库,问题就解决了。但是 BK 也存在一些问题,技术上的问题(例如重命名很麻烦)还不算什么,它最大的坏处是不开源,很多人因为这个不使用它。所以即使我们有几个核心维护者使用 BK——开源项目可以免费使用——但它也没有普及。虽然它帮助过我们开发内核,但依然有不少痛点没有解决。

当 Tridge 违反 BK 的使用协议反编译 BK 的时候,我们到达了紧急关头。我花了几个周(还是几个月来着?)试图调解 Tridge 和 Larry McVoy(伯乐在线注:他是 Bitkeeper 的 老大),最后也没有成功。我意识到我不能继续使用 BK 了,但我真的不想回到没有 BK 的黑暗时代。遗憾的是,我们想用其他 SCM 来代替它,却没有找到能在远程方面工作得好的。现有的软件不能满足我对远程方面的需求,我又担心整个流程和代码的完整性,所以最后我决定自己写一个。

你怎么做到的?整个周末都在熬夜写这个,还是只用了常规的时间?

Torvalds:呵呵,其实可以在 Git 的源代码仓库中看它是如何成型的。除了第一天的工作,因为我花了一天的时间进入“自举(self-hosting)”。之后我就能使用 Git 向 Git 自己提交代码了,虽然第一天所有的东西都不是明确的,但是大体上也都在那里了。虽然这些工作大多是在白天完成的,但也有时候工作到了深夜,甚至有两天到了凌晨两点。最有趣的部分是如何将它快速成型。Git 树中的第一次提交没有太多代码,但是它的基本功能已经实现了——向它自己提交代码。这部分写代码并不难,难的是如何组织数据。

所以我想强调的是,虽然它在短短十天内就完成了(我第一次使用 git 向内核提交代码的时间),但是这并不是某种“马拉松”式的开发。事实上,我早期的开发成本很低,这取决于基本的思路正确。在这个项目开始之前,我想了很久,我总结了很多别人犯过的错误,然后极力避免了。

Git 达到了你的期望吗?你估计一下它现在工作得如何?它还有什么不足吗?

Torvalds:我对 Git 很满意。它工作得相当出色,满足了我的所有需求。有趣的是,它还接手了很多其他项目,它成长地相当迅速。在切换版本控制系统中有很多惰性,看看 CVS 和 RCS 这些坚持了这么久就知道了。不过等时机到了,Git 早晚都会接管过来。

你觉得为什么它会被如此广泛地接受?

Torvalds:我提过以前我为什么痛恨 SCM,我相信很多人也为相同的问题烦恼过。很多项目要改一两个小地方就会使人抓狂。在 Git 之前,没有东西来真正解决这个问题。人们不清楚分布式的重要性, 可能还会与此抗争。一旦他们明白它支持的方便可靠的备份,并允许做私人的测试仓库,而不必担心有无中央存储仓库的权限的话,他们就永远不会放弃 Git 了。

Git 会永远流行吗?还是你预见在将来的十年会有另一种版本控制系统?作者会是你吗?

Torvalds:我不会是唯一一个作者,将来我们也可能使用另一种工具,但是我敢保证,它一定和 Git 非常像(“git-like”)。我不是说 Git 的什么都是对的,但它的基本路线是对的,之前其他 SCM 未曾尝试过。

没有假谦虚 :)

为什么 Git 能在 Linux 上工作地这么好呢?

Torvalds:很显然,Git 最初是为我们的工作流程设计的,所以这是它的一部分。虽然我重复“分布式”这个词很多次了,但这不为过。它被设计为足以高效地应付像 Linux 一样的大项目,它也用于完成 Git 之前人们觉得“艰难”的事情——因为这些事我每天都要做。

举个例子吧:在大多数的 SCM 中,“merging” 操作都被认为是痛苦而且艰难的事情。你需要计划好你的合并操作,因为这涉及到很多繁琐的细节。这我不能接受,因为我每天要做几十次合并,即使这样,最大的麻烦还不是合并本身,而是测试结果。“Git”的合并只需要几秒钟,写合并注释反而会花去我更多的时间。

所以 Git 基本上是为了满足我的需求来写的。

人们说 Git 是为聪明人设计的,即使 Andrew Morton 也说 “Git的明确设计让你感觉你比你想象中的要蠢。”你对此的回应是什么呢?

Torvalds:我觉得曾经可能是这样的,但现在不再是了。人们这么想可能会有很多原因,但只有一个站得住脚,很简单:“在 Git 中完成一件事你有太多的方法”。

使用 Git 你可以做很多事,大多数“你应该怎样”的规则,其实并不是技术上的限制,而是建议,这样你和别人一起工作的时候可以配合得更好。Git 是一个强大的工具,但是你不能因为这个望而却步。虽然你可以每次用不同的方法完成相同的事情,但在多数情况下,学习 Git 的最好方法还是从最基本的事情做起。直到你熟悉基本操作了,再去接触别的东西。

Git 给人复杂的印象有一些历史原因。其中一个是,它很早之前确实是复杂的。一开始需要使用 Git 来做内核方面的工作的时候,人们要配置一些脚本。那时候的工作主要集中于让核心模块工作,花在易用性方面的精力很少。所以很显然,Git 因其复杂性著称,但那大约还是头一年的事了。

人们认为 Git 难的原因是 Git 的与众不同。很多人用过十几二十年的 CVS,但 Git 并不是 CVS,一点都不像。概念不同,命令也不同。Git 从来没有考虑过要像 CVS,甚至大行反道。所以如果你使用 CVS 之类的系统很长时间,就会觉得 Git 复杂,而且它的差异毫无必要。人们会对版本号码感到奇怪。为什么 Git 的版本不像 CVS 的“1.3.1”这种递增式的数字?为什么会是恐怖的四十位 Hex 码?

但 Git 的不同并不是“毫无必要的”。只是这点让人们觉得它太复杂了,因为它来自一个不同的背景。“CVS”的背景过时了。现在很多程序员从没用过 CVS,如果他们学 CVS,可能觉得 CVS 的方式太诡异了,因为他们最先学的 Git。

如果没有 Git,Linux 内核会发展的像现在这样好吗?为什么?

Torvalds:“没有 Git”,好吧,但是一定会有别人写出来个像 Git 的工具,一个分布式版本控制系统。毫无疑问,我们需要“Git”这样的东西。

你怎么看待 Github ?

Torvalds:Github 是非常棒的代码托管服务,对此我没有任何反对。我的抱怨主要是因为它作为一个开发平台——提交代码,pull request,跟踪问题等等——不够好。不适用于内核之类的项目。限制太多了。

部分原因是,因为内核发展的原因,部分是因为 Github 的接口很鼓励坏习惯。在 Github 的提交有不好的提交信息等等,就是因为接口的问题。他们确实做了改善,可能现在好点了,可是永远不会适用于 Linux 内核这样的项目。

你见过的用 Git/Github 做的最有趣的事情是什么?

Torvalds:看到创建一个新项目能如此简单,我很开心。以前搞代码托管很痛苦的,但现在用 Git/Github ,创建一个小项目就小菜一碟了。你的项目是什么并不重要,重要的是你可以做得到。

你现在有什么精彩的项目吗?有什么将推动软件发展软件吗?

Torvalds:暂时没有,如果有的话,我会告诉你。

本文由伯乐在线推荐,赖信涛翻译,原文Linux.com,点击下图,可以访问特别制作的Git 十周年。

AtlassianGit10year

 

用 0x3f3f3f3f 设定最大int值的优点

在许多算法中都要用到一个常量来表示最大值,例如:寻找一个最小数,就要先设定一个值a,如果比a小,a就等于这个数;再如,最短路径中基本的松弛操作:

计算机不会表示出“无穷大”的概念,所以我们只能以一个定值来表示“最大”。那么使用什么值呢?

对于int类型,很自然地,我们想到用 0x7f ff ff ff 。这是32-bit的int类型所能表示的最大值。int类型在内存中的形式是,除了第一位表示正负,剩下的二进制位表示数据大小,将所有位设置为1,就是int的最大值,这个值是 2^31-1=2147483647 ,是一个十位数。

20150402204748

这样做对于上文中的第一个例子,是没有问题的,因为不涉及到计算。但是如果对于后一种,就会出现数据溢出的隐患。如果这个最大值加上任何一个数,就会变成一个很小的负数。所以,我们还要满足“无穷大加上无穷大还是无穷大。”的原则。

如果使用 0x3f3f3f3f ,这个问题可以得到完美的解决。这个数字的值是 1061109567,也是一个十位数,和 0x7fffffff是一个数量级的。而且它的两倍是 2122219134 ,就满足了即使两个无穷大相加,仍然可以表示一个无穷大。

20150402205123

 

使用这个数还有一个好处。我们想将一个数组的数据全部置为无穷大的时候(经常用到),使用的 memset的第二个参数value是8-bit的。

value:Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned charconversion of this value.

也就是说,memset是按照8位来格式化数组的,而通过上图我们可以发现,0x3f3f3f3f的四个八位都是一样的!这样我们就可以使用memset来将数组所有值最大化,而不用使用循环了,提高了效率。

综上,将INF(最大值)设置为0x3f3f3f3f是一个不错的选择!