159-C++基础

159-C++基础,第1张

1、const的初步认识

const怎么理解?

  • const修饰的变量不能够再作为左值!!!
  • 初始化完成后,值不能被修改!!!

  • 图示b=30;语句错误。因为const修饰b的值为20,之后,b的值就不能被修改了!
2、C和C++中const的区别是什么? C中的const
  • 我们在C文件中使用const,在C语言,把const修饰的量和普通的量都是变量,只是const修饰的变量不能作为左值。
  • 在C语言中,const修饰的量可以不初始化,但是就没有机会再给它合法的值了,因为不能作为左值。
  • 在C中,const修饰的量不叫常量,叫做常变量。

下面这个数组写法是错误的,因为a不是常量,是常变量,所以它不能作为常量/常量表达式来使用。


面试问题:

  • 指针p指向的是a的内存;
  • const只是语法上保证修饰的量a不能作为左值,即不能作为左值修改;
  • 但是内存是可以修改的,我们通过指针就可以修改了;
  • 我们也可以通过插入汇编指令去修改a的内存;

我们看到,a的内存的值已经被改为30了。
因为在C语言中,a是常变量!!!

C++中的const
  • 在C++中,对于const修饰的量是必须要进行初始化的。


可以看到,不初始化是无法通过编译的。

C++的const必须初始化,叫做常量。

  • 既然是常量,是可以来定义数组的(因为是常量,所以可以作为数组的下标哦!)


我们把a进行强转看看:


可以发现,打印出来的值和在C文件中打印出来的值不一样。

因为对const的编译方式不同:

  • 在C中,const就是当作一个变量来编译生成指令的。
  • 但是在C++中,所有出现const常量名字的地方,都被常量的初始化值给替换了!!!

数组定义:

在C++中相当于将数组长度a直接替换了:(是用20在定义数组的长度。)

在这行代码中:

  • 出现const常量名字的地方,都直接用常量的值进行替换;


问题:p指针到底有没有修改a的内存值?

  • 改了,a的内存值已经被修改成30了。
  • *pa的内存的值改为30了,但是编译器在编译时是把常量a都用20替换了,和a的内存就没有关系了。
  • 所以,const修饰必须初始化,不然拿谁替换啊???

我们再来看:

C++文件:

用变量b初始化a,但是变量的值是多少只有在运行的时候才知道,所以我们可以认为,a的地方都用变量b来替换了。

此时的a已经相当于退化变成C语言中的常变量了。不能定义数组了,也不能替换了。

  • 在C++中,const初始值是一个常量,则这个就是一个常量;是变量,就是常变量
3、const与一级指针的结合应用

后面给空指针都是用nullptr。

  • 因为在C++中,NULL是空指针或者0值。NULL不区分指针和整数。

const修饰的量 叫常量,和普通变量的区别是什么? C++有两点区别?

  • 1、编译方式不同 (编译过程中所有出现常量名字的地方,都会用常量的初值来替换)
  • 2、不能作为左值了

C++中const修饰的量常出现的错误是:

  • 常量不能再作为左值 (不能直接修改常量的值)
  • 不能把常量的地址泄露给一个普通的指针或者普通的引用变量 (不可以间接修改常量的值)
  • 这2点是C++编译器可以检测出来报错的。

我们看下面代码:

因为指针没有做任何的修饰,指针解引用可以随便赋值的,会间接修改。

无法编译通过:

那怎么转换呢?

const和一级指针的结合:有4种情况

C++的语言规范:const修饰的是离它最近的类型。

1、const int *p = &a;
const int *p = &a;
  • const修饰的就是int了,因为int本身就可以组成一个类型,不需要再带后面的* 。

  • 我们不关心const修饰的是什么类型,我们关心的是const修饰的是什么表达式。什么表达式不能再被赋值了。

  • 我们把修饰的类型去掉,就是const修饰的表达式了:*p

  • *p就不能被赋值了。

  • *p被const修饰了,const修饰了指针p的指向,指向的东西不能被赋值了。

  • 但是指针本身可以被赋值,因为p本身没有被const修饰。(p=&b是可以的)

  • p可以任意指向不同的int类型的内存,但是不能通过指针间接修改指向的内存的值。

2、int const* p;(和第1个一样的)
int const* p;
  • const修饰的是离它最近的类型,但是*不是类型哦,不能用 * 定义变量,所以修饰的还是int。
  • const修饰的表达式还是 *p;
3、int *const p = &a;
int *const p = &a; 

  • 这个const修饰的类型是int *了,因为 * 自己不能单独作为类型,所以再往前走,就是int *了
  • 去掉const修饰的类型,就是const修饰的表达式,就是p本身了;
  • p本身是常量,不能被修改(p = & c,是错的),但是 *p没有被const修饰,可以修改(*p = 20是可以的)。
  • 这个指针p现在是常量,不能再指向其它内存,但是可以通过指针解引用修改指向的内存的值
4、const int *const p = &a;
  • 上面的情况的综合
  • 前面的const修饰的类型是int,所以const修饰的表达式是*p,*所以 p不能被赋值。
  • 后面的 const修饰的类型是int *,所以修饰的表达式是p,所以p不能被赋值。

举例:
这样*p就不能被解引用了。

下面几种写法都可以指向a:

  • 总结:

我们看这个是什么情况?

直接先说结果:其实是int* <= int*,const没有参与作用!

我们先来看下面:

  • const如果右边没有指针*的话,const是不参与类型的!!!
  • const只用来表示q2是常量,q2不能作为左值

其实是int <= int,const没有参与作用!**

下面这两个也是都没有问题的:

总结const和指针的类型转换公式:
左值         =   右值 
int*        =    const int*    是错误的!
const int*  =    int*          是可以的!

面试案例


int *q=p是错误的。const int * 不能赋值给int *

4、const与二级指针的结合应用


左边的类型是const int**,右边的类型是int **

这个类型转换是正确还是错误的???
我们看下面示意图:

对于这个二级指针q,它的表达式组成就这3种:

  • q(表示本身的值)
  • *q(表示它所指向的一级指针p的值)
  • **q(表示它所指向的一级指针p指向的变量a的值)

const和二级指针的结合:(有3种情况)

  • 第一种,const修饰的是int类型,所以**q不能被赋值,但是* q可以被修改赋值,q本身也可以被赋值。
  • 第二种,const修饰的是int * 类型,所以 * q不能被赋值,但是q和 **q`可以被赋值。
  • 第三种,const修饰的是int * * 类型,所以q不能被赋值,但是*q **q可以被赋值。
总结const和指针的类型转换公式:
左值    =   右值 
int*    =    const int*    是错误的!
const int*  =   int*       是可以的!

const和多级指针结合的时候,两边都必须要有const,一边有一边没有是不行的
int**  =  const int**        是错误的!
const int**  =  int**        是错误的!

int**  =  int*const*(这个const是和一级指针的结合,后面是1*) 是错误的!
==* =const * 所以是错误的!!!

int*const*  =  int**     是可以的!(*转成const*是可以的)
const* = * 是可以的

我们看:

  • p是普通的指针,*q指向p这个普通的指针, * q 和p访问的是同一块内存,如果我对 * q赋值,相当于是把内容写到这块内存中,*q存的是const int *,也就是把整型常量的地址是赋值给 *q,const int b=20,可以把&b赋值给 *q,但是p是普通的指针啊,p可以解引用修改整个整型常量的地址啊,所以肯定不行啊!!!不能把常量的地址泄露给一个普通的指针!!!

相当于把这个整型地址放到普通的一级指针变量里面。
但是常量的地址赋值给普通的指针p(因为p和*q等价)了,这是不行的。

怎么改呢???

解决方法1:

  • 此时 * p不能被赋值了。就可以了。

    解决方法2:
    让*q不能赋值。
5、总结,笔试题 例1


A错:

B正确:

C正确。 const不参与类型。都是int*

例2


A错误。 把常量的地址给普通的指针了。

B正确。

C正确。

D错误。

调整下,变为:

E错误。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/873085.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-13
下一篇2022-05-13

发表评论

登录后才能评论

评论列表(0条)

    保存