函数传指针

函数传指针与引用

            由于在今天编程的时候遇到一个小小的问题,这个问是虽然小,但是闲扰了我一整天的时间------注意,是一整天!
  废话不多说,先给出一段代码
    
  1. // 二叉树的建立.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include <iostream>
  4. using namespace std;
  5. //定义二叉排序树的节点
  6. typedef struct Node
  7. {
  8. int data;
  9. struct Node * lchild;//左孩子
  10. struct Node * rchild;//右孩子
  11. }Node,* PNode;
  12. PNode T=NULL;//二叉排序树的根节点
  13. //中序遍历二叉树
  14. void MidSequence(PNode t)
  15. {
  16. if(t!=NULL)
  17. {
  18. MidSequence(t->lchild);
  19. cout<<t->data<<" ";
  20. MidSequence(t->rchild);
  21. }
  22. }
  23. //往二叉排序树中插入一个新节点(递归实现)
  24. void CreateBSortTree2(PNode & t,int data)
  25. {
  26. if(t==NULL)
  27. {
  28. //建立一个新节点
  29. PNode p=(PNode)malloc(sizeof(Node));
  30. p->data=data;
  31. p->lchild=NULL;
  32. p->rchild=NULL;
  33. t=p;
  34. return;
  35. }
  36. else if(t->data>data)
  37. CreateBSortTree2(t->lchild,data);
  38. else
  39. CreateBSortTree2(t->rchild,data);
  40. }
  41. void insertNode(Node *root,int value){
  42. if(root==NULL){
  43. Node *node=(Node*)malloc(sizeof( Node));
  44. node->data=value;
  45. node->lchild=NULL;
  46. node->rchild=NULL;
  47. root=node;
  48. return ;
  49. }
  50. if(root->data>value){
  51. insertNode(root->lchild,value);
  52. }
  53. if(root->data<value){
  54. insertNode(root->rchild,value);
  55. }
  56. }
  57. //测试
  58. int main()
  59. {
  60. int a[]={0,5,8,4,2,3,10};
  61. int len=sizeof(a)/sizeof(int);
  62. for(int i=0;i<len;i++)
  63. {
  64. //CreateBSortTree2(T,a[i]);
  65. insertNode(T,a[i]);
  66. }
  67. std::cout<<T->rchild->data;
  68. MidSequence(T);
  69. system("PAUSE");
  70. return 0;
  71. }
上面代码的意思是写了两个二叉树插入的代码,一个是我写的:
  1. void insertNode(Node *root,int value){
  2. if(root==NULL){
  3. Node *node=(Node*)malloc(sizeof( Node));
  4. node->data=value;
  5. node->lchild=NULL;
  6. node->rchild=NULL;
  7. root=node;
  8. return ;
  9. }
  10. if(root->data>value){
  11. insertNode(root->lchild,value);
  12. }
  13. if(root->data<value){
  14. insertNode(root->rchild,value);
  15. }
  16. }
上面这部分的代码是存在一定的问题的。不能按期望的结果把value值插入到二叉树中。
  1. //往二叉排序树中插入一个新节点(递归实现)
  2. void CreateBSortTree2(PNode & t,int data)
  3. {
  4. if(t==NULL)
  5. {
  6. //建立一个新节点
  7. PNode p=(PNode)malloc(sizeof(Node));
  8. p->data=data;
  9. p->lchild=NULL;
  10. p->rchild=NULL;
  11. t=p;
  12. return;
  13. }
  14. else if(t->data>data)
  15. CreateBSortTree2(t->lchild,data);
  16. else
  17. CreateBSortTree2(t->rchild,data);
  18. }
而上面的程序按预期的结果运行了。其实比较上面两段代码,我们可以发现,两段代码除了
void  CreateBSortTree2(PNode & t,int data)
void insertNode(Node* root,int value)
红色的部分外,其它的一模一样的。于是我们会问了,为什么会这样子?我们传的不是指针吗,只要是指针,不管在哪里
都可以改变原来的值吗?
嗯,是的,确实可以改变原来的值,因为它把原来值的地址传给你了嘛。。注意,这里传指针也就是将地址按值传过了,
你要知道C语言里面传值是坑人的复制一份的策诺。嗯。。。你确实可以改变函数外面的那个值,但关键是你得使用一个
解引用(*)的操作 也就是说,你得结合那个解引用的操作才行啊,,其它都是扯淡。
  1. #include<iostream>
  2. void foo(int *a){
  3. int b=10;
  4. std::cout<<"b的值 "<<b<<std::endl;
  5. //a=&b;
  6. *a=b;
  7. }
  8. int main(){
  9. int a=3;
  10. foo(&a);
  11. std::cout<<"a的值 "<<a<<std::endl;
  12. }

但是如果程序变成这样:、
  1. #include<iostream>
  2. void foo(int *a){
  3. int b=10;
  4. std::cout<<"b的值 "<<b<<std::endl;
  5. a=&b;
  6. // *a=b;
  7. }
  8. int main(){
  9. int a=3;
  10. std::cout<<"函数运行前a的值 "<<a<<std::endl;
  11. foo(&a);
  12. std::cout<<"函数运行后a的值 "<<a<<std::endl;
  13. }

看到没有,这里a的值可是没有半点改变呢。但是在函数里面我们可是改变了它的地址啊。。。
void foo(int *a){
int b=10;
std::cout<<"b的值 "<<b<<std::endl;
a=&b;
// *a=b;
}
这里传入叁数的时候,确实是将a的地址变成了b的地址。
但是前面说过,传指针其实就是将地址传值嘛。
指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

我们还是回到前面的问题,那为什么人家的代码可以呢?
  1. //往二叉排序树中插入一个新节点(递归实现)
  2. void CreateBSortTree2(PNode & t,int data)
  3. {
  4. if(t==NULL)
  5. {
  6. //建立一个新节点
  7. PNode p=(PNode)malloc(sizeof(Node));
  8. p->data=data;
  9. p->lchild=NULL;
  10. p->rchild=NULL;
  11. t=p;
  12. return;
  13. }
  14. else if(t->data>data)
  15. CreateBSortTree2(t->lchild,data);
  16. else
  17. CreateBSortTree2(t->rchild,data);
  18. }
因为它传的是引用:
而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。
被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操
作都影响了主调函数中的实参变量。

引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。


 






































posted @ 2015-07-17 19:19  yml435  阅读(324)  评论(0编辑  收藏  举报