指针是一个变量,其存储的是值的地址而不是值本身即地址是指定量,而值是派生量,求指针ptr处存储的值,用*ptr获得;
常规变量,值时指定量,而地址是派生量,常规变量MEM的地址用&MEM求得,一般用十六进制表示。
1、指针的声明和初始化
指针声明时必须声明指针指向的数据的类型。注意,指针创建之后,计算机为其分配了用来存储地址的内存,但不分配用来存储指针所指向的数据的内存。所以应先初始化,确定其指向的内存位置,再进行赋值。
声明:int* ptr;//注意,*左右两侧的空格无关紧要。
int* ptr1,ptr2;//此句定义了一个指针变量,一个int变量,要定义两个指针,则两个指针变量前都要加*。
初始化:int height = 5;
int * ptr = &height;//此句将&height赋值给ptr而不是*ptr。
在C语言中,可进行如下赋值:
int *pt;
pt = 0x8000;
但在C++中,对类型一致性要求更严格,要将数字作为地址来使用需要进行强制类型转换将数字转换为合适的地址类型,如下:
int *pt;
pt = (int *)0x8000;
这样,两边都是整数的地址,有效。注意,pt是int值的地址,但是并不意味着pt是int类型。
2、使用new来分配内存
指针的价值在于在运行阶段分配未命名的内存空间以存储值。在C语言中,只能通过malloc()函数来分配内存,在C++
还有另一种方式——new运算符。
new作为一种运算符,只需告诉它需要为哪种类型的数据分配内存地址,new可以找到一个正确的长度,并返回内存地址。
int *pn = new int;
注意:new分配的内存块通常和常规变量声明分配的内存块不同。变量和指针都被存储在被称为栈(stack)的内存区域,而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存。
3、使用delete释放内存
int *ps = new int;
...
delete ps;
delete将释放ps指向的内存,但不是删除指针ps本身。只能用delete释放使用new分配的内存,不能释放常规变量释放的内存,所以new和delete一定要配对使用,且对同一内存不能多次释放
。delete用于释放new分配的内存,并不是说一定要用new的指针,如下亦可:
int* ptr = new int;
int* ptr2 = ptr;
delete ptr2;
另外,对空指针使用delete是安全的。
4、使用new创建动态数组并对其进行访问
动态数组:在程序运行时创建数组并选择数组的长度,即为动态联编,对应的数组成为动态数组。
创建与释放格式:
int* person = new int [10];//new返回第一个元素的地址
delete [] person;//方括号意味着删除数组而不仅仅指目前指针指向的元素。
访问动态数组:
使用指针对动态数组的访问就像数组一样,将指针当做数组名,person[0]即第一个元素,person[1]即表示第二个元素,以此类推。但是需要注意,指针是变量,可以进行运算,当执行过person = person+1;之后,person[0]将为数组中的第二个元素。这里,将指针变量加1之后,相当于增加其指向类型的字节数。而数组名是常量,不能进行修改,虽然数组名在C++中表示第一个元素的地址,也可以用*(arrayName+i)表示arrayName[i]。另外,sizeof用于数组名时得到整个数组的长度,而用于指针名时得到指针的长度。
数组名一般解释为第一个元素的地址,但是,可对数组名进行取地址运算,得到的是整个数组的地址。
short tell[10];
cout<<tell<<endl;
cout<<&tell<<endl;
从数字上看,两地址相同,但,tell是一个2个字节内存块的地址,而&tell是一个20个字节内存块的地址。tell+1将地址值加2,&tell+1将地址值加20.即tell是一个short类型的指针,而&tell是一个指向包含10个元素的short数组。等价于:
short (*pas)[10] = &tell;
所以,*pas[0]即为tell[0]。
代码运行参考:指针部分源码
运行结果:
5、指针和字符串
在C++中,用双引号括起来的字符串像数组名一样,也是第一个元素的地址。对char类型数组名或char类型指针,cout+数组名或指针,输出的是整个字符串。要想输出整个地址,需要进行强制类型转换,(int*)+数组名或指针名。这是字符串类型的数组或指针与其他类型不同的地方。
6、使用new创建动态结构
例如:
struct things
{
int good;
int bad;
};
声明:things *ps = new things;
或:
things egg = {3,2};
things *ps = &egg;
访问方式:
结构名访问:egg.good, egg.bad;(结构名用句点)
指向结构的指针访问:ps->good, ps->bad;(指针用箭头)
或:(*ps).good, (*ps).bad。
结构和类相似,这些方法也使用与类。
附:
(1)通常的指针或数组名为指向数组第一个元素的指针,如
int mem[3] = {3,2,1};
int* ps = mem;
(2)数组名取地址为指向数组整体的指针,如
int (*ps)[3] = &mem;
(3)还有指针数组,如
int mem1 =3;
int mem2 =2;
int mem3 =1;
int * ps[3] = {&mem1,&mem2,&mem3};//这里mem1~3位变量名,不是数组名,取地址需要&
其中,ps[1]就是一个指针。
(4)也可定义指向指针数组的指针,如
const int ** ppa = ps;
ppa就是一个指向指针数组的指针,*ppa就是&mem1。