C++中的“指针”
0赞指针是用来保存内存地址的变量。每个被定义的变量都有自己的地址,可以用指针来存放任何被定义的变量的地址。如(p存放的是变量的地址,*p存放的是变量的数据。):
int a; // 定义一个整型变量a int *p; // 定义一个指向整型变量的指针p p = &a; // 将变量a的地址赋给变量p
定义一个指针后一定要用它保存一个内存地址,如果不那么做的话,那么该指针就是一个失控指针,它可以指向任何地址,并且对该地址的数值进行修改或者删除,可能会造成意想不到的后果。所以,可以将指针初始化为0,如:
int *p; p = 0;或者int *p = 0;
由于不同类型的变量在内存中所占用的字节不同,而指针又是用来保存内存地址的变量,因此指针只能存储与它类型相同的变量的地址。
注意区分指针地址、指针保存的地址和该地址的值,如:
int a = 1; int *p = &a; cout << "指针地址:" << &p << endl; cout << "指针保存的地址:" << p << endl; cout << "指针保存地址的数值:" << *p << endl;
为什么使用指针?因为在操作大型数据和类时,指针可以通过内存地址直接访问数据,可避免在程序中复制大量的代码,因此指针的效率最高。一般来说,指针会有3大用途:
(1)处理堆中存放的大型数据;
(2)快速访问类的成员数据和函数;
(3)以别名的方式向函数传递参数。
如何使用堆?首先创建一个堆,然后定义一个指向该堆的指针,最后通过该指针就可以访问堆中的数据。在C++中使用关键字new创建一个堆并分配内存,在new后面跟一个要分配的对象类型,编译器根据这个类型来分配内存。如:
int *p;p=new int; 或int *p=new int; // 分配了四个字节的内存空间
由于使用new创建的内存空间不会被系统自动释放,因此假如不去释放它,那么该区域的内存将始终不能为其他数据所使用,而指向该内存的指针是个局部变量,当定义该指针的函数结束并返回时,指针也就消失了,从而再也找不到这块内存区域,这种情况叫做内存泄漏。因此,当不需要一块内存空间,可以使用关键字delete释放该内存空间(不要再次对该指针进行删除,因为它所指向的内存区域已经被释放,如果再进行释放,将会使程序崩溃。但是,如果将该指针赋为0的话,那么删除一个指针是安全的。),但不会释放该指针,指针可以继续使用。另外,当用delete释放一个指针所指向的空间后,最好将该指针的内存地址清0。如:
int *p=new int; delete p; p=0;
还可以在堆中创建对象(创建对象时会自动调用类的构造函数来初始化对象的成员数据),如下,定义了一个Human类的指针p,指向new创建的内存空间。占用内存大小由Human类对象的成员变量来决定。
Human *p;p=new Human; 或Human *p=new Human;
如果要删除在堆中创建的对象,可以直接删除指向该对象的指针,这样会自动调用对象的析构函数来销毁该对象,同时释放内存。
可以通过指针变量访问堆中创建的对象,如下,其中->是成员指针运算符,利用该符号可以实现读取对象的内存地址并且访问该对象的成员的作用。
(*p).get();或p->get();
指针可以进行加减操作,如下,定义了一个指针并指向int型变量,执行加1操作,会将原来的内存地址增加4个字节;执行减1操作,会将原来的内存地址减少4个字节。
int *p=new int; p++; p--;
常量指针是指该指针不可改变,但其指向的数据可改变,如下:
int *const p;
指向常量的指针是指该指针可改变,但其指向的数据不可改变,如下:
const int *p;
指向常量的常指针是指该指针不可变,其指向的数据也不可变,如下:
const int * const p;