所以,指针所指向的地址,有可能是变量B,也有可能是变量F,或者变量S,指针是房东,可以把房子租给B,C,或F,它可以动态为变量分配内存,也可以把变量销毁(delete),交不起房租就滚蛋(析构函数)。
从上面的故事中,我们看到指针的两个用途:索引内存和分配内存。
#include <stdio.h>void main(){ int* pint = new int(100); printf(" *pint的值:%d\n", *pint); printf(" pint的值:0x %x\n", pint); getchar();}
0x10f1968 , 0x10f1969, 0x10f196A, 0x10f196b
利用指针标识符 * 放在指针变量前即可获得指针所指地址中存储的实际值。
所以,int* p = new int(30)中,*p返回的值就是int的本值30,而p则只是返回30的首地址。
#include <stdio.h>void main(){ int* arrint = new int[3]; arrint[0] = 20; arrint[1] = 21; arrint[2] = 22; for(int i =0; i < 3; i++) { printf(" 数组[%d] = %d\n", i, arrint[i]); } delete [] arrint; // 清理内存 getchar();}
上例中,我创建了有三个元素的数组。在使用完成后,要使用delete来删除已分配的内存,所以,我们的第一个例子中,其实不完善,我们没有做内存清理。
为什么指针可以创建数组?前面我提到过,指针是指向首地址的,那么你想想,我们的数组如果在堆上分配了内存,它们是不是也按一定次序存放在一块连续的内存地址中,整个数组同样构成了一段内存块。
很多书和教程都把这个符号叫引用,但我不喜欢翻译为引用,因为引用不好理解,如果叫取地址符,那我估计你就会明白了,它就是返回一个变量的首地址。
#include <stdio.h>void main(){ int a = 50; int* p = &a; printf(" a的值:%d\n", a); printf(" p的值:0x_%x\n", p); getchar();}
那么,这样做有啥好处呢?我们把上面的例子再扩展一下,变成这样:
#include <stdio.h>void main(){ int a = 50; int* p = &a; printf(" a的值:%d\n", a); printf(" p的值:0x_%x\n", p); /* 改变指针所指向的地址块中的值,就等于改变了变量的值 */ *p = 250; printf(" a的新值:%d\n", a); getchar();}
我们定义了变量a,值为50,然后指针p指向了a的首地址,但注意,后面我只是改变了p所指向的那块内存中的值,我并没有修改a的值,但是,你看看最后a的值也变为了250,想一想,这是为什么?
上面介绍了指针可以存首地址,可以分配内存,可以创建数组,还说了取地址符&,那么,这些东西有什么用呢?你肯定会问,我直接声明一个变量也是要占用内存的,那我为什么要吃饱了没事干还要用指针来存放首地址呢?
好,我先不回答,我们再说说函数的参数传递。看看下面这样的例子。
#include <stdio.h>void fn(int x){ x += 100;}void main(){ int a = 20; fn(a); printf(" a : %d\n", a); getchar();}
我们希望,在调用函数fn后,变量a的值会加上100,现在我们运行一下,看看结果:
我们可能会很失望,为什么会这样?我明明是把20传进了fn函数的,为什么a的值还是不变呢?不用急,我们再把代码改一下:
#include <stdio.h>void fn(int x){ printf(" 参数的地址:0x_%d\n", &x); x += 100;}void main(){ int a = 20; fn(a); printf(" a : %d\n", a); printf(" a的地址:0x_%x\n", &a); getchar();}
那么,如何让函数调用后对变量a作修改,让它变成120呢?这里有两个方法:
#include <stdio.h>void fn(int* x){ *x += 100;}void main(){ int a = 20; fn(&a);//用取地址符来传递,因为指针是保存地址的 printf(" a : %d\n", a); getchar();}
#include <stdio.h>void fn(int& x){ x += 100;}void main(){ int a = 20; fn(a);//直接传变量名就行了 printf(" a : %d\n", a); getchar();}
不管是类还是结构(其实结构是一种特殊的类),它们在创建时还是要创建内存的,但是,创建类的对象也有两种方式,直接声明和用指针来分配新实例。
#include <iostream>using namespace std;class Test{public: Test(); ~Test(); void Do(char* c);};Test::Test(){ cout << "Test对象被创建。" << endl;}Test::~Test(){ cout << "Test对象被销毁。" << endl;}void Test::Do(char* c){ cout << "在" << c << "中调用了Do方法。" << endl;}void Func1(){ Test t; t.Do("Func1"); /* 当函数执行完了,t的生命周期结束,发生析构。 */}void Func2(){ Test* pt = new Test; pt -> Do("Func2"); /* 用指针创建的对象,就算指针变量的生命周期结束,但内存中的对象没有被销毁。 因此,析构函数没有被调用。 */}int main(){ Func1(); cout << "---------------------" << endl; Func2(); getchar(); return 0;}
我们来看看这个例子,首先定义了一个类Test,在类的构造函数中输出对象被创建的个息,在发生析构时输出对象被销毁。
接着, 我们分别在两个函数中创建Test类的对象,因为对象是在函数内部定义的,根据其生命周期原理,在函数返回时,对象会释放,在内存中的数据会被销毁。理论上是这样的,那么,程序实际运行后会如何呢?
那么,如何让第二个函数在返回时也销毁对象实例呢?还记得吗,我前文中提过。对,用delete.。
void Func2(){ Test* pt = new Test; pt -> Do("Func2"); delete pt;}
联系客服