设为首页 加入收藏

TOP

14.1 不要重复你自己
2013-10-07 15:06:35 来源: 作者: 【 】 浏览:67
Tags:14.1 不要 重复 自己

第14章 数组和指针

数组是"固定大小的一组类型相同的数据……从逻辑上说是连续地存储的,并且……可以通过下标索引进行访问"[Sedg1998a],数组还是基本数据结构之一[Knut1997]。大多数语言中都有数组,然而许多现代语言中却没有指针的概念,因为指针被认为是太危险的东西。指针允许对它们所指向的实例所占用的内存位置进行直接访问,但是它们也常常会导致破坏内存。尽管这样,C和C++(www.cppentry.com)还是提供了指针,因为它们在程序的效率方面提供了强大的威力和更多的可能性,这与"C精神"是相符的(见序言)。

在本章中,我们将考察一些议题,这些议题是关于语言的一些不尽人意的地方,包括数组大小、数组/指针双重性,以及C++(www.cppentry.com)所特有的一个问题,即传递指向派生类数组的指针。

14.1  不要重复你自己

Andrew Hunt和David Thomas在他们的著作The Pragmatic Programmer中描述了DRY(Don't Repeat Yourself,不要重复你自己)原则。从本质上,这条原则说的是:任何东西你应该只定义一遍。因为如果存在多于一处的定义的话,那么当其中一处更新而其他某(些)处没有同步进行更新时,不一致性就无可避免地产生了!这是衡量代码质量的一个基本标准,在数组的定义和操纵中常常会见到:

  1. char  ar[23];  
  2.  
  3. strnset(ar, ' ', 23); 

如果我们改变了数组ar的大小,却不对strnset()的第三个参数作出相应的改变,就会导致两种可能的后果。如果我们增大了ar的大小,那么strnset()将不再能够对整个数组进行填充。更糟糕的情况则是我们缩减了数组ar的大小,从而导致strnset()对数组之外的内存(数组的真实结尾之后的内存)进行破坏性的写入(覆盖)。对于这种情况,通常的建议是声明一个常量(通过C的#define或C++(www.cppentry.com)的const),并在其他用到该数字的地方都采用该常量。这样一来,当需要作出改动的时候,改动一处即可:
  1. #ifdef __cplusplus  
  2.  const size_t DIM_A = 23;  
  3. #else  
  4. # define DIM_A        (23)  
  5. #endif /* __cplusplus */  
  6.  
  7. char  ar[DIM_A];  
  8.  
  9. strnset(ar, ' ', DIM_A);  

现在,要想改变ar的大小只需改变DIM_A就行了,strnset()的第三个参数以及其他任何使用该常量的地方均会随之而改变。这种解决方案不赖,但是它仍然脆弱,代码依然可能遭受错误的改动。比方说,或许维护者希望增加空间来存放null结束符,但他并不去将DIM_A修改为合适的值,而是去错误地将ar的定义改变为ar[DIM_A+1]:
  1. char  ar[DIM_A + 1];  
  2.  
  3. strnset(ar, ' ', DIM_A); // ar[DIM_A]是啥东西?  

代码复审自然能够查出这个错误,但是正如我们所知,代码复审计划的定期性总是远远小于它应该的那样。 如果C++(www.cppentry.com)中的数组像其他(某些)语言中的数组那样具有length属性就好了,像这样:
  1. char  ar[DIM_A];  
  2.  
  3. strnset(ar, ' ', ar.length);  

C和C++(www.cppentry.com)都有sizeof()操作符,但是该操作符返回的是以字节计的大小。在本例中,我们自然可以直接使用sizeof(),因为sizeof(char) == sizeof(byte)(见13.1节)。然而,如果例子当中使用的是wchar_t数组以及wcsnset()的话,sizeof()就会使ar只有1/2或1/4(具体取决于wchar_t中的字节个数)被wcsnset()所影响。 我们需要的是一个可以求出数组中元素个数的操作符,而不是一个求出按字节计的数组大小的操作符。

Imperfection:C和C++(www.cppentry.com)没有为数组类型提供dimensionof()操作符。

这是我们在编码中经常会涉及的问题,经典的 解决方案(对C和C++(www.cppentry.com)同样有效)是使用宏,比如NUM_ELEMENTS()宏, 定义如下:

  1. #define NUM_ELEMENTS(x)   (sizeof((x)) / sizeof((x)[0])) 

我们通过将数组以字节计的大小除以其中每个元素的(也是以字节计的)大小来得出数组中元素的个数。这样我们的例子代码就可以改成:
  1. char  ar[DIM_A];  
  2.  
  3. strnset(ar, ' ', NUM_ELEMENTS(ar));  

这通常是一种可行的解决方案,但仍然存在一个缺点,我们将会在14.3节进行讨论,当前我们先叉开话题讨论一些相关的内容。
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇14.2 数组退化为指针 下一篇14.2.2 阻止退化

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: