const int p指针可变、内容不可变;int const p指针不可变、内容可变;二者叠加为const int* const p则指针和内容均不可变。

const int* p 和 int* const p 的区别到底在哪
关键看 const 修饰谁:左边是“指向的内容不可变”,右边是“指针本身不可变”。很多初学者把二者都叫成“常量指针”,结果改值时报错却找不到原因。
常见错误现象:const int* p = &x; *p = 10; 编译失败,提示 assignment of read-only location '* p';而 int* const p = &x; p = &y; 同样报错,提示 assignment of read-only variable 'p'。
-
const int* p(等价于int const* p):指针可改,所指内容不可改 → 适合只读访问场景,比如函数参数传入不希望被修改的数组 -
int* const p:指针不可改,所指内容可改 → 适合绑定固定地址后反复操作,比如硬件寄存器映射、初始化后不再重定向的缓冲区 - 两者可以叠加:
const int* const p,指针和内容都不可变,相当于“完全只读引用”
函数参数中用 const int* 是为了安全,不是为了性能
很多人以为加 const 是为了让编译器优化,其实主要作用是契约声明:告诉调用方“我不会改你的数据”,也防止自己手滑写 *p = ...。编译器是否优化,跟这个没关系。
使用场景举例:遍历只读数组、传递配置结构体地址、封装 C 风格 API(如 strlen(const char*))。
立即学习“C++免费学习笔记(深入)”;
- 如果函数内部确实需要修改所指内容,就别加
const—— 强行加会导致编译不过,或用const_cast拆掉,这是危险信号 - 如果传入的是字面量或临时对象(如
func(&42)),必须用const int*,否则 GCC/Clang 直接拒绝 - 注意:C++11 起,
int x = 5; func(&x);传给void func(const int*)完全合法,但传给void func(int*)就会警告“discarding qualifiers”
int* const p 初始化后就不能再赋值,连 nullptr 都不行
因为 const 修饰的是指针变量本身,它必须在定义时初始化,之后任何对 p 的赋值(包括 p = nullptr)都会触发编译错误。
典型误用:int* const p; p = &x; —— 这是非法的,p 是未初始化的 const 变量。
- 正确写法只有:
int x = 10; int* const p = &x;(定义即初始化) - 不能用于函数局部变量做“运行时绑定”,比如想先声明、后根据条件赋值,得换思路(改用普通指针 + 逻辑约束,或用
std::optional<int></int>) - 类成员中用
int* const ptr_是可行的,但必须在构造函数初始化列表里赋值,不能在构造函数体内
const int* const p 在嵌入式和接口设计中最容易被忽略
这个双重 const 经常被当成“多此一举”,但它在头文件暴露接口、跨模块协作、内存映射场景下特别关键——既防调用方乱改数据,也防实现方意外重定向指针。
比如定义一个只读配置表:extern const ConfigEntry* const config_table;,使用者知道:表地址固定、表内容不可写。
- 若只写
const ConfigEntry* config_table,别人可能偷偷执行config_table = new_table;,导致全局行为异常 - 若只写
ConfigEntry* const config_table,别人仍可能改表内字段,破坏配置一致性 - 注意:这种变量必须定义在 .cpp 文件里并初始化,头文件中只能用
extern声明,否则多个翻译单元链接时报 duplicate symbol


















