核心内容摘要
《不该瞒着妻子参加漫展》:一场关于爱与理解的二次元奇遇_1
const 指针与指针 const分清常量指针与指针常量在C指针编程中const与指针的组合是高频易错点尤其是“常量指针”const 指针与“指针常量”指针 const二者语法格式仅差const位置含义与用法却天差地别。
前文我们已掌握指针、二级指针及引用的核心逻辑本文将聚焦这两种特殊指针从语法规则、本质差异、内存特性、实战场景四个维度逐一拆解帮你精准区分二者边界规避编程中的常见错误彻底吃透const与指针的组合用法。
前置回顾const 修饰变量的核心逻辑在讲解特殊指针前先回顾const修饰普通变量的基础规则为后续分析铺垫const修饰变量时本质是将变量变为“只读常量”禁止通过该变量修改其存储的值但变量内存地址仍可被引用。
语法格式const 数据类型 变量名或数据类型 const 变量名二者等价修饰普通变量时const位置可互换。
示例const int a 10;与int const b 20;均表示变量值不可修改。
关键提醒当const与指针结合时const的位置决定了其修饰对象是指针指向的值还是指针本身这也是区分两种特殊指针的核心。
核心辨析常量指针与指针常量的定义与本质常量指针与指针常量的核心差异在于const修饰的目标不同常量指针修饰“指针指向的值”指针常量修饰“指针本身”。
以下从语法、本质、特性三方面逐一拆解。
常量指针const 指针指向常量的指针1语法格式// 两种等价写法const 修饰指针指向的值const数据类型*指针名;数据类型const*指针名;示例const int *p;或int const *p;均为int类型的常量指针。
2本质与核心特性常量指针的本质是“指针指向的目标值不可修改”但指针本身是变量可修改其指向的地址。
形象理解指针是“可变的路标”但路标指向的“目的地内容”不可更改。
核心规则必记禁止通过常量指针修改指向的值只读特性但可通过原变量修改值若指向的是普通变量。
指针本身可重新赋值指向其他同类型变量普通变量或常量均可。
3实战示例与验证#includeiostreamusingnamespacestd;intmain(){inta10,b20;constint*pa;// 常量指针p指向变量a// 特性1禁止通过指针修改指向的值// *p 20; // 错误常量指针指向的值不可修改a20;// 合法通过原变量修改值指针指向的值同步更新cout*pendl;// 输出20// 特性2指针本身可修改指向pb;// 合法指针p重新指向变量bcout*pendl;// 输出20// 特性3可指向常量constintc30;pc;// 合法常量指针可指向常量cout*pendl;// 输出30return0;}
指针常量指针 const指针本身是常量1语法格式// 唯一写法const 修饰指针本身位置不可互换数据类型*const指针名;示例int *const p;为int类型的指针常量。
2本质与核心特性指针常量的本质是“指针本身是常量存储的地址不可修改”但指针指向的目标值可修改若指向的是普通变量。
形象理解指针是“固定的路标”始终指向同一个地址但路标指向的“目的地内容”可更改。
核心规则必记指针本身必须在定义时初始化且初始化后不可重新赋值无法修改指向的地址。
可通过指针修改指向的值若指向的是普通变量而非常量。
3实战示例与验证#includeiostreamusingnamespacestd;intmain(){inta10,b20;int*constpa;// 指针常量p初始化指向变量a// 特性1指针本身不可修改指向// p b; // 错误指针常量地址不可修改// 特性2可通过指针修改指向的值指向普通变量时*p20;// 合法修改a的值coutaendl;// 输出20cout*pendl;// 输出20// 特性3若指向常量不可修改值constintc30;constint*constp2c;// 指向常量的指针常量// *p2 40; // 错误指向的值是常量不可修改return0;}
终极区分技巧看 const 与 * 的位置关系面对const与指针的组合无需死记名称只需通过以下技巧快速判断修饰对象const 在 * 左侧修饰“指针指向的值”为常量指针值不可改指针可改。
const 在 * 右侧修饰“指针本身”为指针常量指针不可改值可改需初始化。
const 在 * 两侧既修饰指针指向的值又修饰指针本身值和指针均不可改需初始化如const int *const p;。
constint*p1;// const在*左 → 常量指针intconst*p2;// const在*左 → 常量指针与p1等价int*constp3;// const在*右 → 指针常量需初始化constint*constp4;// const在*两侧 → 值和指针均不可改需初始化
深度对比常量指针与指针常量的核心差异为进一步厘清边界以下从语法格式、修饰对象、初始化要求、可修改性、使用场景五个核心维度对二者进行全面对比结合表格更直观呈现。
对比维度常量指针const 指针指针常量指针 const语法格式const T* p;或T const* p;T* const p;唯一写法修饰对象指针指向的值指针本身存储的地址初始化要求可先定义后赋值无需初始化必须在定义时初始化否则编译报错可修改性
指向的值不可改通过指针
指针可重新指向其他地址
指针地址不可改
指向的值可改指向普通变量时指向对象可指向普通变量或常量优先指向普通变量指向常量需搭配const修饰值核心用途保护指向的数据不被修改灵活切换指向对象固定指针指向确保始终操作同一个地址的数据补充与常引用的关联对比前文讲解的常引用const T ref与常量指针有相似性均为“保护指向/绑定的值不被修改”但二者本质不同常量指针是“指针变量”可修改指向常引用是“变量别名”绑定关系不可改无独立内存。
常量指针支持空值const T* p nullptr;常引用无空引用必须绑定有效变量。
实战场景两种特殊指针的选型逻辑常量指针与指针常量的选型核心取决于需求是否需要保护数据不被修改是否需要固定指针指向。
以下是常见实战场景及选型建议结合案例帮你落地应用。
优先使用常量指针的场景1函数参数传递保护数据不被修改当函数需接收指针参数且仅需读取数据、无需修改时用常量指针可防止函数内部误改外部数据提升代码安全性。
这是常量指针最常用的场景尤其适用于传递大型对象地址避免拷贝。
#includeiostream#includecstringusingnamespacestd;// 常量指针作为参数保护字符串不被修改voidprintString(constchar*str){// strcpy(str, hello); // 错误禁止修改指向的数据cout字符串strendl;}intmain(){chararr[]world;printString(arr);// 传递字符串地址数据安全return0;}2灵活切换指向同时限制数据修改当需要遍历多个数据、切换指针指向且不允许修改数据内容时用常量指针既能满足指向灵活性又能保护数据。
#includeiostreamusingnamespacestd;intmain(){constintarr1[]{1,2,3},arr2[]{4,5,6};constint*parr1;// 常量指针指向arr1// 遍历arr1for(inti0;i3;i){cout*(pi) ;// 输出1 2 3}parr2;// 切换指向arr2合法for(inti0;i3;i){cout*(pi) ;// 输出4 5 6}return0;}
优先使用指针常量的场景1固定指针指向确保操作目标不变当指针需始终指向同一个变量/对象不允许修改指向且需修改数据内容时用指针常量固定指向避免误改地址。
#includeiostreamusingnamespacestd;intmain(){inta10;int*constpa;// 固定指向a不可修改// 多次修改a的值指针始终指向a*p20;coutaendl;// 输出20*p30;coutaendl;// 输出30return0;}2类成员指针固定指向类成员在类中若需定义指向类成员的指针且不允许修改指针指向始终操作该成员可用指针常量确保成员访问的稳定性。
#includeiostreamusingnamespacestd;classPerson{public:intage;Person(inta):age(a){}};intmain(){Personp(
;intPerson::*constpMemberPerson::age;// 指针常量固定指向age成员// 修改成员值指针指向不变p.*pMember30;coutp.ageendl;// 输出30Personp2(
;coutp
*pMemberendl;// 仍指向age成员输出40return0;}
双 const 指针场景const T* const p当既需要固定指针指向又需要保护数据不被修改时用双const指针适用于“只读且指向固定”的场景如配置项地址、常量数据。
#includeiostreamusingnamespacestd;intmain(){constinta10;constint*constpa;// 双const指针值和指向均不可改// *p 20; // 错误值不可改// p b; // 错误指向不可改cout*pendl;// 仅可读取输出10return0;}
避坑指南常见错误与规避方法
混淆 const 修饰对象误改不可修改内容constint*pa;*p20;// 错误常量指针指向的值不可改int*constpa;pb;// 错误指针常量指向不可改规避方案用“const与*位置”技巧快速判断修饰对象牢记“左值右针”原则左修饰值右修饰针。
指针常量未初始化int*constp;// 错误指针常量必须初始化int*constpa;// 正确定义时绑定地址规避方案指针常量定义时立即初始化绑定有效变量地址不可先定义后赋值。
常量指针指向常量后试图通过原变量修改值constinta10;constint*pa;a20;// 错误a本身是常量无论通过何种方式均不可改规避方案常量指针指向常量时数据完全不可修改既不能通过指针也不能通过原变量仅可读取。
函数参数传递时误将普通指针赋值给常量指针voidfunc(constint*p);int*pa;func(p);// 正确普通指针可赋值给常量指针权限缩小安全voidfunc(int*p);constint*pa;func(p);// 错误常量指针不可赋值给普通指针权限放大不安全规避方案指针赋值遵循“权限不放大”原则普通指针可转为常量指针反之则禁止。
六、
总结常量指针与指针常量的核心区别本质是const修饰对象的不同——左修饰值右修饰针。
掌握二者的关键的是无需死记名称只需通过const与*的位置判断修饰目标再结合场景需求选型需保护数据不被修改、灵活切换指向 → 用常量指针const T* p。
需固定指针指向、允许修改数据 → 用指针常量T* const p定义时必须初始化。
需既固定指向又保护数据 → 用双const指针const T* const p。