小议指针(转自刺猬小屋)

来源:互联网 发布:信天游手机炒股软件 编辑:程序博客网 时间:2024/05/16 01:18

1.指针与引用

C++引入了参数引用机制,从而在一定程度上避免了对指针过多的纠缠,不过引用的机制掩盖了初学者对于指针的迷茫,但是这对真正想做技术来说不一定是好事。

下面是C++的一个引用调用:

void f(int &parameter )

 {

     parameter =3;

 }

int  main()

{

   

   int a=0;

   f(a);

   printf("%d",a);

   ......     //代码略

}

 

最后打印出来的是3,而不是0,这就是C++引用调用的用处,在主函数定义的一个变量,如若我们需要在函数体内对它进行更改,我们就用引用调用,这样在函数体内对于parameter的操作我们就可以理解为是直接对主函数变量a的操作了。如果我们不采用引用调用的话,实际上的内存中的操作如下图所示:

当主函数的变量传入到调用函数中时,调用函数将会“拷贝”出一个a的副本来,这样我们直接在调用函数中的操作,实际上是对拷贝的一份操作,比如parameter=3  只是对另一个"a"进行操作,实际上在主函数的a根本没有任何改变,这也就是我们教科书上花很大篇幅教导我们那个Swap(int a,int b)不成功的原因。

但是在C中,我们没有调用引用的概念,不过借助于指针,我们完全可以模拟出引用调用的操作。那么在纯C中,我们只需要按照这个思路来写出

   

 a是主函数定义的一个变量,我们通过把它的地址传给函数体内定义的指针,使指针指向该地址,那么通过改变函数体指针的值,我们就可以改变主函数的值了。

void f(int *p)

{

    *p=3;

}

void main()

{

    int a=2;

    f(&a);

}

 

注意上面的f(&a),表示把地址传给函数体内的指针,那么指针就是指向了主函数的变量a所在内存,改变p实质就改变了a的值了,通过这种办法我们就解决C++的引用在C中实现的问题了。 

接着说指针用作引用参数传递的问题。为了解释这个问题,我们来看看这个例子。这个是我做数据结构时遇到的一个一直悬而未决的问题(呵呵):

问题开始前,我们先定义一个结构体:

typedef struct node{
    int data;
    struct node *Lchild,*Rchild;
}node;

 

很简单的一个结构体,学过数据结构的应该很快能看出这是个树的结点。我们的目的是在主函数定义一个node指针,初始值为空。然后我们再传到一个函数内分配空间:

int main()

{

     node *root=NULL;

     maketree(root);

...........

}

//函数

void maketree(node * &root)

{

     root=(node *)malloc(sizeof(node));

}

 

代码也很简单,主要意图是想在maketree中建立一棵树,通过C++的引用调用,我们就可以把root这个指针指向一棵按照要求建立的一棵树。不过这是借用的C++中的引用,如果我们要在纯C中实现该功能呢?要在主函数定义一个指针然后在其它函数中修改该指针的值,并且要保证修改后主函数指针也跟着改变。

int main()

{

     node *root=NULL;

     maketree(root);

...........

}

//函数

void maketree(node * root)

{

     root=(node *)malloc(sizeof(node));

}

注意函数maketree中参数的变化,我们去掉了"&"这个引用调用的符号。同样是通过指针调用,比对一下小议指针(一)中的程序,仅仅是在主函数中差了一个&,注意这里的'&'符号是一个取地址符号,跟上面的C++中的'&'完全不一样,但是这样最后我们在主函数得到的指针值是个非法的值,仍然不可访问!

回想一下函数调用的原理:

主函数传递指针给maketree函数,maketree函数拷贝了原指针。

接下来就明了了,看看这个:

函数体内拷贝root的指针p开始是NULL,但是现在不同啦,我们为他开辟了一个空间,但是root呢,仍然是为空。(我们根本没有动过root ! 操作都在这个貌似root的拷贝函数p上)

回忆下小议指针一中我们的思路:

注意上图p是指向root的一个指针,这样我们想对root进行操作,只需要对p动动刀即可,这样我们在函数体内的操作间接就是对root操作了。

 

int main()

{

     node *root=NULL;

     maketree(&root);

...........

}

//函数

void maketree(node * *root)

{

     *root=(node *)malloc(sizeof(node));

}

分析下上面的改动,

第一 主函数中的root改为&root,表示把root的地址传递给函数

第二 函数参数中root为为二级指针,因为主函数中root是一级指针,现在我们需要一个指向一级指针的指针,自然是二级指针了

第三 函数体内root改为*root,maketree中的root就是上图中的p,而我们如果要对root操作,自然要取p的指向,例如*p=a,如果我们要对a借助p操作,我们是写p,还是写*p呢?

原创粉丝点击