一个很简单的问题:在C语言中,如果一个数组有10个元素,那么这个数组的下标的允许取值范围是什么呢?
你当然能很快的回答 0-9!而不会说是1-10。但是你能说自己从没写过如下这样的代码吗?
int a[10];
for (int i=0; i <= 10; i++)
a[i] = 0;
是的,这是一个简单的错误,不过也是一个容易犯的错误。
下一个问题:假定整数x满足边界条件x>=16且x<=37,那么此范围内x的可能取值个数有多少?
是37-16=21吗?很遗憾,我们又犯了一个错误,正确的应该是37-16+1=22。
为什么要多加1呢?这就是《C陷阱与缺陷》中所说的“栏杆错误”,并且该书还告诉我们,尽管这些错误很容易出现,但是任然存在一些编程技巧来尽量避免,用第一个入界点和第一个出界点来表示一个数值范围!
比如,对前面的例子,我们不应说整数x满足边界条件x>=16且x<=37,而是说整数x满足边界条件x>=16且x<38。注意,这里下界是“入界点”,即包括在取值范围之中;而上界是“出界点”,即不包括在取值范围之中。这种不对称也许从数学上而言并不优美,但是它对于程序设计的简化效果却足以令人吃惊:
1.取值范围的大小就是上界与下界之差。38-16的值是22,恰恰是不对称边界16和38之间所包括的元素数目。
2.如果取值范围为空,那么上界等于下界。这是第1条的直接推论。
3.即使取值范围为空,上界也永远不可能小于下界。
而最关键的是,对于像C这样的数组下标从0开始的语言,不对称边界给程序设计带来的便利尤其明显:这种数组的上界(即第一个“出界点”)恰是数组元素的个数!因此,如果我们要在C语言中定义一个拥有10个元素的数组,那么0就是数组下标的第一个“入界点”(指处于数组下标范围以内的点,包括边界点),而10就是数组下标中的第一个“出界点”(指不在数组下标范围以内的点,不含边界点)。正因为此,我们这样写:
int a[10];
for (int i=0; i < 10; i++)
a[i] = 0;
而不是写成下面这样:
int a[10];
for (int i=0; i <= 9; ++i)
a[i] = 0;
好了,说了这么多。本篇目的不仅仅是引出这个编码技巧:“用第一个入界点和第一个出界点来表示一个数值范围!”,其实我希望表达的是:C/C++语言中,写类似for这些涉及边界值的语句时,统一采用不对称边界编码风格!这样不仅避免犯错,还能少敲一个'='号哦~