文章目录
const修饰的变量和普通变量的区别
基本理解:
- 普通的变量可以作为左值。
- const修饰的变量不能再作为左值。(值初始化完成后,不能被修改)
#include<stdio.h>
int main()
{
int a = 10;
a = 20;//ok
const int b = 20;
b = 30;//err
return 0;
}

C和C++中const的区别
相同点:都不能再作为左值出现
不同点:
-
const编译方式不同
-
C中,const就是当作一个变量来编译生成指令
-
C++中,所有出现const常量名字的地方,都被常量的初始值替换了。
-
初始化方式
-
C中,const修饰的量未进行初始化可以编译通过(但是如果不进行初始化,就失去了给它合法值的机会) 常变量
-
C++中,const修饰的量必须进行初始化,否则编译出错。 常量
注意:
我们说const修饰的量不能再作为左值,但是const修饰的量,这个量的内存能不能被修改呢??
内存是可以修改的,可以通过汇编指令或者指针进行修改。
const只是在语法上保证它修饰的量不能被作为左值进行修改。其内存是可以修改的。
以下代码就是通过指针对a所在的内存中的值进行了修改。
#include<stdio.h>
int main()
{
const int a=10;
int *p = (int *)&a;
*p = 40;
printf("a=%d,*p=%d,*(&a)=%d", a, *p, *(&a));
return 0;
}

#include<stdio.h>
int main()
{
const int a = 20;
int array[20] = {};
int *p = (int *)&a;
*p = 30;
printf("a=%d,*p=%d,*(&a)=%d", a, *p, *(&a));
return 0;
}


const修饰的量应注意的
- 常量不能再作为左值
- 不能把常量的地址泄露给一个普通的指针或普通的引用变量
C++的语言规范:const修饰的是离它最近的类型
当const右边没有指针(*)时,const是不参与类型的
—————————————————————————————————————
const和一级指针的结合
const和一级指针的结合方式
int *q1=nullptr;
int *const q2=nullptr;
cout<<typeid(q1).name()<<endl; //int *
cout<<typeid(q2).name()<<endl; //int *
const int *p;
/*
* const修饰的类型是int
* 修饰的表达式是*p,*p不能再被赋值
* 可以任意指向不同的int类型的内存
* 但是不能通过指针间接修改指向内存的值
*/
int const *p;
/*
* const修饰的类型是int
* const修饰的表达式是*p
*/
int *const p;
/*
* const修饰的类型是int *
* const修饰的表达式是 p
* p不能再被修改,p是常量,不能再指向其他内存
* (*p)可以被赋值,可以通过指针解引用修改指向内存的值
*/
const int *const *p
/*
* (*p)不能被赋值
* p不能被赋值
* p不能再指向其他内存
* 不能通过p解引用修改p所指向内存的值
*/
const和一级指针的类型转换公式
int * <= const int * //error
const int * <= int * //ok
int *const <= int * //ok
int * <= int *const //ok
面试题
int a=10;
const int *p=&a;
int *q=p; //error int * <=const int *
cout<<typeid(p).name()<<endl;// int const * ,const在int的左右无所谓
/*
* 问题?
* p中放的是整型常量的地址,不能把整型常量的地址赋值给一个普通指针
*/
const和二级指针的结合
int a=10;
int *p=&a;
const int **q=&p;//const int ** <= int **
const和二级指针的结合方式
const int **q;
/*
* const修饰的类型是int
* const修饰的表达式是**q
* (**q)不能被修改
* q可以被修改
* (*q)可以被修改
*/
int *const *q;
/*
* const修饰的类型是int *
* const修饰的表达式是*q
* (*q)不能被赋值
* (**q)可以被赋值
* q可以被赋值
*/
int **const q
/*
* const修饰的类型是int **
* const修饰的表达式是q
* q不能被赋值
* (*q)可以被赋值
* (**q)可以被赋值
*/
const和二级指针的类型转换公式
- 要么两边都必须有const
- 要么两边都没有const
int ** <= const int ** //error
const int ** <= int ** //error
int ** <=int *const *
/*
* 属于const和一级指针的结合
* 两边都去掉int*
* 变为( * <= const * ) error
*/
int *const * <= int **
/*
* 还是相当于const和一级指针的结合
* 两边都去掉int *
* const * <= * ok
*/
转换错误原因分析
如果const int ** <= int ** 能够成立的话,就有可能把一个常量的地址泄露给一个普通指针,这是不允许的。
解决办法:
- 让const 修饰*p (const int *p), *p不能被赋值,这样就不可能通过p解引用把常量的值修改了。
- 让const修饰*q (const int *const *q), *q不能被赋值,就不可能通过 *q=&b这样的方式把一个常量的地址泄漏给一个普通指针
const和一级指针、二级指针结合的典型例题
int a = 10;
const int *p = &a;//const int * <= int * ok
int *q = p; // int * <= const int * error
int a = 10;
int *const p = &a;//int * <= int *
int *q = p;//int * <= int *
int a = 10;
int *const p = &a; //int * <= int *
int *const q = p; //int * <= int *
int a = 10;
int *const p = &a;//int * <= int * ok
const int *q = p;//const int * <= int * ok
int a = 10;
int *p = &a; //int * <= int *
const int **q=&p;//const int ** <= int ** error
int a = 10;
int *p = &a;//int * <= int *
int *const*q = &p; ok
/*
* int * const * <= int **
* const 跟一级指针的结合
* const * <= * ok
*/
int a = 10;
int *p = &a;//int * <= int *
int **const q = &p;//int ** <= int ** ok
int a = 10;
int *const p = &a;//int * <= int *
int **q = &p; //error
/*
* int ** <= int *const *
* const 跟一级指针的结合
* * <= const * error
*/
int a = 10;
const int *p = &a;//const int * <= int * ok
int *const* q = &p;//int *const * <= const int **
/*
* 首先看左边的const,const跟一级指针结合多了一个const ok
* 再看右边的const,转换成int * <= const int * error
*/

const与一级指针、引用结合的典型例题
int a=10;
int *const p=&a;//p为常量
int *&q=p;//error
//int *&q=p <==> int **q=&p
/*
* 错误原因在于把常量p的地址泄漏给了一个普通的二级指针
*
*/
int a=10;
const int *p=&a;
int *&q=p;//error
/*
* int *&q=p <==> int **q=&p
* int ** <=> const int
*/
int a=10;
int *p=&a;
const int *&q=p;//error
/*
* const int *&q=p <==> const int **q=&p
* const int ** <==> int ** error
*/