const int*, int * const, const int * const: 血腥指针解析

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么这个话题甚至让经验丰富的 C++ 开发者抓狂?

\n\n

如果你曾经打开过别人的 C++ 代码,看到类似 const int * const data 的东西,你肯定有过关闭编辑器去喝茶的冲动。这种奇怪的语法,const 散落在星号两侧,真是一块绊脚石。问题 “const int*、const int * const 和 int * const 之间有什么区别?” 在 Stack Overflow 上获得了数十万次浏览。这并非偶然。

\n\n

理解这些结构不仅仅是学究的任性。这是编写安全、自文档化代码的关键,更重要的是,通过面试的关键。今天,我们将一劳永逸地解决这个困惑,使用一个始终有效的简单规则。

\n\n

三大支柱:我们要比较什么?

\n\n

在 C++ 中,指针和常量性可以有四种组合方式(其中三种是最常见的)。让我们来定义它们:

\n\n
    \n
  • 变体 1: const int* ptr(或 int const* ptr——这是相同的)。
  • \n
  • 变体 2: int * const ptr。
  • \n
  • 变体 3: const int * const ptr(前两者的组合)。
  • \n
\n\n

关键思想:const 总是修饰它左边的内容。如果左边没有内容,则修饰它右边的内容。听起来很简单,但在实践中,这条规则非常有用。

\n\n

变体 1:const int* ptr(指向常量整数的指针)

\n\n

从右向左读:“ptr 是一个指针,指向一个整数,该整数是常量”。

\n\n

这在实践中意味着什么?

\n
    \n
  • 你不能通过 ptr 修改它指向的变量的值。
  • \n
  • 你可以修改指针本身(让它指向另一个变量)。
  • \n
\n\n
#include <iostream>\n\nint main() {\n    int a = 10;\n    int b = 20;\n\n    const int* ptr = &a;  // ptr — 指向 const int 的指针\n\n    // *ptr = 15; // 编译错误!不能通过 const int* 修改值\n    std::cout << "*ptr = " << *ptr << std::endl; // 输出 10\n\n    ptr = &b; // 可以!修改指针本身\n    std::cout << "*ptr = " << *ptr << std::endl; // 输出 20\n\n    return 0;\n}
\n\n

这种类型常用于向函数传递数据,当你希望确保函数不会破坏原始数据时。例如,字符串 void print(const int* data) 是一个“只读”承诺。

\n\n

变体 2:int * const ptr(指向整数的常量指针)

\n\n

从右向左读:“ptr 是一个常量指针,指向一个整数”。

\n\n

这里正好相反:

\n
    \n
  • 你可以修改 ptr 指向的变量的值。
  • \n
  • 你不能修改指针本身(它必须始终指向同一块内存区域)。
  • \n
\n\n
#include <iostream>\n\nint main() {\n    int a = 10;\n    int b = 20;\n\n    int * const ptr = &a; // ptr — 指向 int 的常量指针\n\n    *ptr = 15; // 可以!通过指针修改值\n    std::cout << "*ptr = " << *ptr << std::endl; // 输出 15\n\n    // ptr = &b; // 编译错误!不能修改指针本身\n\n    return 0;\n}
\n\n

可以把 int * const 想象成一个“绑定”的指针。它常用于操作硬件寄存器,或者当指向缓冲区的指针不应“逃逸”到其他位置时。

\n\n

变体 3:const int * const ptr(指向常量整数的常量指针)

\n\n

从右向左读:“ptr 是一个常量指针,指向一个整数,该整数是常量”。

博客

书籍推荐