根据修饰指针变量的const关键字位置不同,分为指向常量的指针和常量指针
指向常量的指针
指向常量的指针,顾名思义,它是个指针,只不过是指向常量的
使用方式: const int num = 20; //定义一个常量
const int * ptr = # //定义指向常量的指针ptr
int * npr1 = # //错误:普通指针不能指向常量
一般情况下,指针类型必须与其指向的对象类型一样,但是存在一个例外,即指向常量的指针可以指向非常量的对象
例: int i = 5;
const int *r = &i; //正确,r可以指向非常量对象
不允许通过指向常量的指针改变其指向对象的值,但是不影响该值自己做修改,例:
int num = 0;
const int *ptr = #
*ptr = 5; //错误:不能通过指向常量的指针改变其指向的对象的值
num = 5; //正确:ptr不影响num自己做修改
常量指针
常量指针,即指针本身是个常量,在定义的时候必须初始化,初始化后,他的值(存放在指针的地址)就不能改变了
使用方式: int num = 5;
int * const ptr = # //定义常量指针
常量指针本身的值不能修改,即常量指针一旦初始化,就不能再指向别的对象,但是其指向的对象的值是可以改变的
例: int i = 0;
int a = 2;
int * const r = &i;
r = &a; // 错误:指针常量初始化后不能指向新的对象(本身存储的地址不能改)
*r = 6; //正确:可以通过常量指针改变其指向对象的值
区分指向常量的指针和常量指针比较容易的方式:
看指针的定义的时候,从右往左读,看离指针最近的那个修饰符号是谁
int * const ptr; 离ptr最近的是const,说明ptr本身是个常量对象,即ptr本身的值不能修改
const int * ptr; 离ptr最近的是 *,说明const控制的不是ptr本身,而是其指向的对象,即指向的对象不能通过该
指针修改值
const和constexpr
const和constexpr都是修饰常量的,但是由上面的例子可以看出,const修饰的指针,其指向的对象不一定是常量
如: int num = 10;
int * const ptr = #
这里const虽然保证了ptr本身的值不可变,但是初始值num是可以改变的,有时候要保证一个变量的初始值是常量表达式,
要用constexpr来修饰,编译器会根据constexpr关键字来验证变量的初始值是否为常量表达式
需要注意的是,如果constexpr声明的是一个指针,那么constexpr仅对该指针有效,例如:
const int * p = #
constexpr int * q = #
其中p是指向常量的指针,而q则是常量指针,即q本身存储的地址不能变