4 指针和引用
4.1 指针的定义与使用
4.1.1 声明一个指针变量
指针是一种数据类型,基于该类型声明的变量称为指针变量,和普通的变量一样,在使用指针变量之前应先对指针变量进行声明。
/*类型 *指针变量名,*(指针运算符)表明语句声明的是一个指针变量,
类型指定了指针所指向的内存单元的数据类型,
该指针对于其他数据类型的内存无法访问。*/
int* pNum;
4.1.2 初始化指针变量
在对指针变量使用**间接引用符(*)**前,一定对其进行初始化,在声明的同时初始化或赋值,使其有一个确定的值,对于无处可指的指针变量也要将其初始化为NULL即0.
4.1.3 指向指针的指针
指针变量也有地址,因此可用一个指针指向其地址,这称为指向指针的指针或二级指针。
int Num;
int *pN=&Num;
int **ppN=&pN;
4.3 动态内存分配
在程序运行时申请一块未命名的内存用来储存变量或者更加复杂的数据结构,并把该内存的首地址记录下来。
string 和vector已经足够方便,不要给自己挖坑[^1]
4.3.1 使用new 动态内存分配
类型名 *指针变量名=new 类型名;
int *pNum=new int;/*返回指向int类型的指针pNum,并用动态申请内存的首地址为pNum同时将其进行初始化,因此,用指针pNum可访问这块内存区域*/
int *p2=new int(0);//初始化为0
4.3.2 使用delete动态释放及动态申请的内存、
动态申请的内存必须由程序员释放。
delete指令会释放动态申请的内存块,但不会删除指针本身,还可以将指针重新指向另一块内存区域。
delete 语句不能释放声明变量获得的内存。
与声明获得的数组不同,使用new动态申请数组的元素个数可变。
int i=5;
int *p1=new int[i];
4.3.6 动态申请并不一定成功
char *pC=new char[10];
if(pC!=null)
//执行操作
else
//内存申请失败处理
通常在内存释放后,将指针赋值为null,这样就不会再次释放已经释放的内存。
4.4 指针和const
4.4.1 常量指针或指针常量
在*的右边添加const修饰符,所声明的指针称为指针常量,即该指针为常量。
int x=0;
int * const pX=&x;//pX的值无法改变,但可通过间接引用改写pX指向的变量。
声明指针常量时必须对其进行初始化,因为指针常量在声明完毕无法进行修改,因此,未初始化的指针常量是没有意义的。
4.4.2 常量指针
将const 放在指针类型之前,使无法通过间接引用改写指针所指向的变量。
int x=5;
const int *pX=&x;
禁止间接引用改写不代表内存变量无法改写,通过变量名访问和改写内存是合法的。
4.4.3 常量指针常量
int x=5;
const int* const pX=&x;
4.5 指针与数组
4.5.1 数组名指针
a[i]==*(a+i);
4.5.3 指向数组的指针
如果数组是多维数组,有两种指针声明方式,即普通指针和数组名方式。
- 普通指针方式
int sz[2][3][4];
int *pz=sz[0][0];
//sz的遍历过程,多维数组一维化,对pz指针运算单位为int
for(int i=0;i<2;i++)
for(int j=0;j<3;j++)
for(int k=0;k<4;k++)
cout<<*(pz+3*4*i+4*j+k);
- 数组名方式
int sz[2][3][4];
int (*pz)[3][4]=sz;//采用数组名方式声明指针pz,对pz指针运算单位是[3][4]的二维整型数组;
for(int i=0;i<2;i++)
for(int j=0;j<3;j++)
for(int k=0;k<4;k++)
{
cout<<*(*(*(pz+i)+j)+k);
cout<<pz[i][j][k];
}
4.5.4 指针数组
"abcd"是常量字符串的地址
char *c="abcd";//"abcd"是常量字符串的地址
cout<<c;//完成的是字符串的整体输出
cout<<*c;//仅仅输出指针所指位置的一个字符
int *sz[4];//
int (*sz)[4];//定义一个指向数组的指针sz,其指向的数组为大小为4的一维int数组
4.6 引用
对引用的操作与变量直接操作完全一样
4.6.1 引用的声明
声明语句中的初始值必须是一个变量或另一个引用。一经声明,不能修改。
类型标识符 &引用名=初始值;//&不是取地址符,而是“引用说明符”
4.6.3 引用的使用限制
- 不能建立数组的引用
- 声明引用的引用是非法的
int &&refNum=num;
指向引用的指针×
int & *refPum=Num;
指向指针的引用√
int * &refPum=pNum;//pNum是一个int的指针,指针的引用合法
4.6.4 其他(关于指针和引用)
int &refNum=*new int;//对用new 申请的动态无名实体建立一个引用
delete &refNum;//
两种情况下,必须用const修饰引用
const int & refInt=9;//去掉const非法
int x;
const double &refDouble=x;//去掉const非法
- 对非左值的引用,如常数
- 类型声明符与初值类型不一致,但可转换。
const 修饰的引用是只读的无法改写,更有价值的是函数值的传递引用及调用。
用的好处就是调用函数的时候,不用填写取地址符&,子函数中也不写取变量符*,结构体和类不用->取成员。传递地址的方式,因为更直观,不管是在函数内部还是函数被调用的地方,一眼就能清楚是否是地址。