常量指针

本质是一个指针,常量作为修饰。不能用该指针修改指向的变量。

形式:int const* p const int* p

1.常量指针指向的对象不能通过这个指针来修改,但仍然可以通过原来的声明修改;
2.常量指针被赋值为变量的地址,之所以叫常量指针,是限制了通过这个指针修改变量的值;
3.指针还可以指向别处;

举例:

1
2
3
4
5
6
int a = 2,b = 3
const int *p = &a // 常量指针

*p = 9; // 错误!*p是const int的,不可修改
p = &b; // 成功!指针可以指向别处
a = 5; // 成功!可以通过原来的声明修改值

指针常量

本质是一个常量,用指针修饰。指针值(即指针的指向)不能改变。

形式:int* const p

1.它是一个常量。
2.指针本身指向的地址不可以变化,但是指向的地址所对应的内容可以变化;

举例:

1
2
3
4
5
6
int a = 2,b = 3
int * const p = &a //指针常量

*p = 9; // 成功!指针是常量,指向的地址不可变化,但指向地址上的值可以变化
p = &b; // 错误!不能改变指针指向的内容
a = 5; // 成功!可以通过原来的声明修改值

指向常量的指针常量

指向常量的指针常量就是一个常量,而且它指向的对象也是一个常量。指针不能改变指向,并且不能用该指针改变指向的实体的值。

形式:const int* const p

举例:

1
2
3
4
5
6
7
int a = 2,b = 3
const int * const p = &a //指针常量

*p = 9; // 错误!不可修改指向实体的值
p = &b; // 错误!不能改变指针指向的内容
a = 5; // 成功!可以通过原来的声明修改值
int c = *p; // 成功!

区分

关于区分,首先带两个const的肯定是指向常量的常指针。对于常量指针和指针常量:
一种方式可以看 * 和 const 的排列顺序,比如

1
2
3
int const* p; //const * 即常量指针
const int* p; //const * 即常量指针
int* const p; //* const 即指针常量

还一种方式是看const离谁近,即从右往左看,比如
1
2
3
int const* p; //const修饰的是*p,即*p的内容不可通过p改变,但p不是const,p可以修改,*p不可修改;
const int* p; //同上
int* const p; //const修饰的是p,p是指针,p指向的地址不能修改,p不能修改,但*p可以修改;

应用

在实际应用中,常量指针比指针常量用的要多,比如在函数传参中,可以用常量指针避免修改参数的内容。比如void fun(const char *a);在函数fun中就不能修改a指向的内容,避免发生不可预知的错误。

顺便一提,当一些比较大的数据作为参数时,函数传参也经常使用引用传参,这样可以节省复制的过程,提高效率。记得我在刚开始编写传递多个三维vector数据的函数时,就深刻体会到这个时间消耗的差距多么巨大。