在函数的使用过程中,我们都明白传值和传引用会使实参的值发生改变。那么能够通过传指针改变指针所指向的地址吗?
在解决这个问题之前,也许我们应该先了解指针非常容易混淆的三个属性:
①.指针变量地址(&p)
②.指针变量指向的地址(p,存储数据的地址)
③.指针变量指向的地址的值(*p)
当我们将指针变量与其它变量比较之后就会发现,指针变量同其它变量是相似的,只是多了最后一种操作。比如一个int类型的变量,int x=5;&x取出存储5这个数据的地址,同样,&p也是存储指针的地址,p就是这个地址里面保存的值,也就是指向的地址。只是与其它变量不同的是,它除了这两种操作之外,还有一个解引用操作符(*p)去获取指针变量指向的地址里面保存的值。
一.指针引用
void make(int *pp)
{
pp=new int(66); //试图改变p指向的地址
}
int main()
{
int a=5;
int *p=&a; //指针变量指向一个int类型的地址
cout<<"address:"<<&a<<" value:"<<a<<endl;
cout<<"address:"<<p<<" value:"<<*p<<endl;
make(p);
cout<<"address:"<<p<<" value:"<<*p<<endl;
}
运行结果如下:我们这里虽然使用的是传指针,但是却不是直接改变指针变量指向的地址的值,却是想通过改变指针变量指向的地址来修改它的值,显然这样失败了。
如果我们希望在函数里面修改指针变量存储的地址而不是它的值,这个时候就需要指针引用了。类似于普通变量传入变量引用,我们也传入一个指针引用,在函数里面,你可以将pp认为和p都是这个指针变量(&p==&pp),不似传入指针参数的时候形参和实参的变量(&p!=&pp)地址不一样。此时我们操作pp的值就是更改了p的值。
void make(int *&pp)
{
pp=new int(66); //改变p指向的地址
}
运行结果如下:当我们修改传入参数为指针的引用的时候就可以修改指针变量所指向的地址了,可以看见,传入指针引用可以修改指针变量的值(p)和指向的值(*p)。
二.二级指针
指向指针的指针变量称为二级指针。
如果pp是一个二级指针,那么有如下属性:
①.二级指针的地址(&pp)
②.二级指针的地址保存的地址(pp)
③.二级指针的地址保存的地址,该地址里面保存的地址(*pp)
④.二级指针的地址保存的地址,该地址里面保存的地址里面的数据(**pp)
除了上面传入指针引用改变一级指针指向的地址以外,我们还可以通过传入一个二级指针去修改它对应的一级指针指向的地址,同样达到了修改指针变量的效果。二级指针的指向的地址存储的值就是一级指针指向的地址。对一级指针变量解引用得到的是指针指向的地址存储的数据,二级指针变量解引用得到的也是该二级指针指向的地址存储的地址值。
void make(int **pp)
{
int * p=new int(66);
*pp=p; //二级指针的解引用被赋值需要得到一个一级指针变量,上图中二级指针的示意图中*pp=p
}
int main()
{
int a=5;
int *q=&a;
int **pp=&q;
cout<<"address:"<<&pp<<" "<<pp<<" "<<&q<<" "<<q<<" value:"<<*q<<endl;
make(pp);
cout<<"address:"<<&pp<<" "<<pp<<" "<<&q<<" "<<q<<" value:"<<*q<<endl;
}
运行结果如下:通过对二级指针的解引用赋值成功修改了一级指针指向的地址。如果仅仅在make函数里面对**pp=66;操作,那么所有的地址不会改变,仅仅会改变值为66。