在C++编程中,const修饰指针是常见的语法特性,不同的修饰位置会直接决定指针本身和指针指向内容的可修改性,很多开发者容易混淆const指针、指针const、常量指针、指针常量的概念和使用规则。

核心概念定义
首先需要明确两个核心概念的定义,避免后续理解出现偏差:
- 常量指针:本质是常量,但是是指针类型的常量,即指针本身的值(指向的地址)不可修改,但指向地址中的内容可以修改。
- 指针常量:本质是指针,但是指向的内容是常量,即指针指向的地址可以修改,但指向地址中的内容不可修改。
而const指针和指针const是两种修饰写法的通俗叫法,对应上述的两种概念,具体关系如下:
| 写法类型 | 对应概念 | 可修改性说明 |
|---|---|---|
int * const p | 常量指针(const修饰p) | p的指向不可改,*p的值可改 |
const int * p 或 int const * p | 指针常量(const修饰* p) | p的指向可改,*p的值不可改 |
const int * const p | 同时修饰指针和指向内容 | p的指向不可改,*p的值也不可改 |
不同写法的代码示例
1. 常量指针(int * const p)
这种写法中const直接修饰指针变量p,意味着p存储的地址值固定,不能再指向其他变量,但可以通过p修改指向地址中的内容。
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 常量指针,const修饰p,p的指向不可修改
int * const p = &a;
// 可以修改指向地址的内容
*p = 15;
cout << "a的值:" << a << endl; // 输出15
// 以下代码会编译报错,常量指针不能修改指向
// p = &b;
return 0;
}
2. 指针常量(const int * p / int const * p)
这种写法中const修饰的是指针指向的内容* p,意味着指向地址中的内容不可修改,但指针p本身可以指向其他变量。
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 指针常量,const修饰*p,指向的内容不可修改
const int * p = &a;
// 可以修改p的指向
p = &b;
cout << "p指向的值:" << *p << endl; // 输出20
// 以下代码会编译报错,指针常量不能修改指向的内容
// *p = 25;
return 0;
}
3. 同时修饰指针和指向内容(const int * const p)
这种写法中const同时修饰p和* p,意味着指针的指向和指向的内容都不可修改。
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
// 同时修饰指针和指向内容,两者都不可修改
const int * const p = &a;
// 以下两行代码都会编译报错
// *p = 15;
// p = &b;
return 0;
}
快速记忆方法
可以按照从左到右的阅读顺序判断const修饰的对象:
- 如果const后面紧跟的是指针变量名(如
int * const p),则const修饰的是指针本身,对应常量指针。 - 如果const后面紧跟的是类型或者*(如
const int * p、int const * p),则const修饰的是指针指向的内容,对应指针常量。
另外也可以通过英文读法辅助记忆:int * const p读作pointer const to int,即指向int的常量指针;const int * p读作pointer to const int,即指向常量int的指针,也就是指针常量。
常见使用场景
常量指针通常用于需要固定指向某个变量,且需要修改该变量内容的场景,比如函数参数中需要接收一个变量的地址并修改其内容,同时不希望指针意外指向其他地址。
指针常量通常用于只需要读取某个变量的内容,不需要修改,但是可能需要切换读取不同变量的场景,比如函数参数中只需要读取传入地址的内容,不希望修改原数据,同时允许传入不同变量的地址。
注意:如果函数的参数需要接收字符串字面量等常量数据,建议使用指针常量写法,避免误修改常量内容导致未定义行为。