const和一二级指针的结合应用

一、const 修饰的量叫常量,它和普通变量的区别是什么?

C++有两点:
1、编译方式不同,用立即数替换

2、不能作为左值被修改

二、const修饰的量(即常量)常出现的错误是:

1、常量不能再作为左值(即不能直接修改常量的值)

2、不能把常量的地址(&a)泄漏给一个普通的指针(p)或者普通的引用变量(可以间接修改常量的值)

int main() {
	const int a = 10;
	int *p = &a;	❌ // *p = 30;   int *  <= const int *
 	// *就相当于地址,因为地址的学名是指针 ,两者互相等价,所以&a的数据类型就是const int *
  // 两边的数据类型不等,故不能执行,需要把&a强转成(int *)或者左边的p的数据类型改成const int *
   // 为什么要把左边的类型改成const int *呢?是因为改了之后,一方面是两边类型一致, 一方面是const int *p的话,就是表明*p是不能够被修改的,这样就符合const int a的意思,不修改a的值,这样a才能够放心地把它的地址告诉p,因为反正*p也改不了a的值
}



三、const和一级指针的结合 有两种情况:

①不能修改指针的解引用

②不能修改指针的指向

C++的语言规范:const修饰的是离它最近的类型(有点像飞轮海的《只对你有感觉》,const就只对离它最近的数据类型有感觉)

const int *p;		// 这里const修饰的类型是int,不是int*, 因为int自己就可以作为一个类型。那其实我们更在意的是const修饰的是什么表达式,除去int这个数据类型,剩下的就是const修饰的表达式了, 就是*p。也就是说*p不能再被赋值了,故你可以通过指针来指向某块内存,但是你不能够通过指针解引用(*p)来修改这块内存里的值。
// *p = 20❌   p = &b ✅ 
// 因为指针p本身没有任何东西修饰它,const修饰的是*p这个表达式,而不是p,所以p可以被重新赋值
// 综上,p可以任意指向不同的int类型的内存,但是不能通过指针间接修改指向的内存的值
int const *p;	//这里*不能够独立作为一个数据类型,所以const修饰的最近的数据类型是int,const修饰的表达式是*p,这样的话就跟上面那个一样了,就是const的位置改变了一下而已。我们经常把写成上面那种形式
int *const p;	
// p = &b;❌  *p = 20;✅
// 这个指针p现在是个常量,不能再指向其它内存,但是可以通过指针解引用修改指向的内存的值
const int * const p;	//这个就相当于是上面的结合
// 第一个const修饰的表达式是*p,第二个const修饰的表达式是p
// 这样就显得非常严格,既不让*p被修改,也不让p被修改



const如果右边没有指针*的话,const是不参与类型的

四、总结const和指针的类型转换公式:

① int * <= const int * ❌ 因为如果把右边常量赋值给左边的普通变量,那左边一解引用就可以对常量的值进行修改了,这样是不被允许的。

② const int * <= int * ✅ 普通变量赋到左边常量去倒是没有什么约束的。

③ int ** <= const int ** ❌

④ const int ** <= int ** ❌ const和多级指针结合的时候,赋值时必须两边都有const (有空可以思考一下为什么)

⑤ int ** <= int * const* ❌ // 这是const和一级指针结合的情况,因为只看const后面的星号*,前面的 * 和 const没关系。两边都去掉 int *,那么就成了 * <= const * ,就跟第一个一样了,所以是错误的。

⑥ int * const* <= int ** ✅ // 跟⑤类似,去掉int * 看一下就知道了,去掉之后就是②了,所以是正确的。

int a = 10;
const int *p = &a;	// 不管a是普通变量还是常量,对于编译器来说,它永远认为p里面放的是整型常量的地址
int *q = p;	// int * <= const int *❌ 不能把整型常量的地址赋给一个普通的指针

// 可能会有面试官这么绕你,说p存放a的地址,p赋值给q,q存放a的地址,q是普通变量,那么可以通过*q修改a的值。那么这样做有什么错误吗??❌  这样说是错误的,就算这里没a,也是错的。
// 也可以是const int *p = nullptr;
// 这样的话就直接看出来是int* <= const int * ❌
// 不管a是普通变量还是常量,对于编译器来说,它永远认为p里面放的是整型常量的地址

int *q1 = nullptr;	// NULL是宏名,可以赋值给空指针或整型,容易跟整数混用,所以不好,C++11以后专门给指针一个初值nullptr,这样就不会和整数混用了。
int *const q2 = nullptr;
cout << typeid(q1).name() << endl;
cout << typeid(q2).name() << endl;
// 输出的结果都是int *
// 结论:const如果右边没有指针*的话,const是不参与类型的
// 所以q2的数据类型是int *,const则表示q2本身是个常量,表示它不能作为左值,不能将它的地址泄漏给一个普通的二级指针。

int a = 10;
int *p1 = &a;
const int *p2 = &a;		// const int *  <= int *
int *const p3 = &a;		// 综合上面的结论:这里就是int* <= int*
int *p4 = p3;	// 实际上也是int * <= int * 



五、const和二级指针的结合

一级指针&二级指针知识点梳理


int main() {
  int a = 10;
  int *p = &a;
  const int **q = &p; ❌	// const int** <= int **
  // 跟多级指针结合应用,必须两边都有const
    
  /*
  	const int **q = &p;这一句话错误的原因如下:
    	*q <=> p
    	*q访问的是一级指针的内存,p是一级指针的内存,都是一级指针的内存
    	const int b = 20;
    	*q = &b;		// 就相当于p = &b,这样就违背了前面的一个结论——不能把常量的地址泄漏给一个普通的指针
    	// &b相当于一个一级指针
  */
    
  /*
  		有两种修改方式:
      ① const int *p= &a;
      (在第二句话钱加个const,这样就不用担心上面说的那种将常量地址泄漏给普通指针的情况了)
      ② const int * const* q = &p;
      (第三句话中间加个const,前面说出现错误的原因就是因为把&b赋值给*q,那我们可以不让*q被赋值,限定它为一个常量,不能作为左值被修改,故最后就不可能通过*q = &b这种方式,把一个常量的地址泄漏给一个普通的指针,这样就不会报错了)
  */
}
posted @   算法扫地僧  阅读(111)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示