『摘要』本文主要通过实例展示C/C++中二重指针的用法和用途,对于诸如二叉树等递归定义的数据结构有一定的指导作用 。
【关键字】:C/C++、二重指针、递归
本人最近想实现一个B+树,虽然对B+树的理论有一定的认识,但由于考研花去大量时间复习功课,对C的一些细节有所遗忘,因此决定从二叉树的实现开始。但刚写完二叉树的创建函数且在编译通过之后,调试时却出现了问题。二叉树是一种递归定义的数据结构,因此其创建函数也必定是递归的。其创建函数描述如下:
图1 二叉树创建函数
理论上没有错误,同时在创建二叉树时也能成功,但通过本人编写的先序遍历该二叉树时,却显示0,即空的二叉树,相关操作代码如下:
//具体的操作步骤
TREE tree = 0; //TREE为二叉树结构体的指针型别
createBinaryTree(tree);
//先序遍历
由于结果错误,因此开始调试,通过观察发现当createVinartTree(tree)操作完成后tree的属性仍然为0,即仍然tree=0。后来又通过仔细分析,发现问题出在函数的参数上。虽然该函数传入的是指针型别,属于实参,但是该函数内部主要以原指针作为操作对象,因此相对于指针来说,传入的只是结构体指针的形参。所以,在函数内部操作的只是一个副本,因此二叉树的创建失败。
为了解决这个问题,笔者决定验证自己的想法是否正确,于是写了如下一段测试代码,代码如下:
//版本1
typedef struct student {
char* name;
int age;
}Student,*STUDENT;
void getInstance(STUDENT s);
int main(){
Student* st = 0;
printf("指针st的地址=%d\n",&st);
getInstance(st);
printf("st新实例的地址=%d\n",st);
return 1;
}
void getInstance(STUDENT s){
printf("指针S的地址 =%d\n",&s);
s = (Student*)malloc(sizeof(student));
printf("s新实例的地址=%d\n",s);
}
这个函数的传值形式与之前二叉树的函数差不多,因此可以类比,具体运行之后得到的记过是(如图):
图2 版本1的运行结果
结果很显然,指针传入函数之后产生了一个新的副本,对副本的任何操作,都不会影响到原指针指向的结构体,与二叉树创建失败类似,目的指针的副本指向了目标结构体,产生了内存泄漏。
这个问题的解决也十分的简单,将结构体的指针作为实参传入函数即可,这样就可以直接操作目标指针,也就不会出现错误的结果。运用二重指针可以轻松实现,具体修改如下:
//版本2
typedef struct student {
char* name;
int age;
}Student,**STUDENT;
void getInstance(STUDENT s);
int main(){
Student* st = 0;
printf("指针st的地址=%d\n",&st);
getInstance(&st);
printf("st新实例的地址=%d\n",st);
return 1;
}
void getInstance(STUDENT s){
printf("指针S的地址 =%d\n",s);
*s = (Student*)malloc(sizeof(student));
printf("s新实例的地址=%d\n",*s);
}
修改部分如黑体部分所示,具体的运行结果如下图:
图3 版本2的运行结果
测试成功,函数内部操作的指针就是实际传入的指针,即通过二重指针实现了目标操作指针的实参传递,因此能达到预想的结果。这也说明了二重指针的实际用处。