C const 与指针
更新时间:2026-08-26。本文是
languages/c/主题入门层第 36 篇。const和指针凑一起,会有四种组合——它们管的是"两件不同的事":指针能不能改 vs 指向的值能不能改。看不懂声明时,用"从右往左读"大法。
本文要回答的问题
const int *p和int *const p有什么区别?- 怎么记住这四种组合?
- 函数参数里的
const char *是什么意思?
一、管的是两件事
指针有两个"自由度":
| 自由度 | 问题 | 例子 |
|---|---|---|
| 指针本身 | p 能不能指向别处? | p = &y; |
| 指向的值 | 能不能通过 p 改 *p? | *p = 5; |
const 放的位置决定管哪一个。
二、四种组合
c
int x = 10, y = 20;
const int *p1 = &x; // ① 指向 const int:*p1 不能改,p1 可以换指向
int const *p2 = &x; // ② 和 ① 完全一样
int *const p3 = &x; // ③ 指针本身 const:p3 不能换指向,*p3 能改
const int *const p4 = &x; // ④ 两个都 const:都不能改| 声明 | 能改 *p? | 能改 p? | 俗称 |
|---|---|---|---|
const int *p | 否 | 是 | 指向常量的指针 |
int *const p | 是 | 否 | 常量指针 |
const int *const p | 否 | 否 | 全 const |
int *p | 是 | 是 | 全裸 |
记忆法:看 const 和 * 谁在左谁在右——const 在 * 左边,修饰的是"指向的类型"(值不能改);const 在 * 右边,修饰的是"指针本身"。
三、从右往左读声明
c
const int *p; // p 是「指向 const int 的指针」→ 值是 const
int *const p; // p 是「const 指针,指向 int」→ 指针是 const从右往左读(先读 p,再往左)是通用方法,多级指针也能读:int *const *pp 读作"pp 是指向 const 指针的指针"。
四、函数参数里的 const:约定与保护
最常见的用途是函数参数——声明"我不会改你传进来的数据":
c
// 约定:只读 s,不改
size_t my_strlen(const char *s) {
size_t n = 0;
while (s[n]) n++;
return n;
}好处:
- 编译器把关:函数里不小心写
*s = 'x',编译直接报错; - 自文档:调用者一看
const char *就知道"传进去不会被改"; - 通用性:
const char*能接收字面量(字符串字面量是只读的),char*反而不行(类型转换警告)。
标准库就是范例:strlen(const char *s)、strcmp(const char *a, const char *b) 全是 const。
五、const 只保护"通过这个指针"
注意 const 的局限:
c
int x = 10;
const int *p = &x; // p 承诺不通过 p 改 x
x = 20; // 直接改 x,完全合法!const int *p 只是"通过 p 不能改",不代表 x 本身是常量。真正的"只读变量"是 const int x = 10;。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
const int *p 改 *p | 编译错误 | 用 int *const p(如果要改值) |
把 const char * 当 char * 传 | 编译警告/错误 | 保持 const 或复制 |
| 以为 const 指针保护了变量 | 直接改 x 成功(正常) | 理解保护边界 |
混用 int const * 与 const int * | 编译错(其实等价) | 统一用 const int * 写法 |
| 全 const 声明太乱 | 读不懂 | 从右往左读 |
七、与本站主线衔接
- const 在编译器的类型系统里怎么检查,见与汇编、性能剖析衔接;
- 正确使用 const 是工程代码规范的一部分,见多文件工程与代码规范;
- 字符串函数大量使用
const char *,见字符串函数。
一句话总结
const 在 * 左边=指向的值不能改(const int *p),在 * 右边=指针本身不能改(int *const p);函数参数写 const char * 是"只读约定",编译器替你把关——声明从右往左读,四种组合永不混淆。