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 常量指针,内容可改

相关推荐
炸膛坦客3 小时前
单片机/C/C++八股:(二十六)IIC 专题(I²C)---- 上集
c语言·c++·单片机
旖-旎3 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
灯澜忆梦3 小时前
GO_并发编程---定时器
开发语言·后端·golang
-银雾鸢尾-4 小时前
C#中的StringBuilder相关方法
开发语言·c#
Henry Zhu1234 小时前
C++中的特殊成员函数与智能指针
c++
-银雾鸢尾-4 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
大模型码小白5 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
_wyt0016 小时前
多重背包问题详解
c++·背包dp
段一凡-华北理工大学7 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe7 小时前
C++——多态
开发语言·c++