本文为znd8866原创,转载请注明出处。
由于本人功力有限,有错误之处恳请指正,谢谢。
(1)这样写为什么会错?
看下面一段程序:
void Fun1 (MyClass *ptr)
{
ptr=(MyClass*)malloc(MyClass);//或者用new来分配:ptr=new MyClass()
}
MyClass *p=new MyClass();
Fun1(p);
会发生什么情况呢?
首先编译器会分配一个MyClass空间,并在栈上创建指针p,它指向创建的MyClass空间:
然后调用Fun1函数,Fun1函数会创建一个新的MyClass类型的指针ptr,它的值既是p的值,它也指向创建的MyClass对象:
然后Fun1函数调用malloc函数,它向系统申请一个新的MyClass空间,将新的MyClass空间的首地址赋给ptr:
相信读者现在已经看出来了,是的,他最终变成了下面的形式:
也就是说,调用函数Fun1后,指针p的值并没有改变,它与调用前没有任何区别。但我们的意图是让Fun1分配新的存储空间给指针p,这显然达不到我们的期望,那么应当怎么做呢?
在不改变函数Fun1返回值的情况下,有两种方法:
(1) 使用指针的指针
(2) 使用指针的引用
(2)指针的指针
看下面的程序:
void Fun1 (MyClass **ptr)
{
*ptr=(MyClass*)malloc(MyClass);
}
MyClass *p=new MyClass();
Fun1(&p);
会发生什么情况呢?
首先,编译器会分配一个MyClass空间,并在栈上创建指针p,它指向创建的MyClass空间:
图中0x00EEBBDD是p指针在栈上的地址。
然后调用Fun1函数。首先,函数Fun1会创建一个指针的指针ptr,它指向的指针指向MyClass类型,它的值即p指针的地址0x00EEBBDD,如下图:
然后,Fun1调用malloc函数,它向系统申请一个新的MyClass内存空间,将这个新的空间的首地址赋给*ptr,注意是*ptr而不是ptr,*ptr就是p的值,即p的值被改变:
从图中可以看出,p的值被改变,他指向了新的空间,达到了我们的期望,但要注意这样会发生内存泄露,即原来分配的0x00FF44DD内存没有释放,这可以在分配内存前先释放原内存来解决,或者使用下面讲的引用。
(3)引用
记住一点:凡是对变量的引用的改变都是对变量本身的直接改变。
这里我们不讨论引用是否占用内存空间(许多书上都说引用不占内存空间,但如果你仔细观察反汇编代码的话,其实引用是占内存空间的),也不讨论编译器对引用的处理(其实编译器是把引用翻译为指针常量的,指针的值不可以改变,但指针指向的变量的值可变),我们仅讨论引用的特性及应用。
引用相当于变量的别名,改变引用就相当于改变变量本身,引用在使用上是和变量等价的。
例如:
void fun (int &a,int &b)
{
inttemp=a;
a=b;
b=temp;
}
int i=3,j=4;
fun (i,j);
会发生什么呢?
在调用fun函数时,首先fun函数会为变量i、j分别创建引用a、b,如下:
从这里就可以看出,如果改变a、b的值,就可以直接改变i、j的值。
(4)指针的引用
到此问题就变得很简单了,在使用指针的引用时,就相当于使用指针本身。
看下列代码:
void Fun1 (MyClass *&ptr)
{
ptr=(MyClass*)malloc(MyClass);//或者ptr=new MyClass();
}
MyClass *p=new MyClass();
Fun1(p);
会发生什么呢?
首先,编译器会分配一个MyClass空间,并在栈上创建指针p,它指向创建的MyClass空间:
然后调用Fun1函数,Fun1函数会创建一个指针p的引用ptr,如下所示:
相信读者已经看出来了,ptr的值就是p的值,改变ptr的值就是对p的值的直接改变。
至此对指针与引用的讨论结束。