C++ 中 typedef 指针别名与 const 的坑

最近在看《C++ Primer》,看到一个非常典型、但又特别容易搞错的知识点:typedef 定义的指针别名,遇上 const 之后到底在修饰谁?

示例代码大概是这样:

cpp 复制代码
typedef char *pstring;

const pstring cstr = 0;
const pstring *ps;

刚看到时,我下意识地想用"文本替换"的方式理解:把 pstring 换回 char *,结果很快就意识到自己想简单了。这篇笔记就记录一下我把这个问题理顺的过程。


1. 先看 typedef char *pstring;

cpp 复制代码
typedef char *pstring;

含义很简单:给类型 char * 起了个别名叫 pstring

关键点是:从这一行开始,pstring 在编译器眼里就是一个"完整的类型" ,就像 intdouble 一样。它的真实含义是"指向 char 的指针"。

这一点如果没立住,后面的误解基本都来自于这里。


2. 第一行:const pstring cstr = 0;

cpp 复制代码
const pstring cstr = 0;

2.1 常见错误:简单文本替换

很多人的第一反应是:

cpp 复制代码
const pstring cstr = 0;
// 替换 pstring -> char *
const char * cstr = 0;   // 看起来像这样

然后就得出结论:

cstr 是一个"指向常量字符的指针"(const char*)。

也就是说:指针本身可以改指向,但不能通过它修改字符内容。

这个结论是错的

2.2 正确理解:const 修饰的是整个别名类型

回到前面那句:pstring 本身是一个指针类型 ,已经等价于 char * 了。

当我写:

cpp 复制代码
const pstring cstr = 0;

时,const 修饰的是"pstring 这个类型本身",也就是"指向 char 的指针"这个整体。

换成标准写法应该是:

cpp 复制代码
char * const cstr = 0;

所以真正的含义是:

cstr 是一个"常量指针 ",指向 char

也就是:指针自己不能改指向,但可以通过它修改指向的字符内容。

2.3 性质总结

  • 这是一个 顶层 const:限制的是"对象本身"(这里是指针)不可修改。

  • 指向的 char 不是 const,可以修改:

    cpp 复制代码
    char ch = 'A';
    const pstring cstr = &ch;  // 相当于 char * const cstr = &ch;
    *cstr = 'B';               // OK,改的是 ch 的值
    // cstr = nullptr;         // ❌ 错误:不能改 cstr 这个指针本身

3. 第二行:const pstring *ps;

cpp 复制代码
const pstring *ps;

这行看着更抽象,我是按"从变量名往外读"的规则来拆的。

3.1 先看 ps 自己是什么

cpp 复制代码
const pstring *ps;
        //  ^  这里有个 *
  • *ps 说明:ps 自己是一个指针
  • ps 没有被 const 直接修饰,所以 ps 这个指针本身是可以变来变去的。

也就是说:ps 是一个"二级指针"的感觉。

3.2 ps 指向什么

ps 指向的对象类型是 const pstring

上一节刚分析过:

cpp 复制代码
const pstring  ≡  char * const

也就是说,被 ps 指向的那个东西,是一个"指向 char 的常量指针"。

所以把整句还原成标准写法,就是:

cpp 复制代码
char * const *ps;

3.3 用一句话总结

ps 是一个指针 ,它指向一个"指向 char 的常量指针"。

稍微具体一点:

  • ps 本身可以改指向别处;
  • *ps(也就是那个 char * const)本身不能改指向;
  • 但通过 *ps 仍然可以修改底层 char 的内容。

示意代码:

cpp 复制代码
char ch = 'A';
char *const cstr = &ch;  // 常量指针
const pstring *ps = &cstr; // 等价写法:char * const *ps = &cstr;

*(*ps) = 'B';  // OK:改的是 ch
// *ps = some_other_ptr; // ❌:*ps 是 char *const,不能改指向
ps = nullptr;  // OK:ps 自己是普通指针,可以改

4. 核心结论:typedef 不是宏替换!

整个问题的根源就在这句:

typedef 不是简单的文本替换。

  • 它定义的是一个完整的"类型别名";
  • 在之上的 const,是修饰这个"别名所代表的类型";
  • 对于像 pstring 这种"本身就是指针类型"的别名而言,
    const pstring 自然就变成了"常量指针",而不是"指向常量的指针"。

可以对比下面几种写法,体会差异:

cpp 复制代码
typedef char *pstring;

const pstring  a = 0;   // char * const a;       常量指针(顶层 const)
pstring const  b = 0;   // char * const b;       同上,只是写法不同

const char    *c = 0;   // 指向 const char 的指针(底层 const)
char const    *d = 0;   // 同上
char * const   e = 0;   // 常量指针,指向非 const char

简要对比:

写法 等价形式 说明
const pstring char * const 常量指针,指针不可改
const char * char const * 指向常量的指针,内容不可改
char * const 常量指针,内容可改

相关推荐
urkay-1 小时前
Android getDrawingCache 过时废弃
android·java·开发语言·kotlin·iphone·androidx
小oo呆1 小时前
【学习心得】Python好库推荐——pipx
linux·开发语言·python
CoderYanger1 小时前
C.滑动窗口-求子数组个数-越短越合法——3258. 统计满足 K 约束的子字符串数量 I
java·开发语言·算法·leetcode·1024程序员节
幽络源小助理1 小时前
《已调试》SpringBoot景区寄存管理系统源码 - 免费JavaWeb项目下载 | 幽络源
java·开发语言·spring boot
豆沙沙包?1 小时前
2025年--Lc302-415. 字符串相加--java版
java·开发语言
JIngJaneIL1 小时前
基于Java民宿管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
azoo1 小时前
cv::Mat 取元素引起的报错
c++·opencv·计算机视觉
杰克尼1 小时前
蓝桥云课-13. 定时任务
java·开发语言·算法
m0_726965981 小时前
RAG小实战
开发语言·python