Chinaunix首页 | 论坛 | 博客
  • 博客访问: 369380
  • 博文数量: 159
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 182
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-02 10:42
文章分类

全部博文(159)

文章存档

2015年(18)

2014年(132)

2013年(9)

分类: C/C++

2014-07-07 18:01:56

    在C语言中因为参数的传递方式属于值传递,局部参数在函数内部的改变并不会影响实参的值,有时候为了保存对在函数中的修改,往往采用返回值或者指向指针的指针的形式来实现,我就采用简单的内存分配来说明。其中很多初学者都会犯的错误就是第一种实现方式,那是因为我们没有搞清楚C语言的参数传递方式。
 

点击(此处)折叠或打开

  1. /*错误的实现*/
  2. void getmemory(int *ptr,int size)
  3. {
  4.    ptr = (int *)malloc(sizeof(int)*size);
  5. }

  6. /*返回值类型*/
  7. int * getmemory(int size)
  8. {
  9.    int *temp = (int *)malloc(sizeof(int)*size);
  10.    if(temp != NULL)
  11.    {
  12.      return temp;
  13.    }
  14.    return NULL;
  15. }

  16. /*指向指针的指针*/
  17. void getMemory(int **buf,int size)
  18. {
  19.     *buf = (int *)malloc(sizeof(int)*size);
  20. }
 
    上面的实现是C语言中关于指针更新的两种方式,这两种方式在一些结构体中使用的也比较多,比如链表,队列等常用的数据结构操作中。这两种实现方式有各自的优缺点,比如返回值类型,因为在C语言中只能返回一个值,当然也可以采用结构体的形式采用保证实现多类型返回。这时候如果返回了一个指针操作,往往也不便于返回其他重要的信息,比如有时候要返回操作是否成功的标志等,这时候就显得特别不方便,最典型的例子就是在链表头中插入新的数据时,这时候链表头被更新了,如果直接返回链表头就不能观察当前操作是否完成,而且如果没有都需要返回值来更新链表头,也显得特别不方便。

 

点击(此处)折叠或打开

  1. /*返回值式的链表更新表头操作*/
  2. head = insert_listnode(head,value);

  3. /*自动更新的操作*/
  4. insert_listnode(*head,value);
 
    一般而言,我在写程序的过程中更加喜欢用第二种形式,这时候就显得第一种特别的不舒服。但是第二种写法也存在一些缺点,特别是当很多人对指针处于懵懂的期间,很容易出现错误,因为在函数内部一般操作的对象不是传递进来的参数,而是对参数的解引用,如果对函数调用和指针不是很清楚的情况下,这种写法很容易出现错误,因为不知道何时是采用(*head)何时采用head,不清楚这一点,代码自然而然就出现了错误。第一种往往是很多入门级程序员(我之前一般采用的方式)比较喜欢的方式。
 
    在C++中关于函数参数的传递比C语言中有了更多的选择,其中比较重要的就是引用的引入,引用是一段内存区域的别名,对别名的操作实质上就是对内存本身的操作,这和传值的方式有着本质的区别,有了这种意识。我觉得采用引用的方式实现指针的更新就会更加的方便,也就能够克服前面两种方法的缺点。即占用返回值和在函数内部合适使用指针合适使用解引用。
 
    采用简单的例子说明:

点击(此处)折叠或打开

  1. bool getMemory(int * &a, int size)
  2. {
  3.    /*本应该采用new实现,但是为了和前面一直,采用malloc实现*/
  4.    a = (int *)malloc(sizeof(int)*size);
  5.    if(a != NULL)
  6.       return true;
  7.    else
  8.       return false;
  9. }
 
    这时候就很好的实现了在函数内部实现实参指针参数的更新,简要的分析一下,由于变量a是一个指针对象的引用,在函数的调用时就发生了引用对象的绑定操作,绑定一旦完成就不会更改了,这时候对变量a的操作实质上就是对指针的操作,如下所示:
 

点击(此处)折叠或打开

  1. int *b;

  2. /*
  3.   在调用该函数的时候,相当于发生了绑定操作
  4.   int *&a = b;
  5.   这时候对a的操作就是对b的操作
  6.   在函数内部将a指向了一个新的对象
  7.   实质就是将b指向了这个对象
  8.   这样就实现了实参指针的更新操作
  9.   这种操作不需要注意解引用,而且不会占用返回值
  10. */
  11. getMemory(b,10);
 
    所以说在C++ 中,多考虑引用的方式作为参数,不仅仅能够避免大数据结构的复制,有时候也能起到恰到好处的作用。我认为这也是C++中推荐使用引用作为参数的原因之一。
阅读(380) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~