设为首页 加入收藏

TOP

14.4 无法将数组传递给函数
2013-10-07 15:04:56 来源: 作者: 【 】 浏览:71
Tags:14.4 无法 递给 函数

14.4  无法将数组传递给函数

你期望程序清单14.2中的代码打印出什么结果?

程序清单14.2

  1. void process_array(int ar[10])  
  2. {  
  3.   printf("[");  
  4.   for(size_t i = 0; i < dimensionof(ar); ++i)  
  5.   {  
  6.     printf("%d ", ar[i]);  
  7.   }  
  8.   printf("]\n");  
  9. }  
  10.  
  11. int main()  
  12. {  
  13.   int ar1[10] =  
  14.   {  
  15.     0, 1, 2, 3, 4, 5, 6, 7, 8, 9  
  16.   };  
  17.   process_array(ar1);  
  18.   return 0;  
  19. }  

如果你说"[ 0 1 2 3 4 5 6 7 8 9 ]",那么你也许会惊讶地发现实际结果并非如此。事实上,该程序输出为"[0]"。C/C++(www.cppentry.com)程序员第一次遇到这种情况时可能会非常惊讶。我们声明了一个拥有10个整数的数组,赋给其一组值,并将其传递给一个函数,该函数接受一个含有10个整数的数组作为参数。看起来一切都井井有条,问题究竟出在哪里呢?

呃,是这样的,在C/C++(www.cppentry.com)中你无法将数组传给函数!但是,从你开始使用C/C++(www.cppentry.com)编程(www.cppentry.com)起,你就清楚地记得的确是把数组传给函数的,不是吗?可惜这只不过是个假象而已!在C里面,数组被传递给函数时总是被转换成指针,非常干脆地阻止了你获取数组大小的企图。而C++(www.cppentry.com)基于兼容性的考虑,亦是如此。在上面的示例中,我们可以将process_array声明为以下任意一种形式,其行为都是一样的:

  1. void process_array(int ar[20]);  
  2. void process_array(int ar[]);  
  3. void process_array(int *ar);  

现在,随着我把这个问题提上了台面,你也许会回忆起一个类似的现象:main()的参数既可以被声明为char **argv,又可以被声明为char *argv[ ]。我并不打算深入讨论导致这种情形的历史原因,Peter van der Linden在他的Deep C Secrets[Lind1994]的第9章中极其深刻地描述了这个问题。我想指出的是:

Imperfection:C/C++(www.cppentry.com)数组在被传递给函数时会退化成指针。

这种灵活性在许多场合下都是非常有用的,但它也会成为一些问题的来源。C++(www.cppentry.com)(从这一点来说,也包括C)提供了一个严格的类型系统:我们不能将一个指向double的指针传递给某个期望得到指向float指针的地方,数组的情形亦然。然而我们却可以将一个任意长度的数组传递给一个期望接受(指针形式的)数组的函数。那么,我们究竟该怎么办呢?

问题的实质在于数组的大小丢失了,因此,如果我们可以找到一种将数组大小随之传递给函数的机制,问题就会迎刃而解。意料之中,这可以通过模板来实现,我将此类模板称为array_proxy,如程序清单14.3所示:

程序清单14.3

  1. template <typename T> 
  2. class array_proxy  
  3. {  
  4. // 构造函数  
  5. public:  
  6.   template <size_t N> 
  7.   explicit array_proxy(T (&t)[N])  
  8.     : m_base(t)  
  9.     , m_size(N)  
  10.   {}  
  11.   explicit array_proxy(T *base, size_t size)  
  12.     : m_base(t)  
  13.     , m_size(size)  
  14.   {}  
  15. // 状态  
  16. public:  
  17.   T *base()  
  18.   {  
  19.     return m_base;  
  20.   }  
  21.   size_t size() const  
  22.   {  
  23.     return m_size;  
  24.   }  
  25. // 数据成员  
  26. private:  
  27.   T *const      m_base;  
  28.   size_t const  m_size;  
  29. // 声明但不予实现  
  30. private:  
  31.   array_proxy &operator =(array_proxy const &);  
  32. };  

这里还定义了一组转发函数(我们在14.6.5小节将会看到它们的运用),这些函数使我们能够在无需指明类型 的情况下创建array_proxy实例。
  1. template <typename T, size_t N> 
  2. inline array_proxy<T> make_array_proxy(T (&t)[N])  
  3. {  
  4.   return array_proxy<T>(t);  
  5. }  
  6. template <typename T > 
  7. inline array_proxy<T> make_array_proxy(T *base, size_t size)  
  8. {  
  9.   return array_proxy<T>(base, size);  
  10. }  

该模板是本章的一个重点内容,是一个特色,后面我们会对其不断精化,以便使其能够对其他数组/指针问题提供帮助,所以暂且别担心它当前较为粗陋的形式。

现在我们总算可以将数组真正当成数组来传递了:

  1. void process_array(array_proxy<int> const &ar)  
  2. {  
  3.   printf("[");  
  4.   for(size_t i = 0; i < ar.size(); ++i)  
  5.   {  
  6.     printf("%d ", i[ar.base()]); // 新手往往难以理解这行代码!  
  7.   }  
  8.   printf(")\n");  
  9. }  

现在这个函数可以打印出我们想要的结果了。显然,我们不想每次在索引时都调用base(),有没有更优雅的使用接口呢?别忘了,array_proxy会不断进化的。
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇14.5 数组总是按地址进行传递 下一篇9.7.1 自动的实例化器(2)

评论

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