目录
指针
指针类型
野指针
二级指针
Const修饰指针
引用
引用的作用
常引用
引用和指针的对比
引用能够完全替换指针吗?
指针
指针是C语言中的概念,它是指计算机储存内容的地址。指针它的值指向存在电脑储存器中另一个地方的值。通过地址能找到的所需的变量单元,即地址指向改变量单元。因此,讲地址形象化的称为“指针”。意思是通过他能找到以他为地址的内存单元(然后可以更改改内存单元中储存的内容)。
指针变量大小:32位机器:4字节,64位机器:8字节
指针类型
由于指针表示指向计算机存储内容的地址,所以指向的内容不同就分出了很多不同的指针类型,比如指向整形就被称为整形指针、指向函数地址的就被称为函数指针、指向数组的指针被称为数组指针等
指针类型就决定了我们后续进行解引用操作时,可以访问的空间大小。比如char*能访问1个字节,int*能够访问4个字节,double*能够访问8个字节。
指针类型也决定了:指针一步走多远(指针的步长)。比如:char*类型的指针变量+1,地址+1;int*类型的指针变量+1,地址+4。
野指针
野指针:是指针指向的位置是不可知的、随机的。
野指针出现原因:
1.指针变量没有初始化(即没有赋值给指针变量)
2.指针越界访问:当指针指向的范围超出了原先设定的范围,则会出现野指针,比如使用数组指针时访问超出了数组的范围。
3.指针指向的内存被释放。比如我们在一个函数中把一个局部变量的地址给储存起来了。但是当我们退出函数后,局部变量会被删除,就算我们储存了局部变量的地址,但这个地址实际上在函数结束又返还给了内存,此时这个指针就变为了野指针。
如下图所示,我们定义的int类型的arr数组,总共只有10个元素,我们用p来指向这个arr数组的元素位置,但是当i=11时,我们指针就超过了arr数组指定的范围,即越界访问,这时就会产生野指针。
如何避免野指针?
- 指针创建时要初始化,若真不知道赋给指针变量什么值,就可以先赋值NULL/nullptr(空指针)
- 小心指针越界(越界时,系统会崩溃,假如系统崩溃,可以看看是否指针越界)
- 指针指向的空间释放后,给其赋值NULL。即指针不用的时候就赋值NULL空指针(注意NULL空指针不能访问)
- 指针试用前先检查有效性
二级指针
二级指针:就把一级指针的地址存起来,(一级指针存变量的地址)。一个*就是一级指针,**就是二级指针。可以依次往上递增,同理***存放二级指针的地址,称为3级指针。
注意:多级指针解引用访问时也要解多次。
Const修饰指针
当const在类型前面,修饰的是指针变量num所指向的内容,如 const int* num。此时const修饰的是指针变量num所指向的内容,表示指针变量 num 所指向的内存单元里面的内容不可变,指针变量num是可变的,可以改变,指向其他地址。
当const修饰指针变量时,如 int* const num此时 const 修饰的是指针变量 num,所以指针变量 num 不可变,指针变量num所指向的内容可变。
方便记法:
const int* num:num先与*结合,*num表示一个int类型,*num不可变
int* const num:num先与const结合,在解引用,表示num不可变
引用
引用是C++中的概念,在C++中我们可以给变量取别名,这个操作就叫引用。使用方法:类型& 新变量名=旧变量名。如下图所示,打印的&b和&a,打印a和b的地址,会是同个地址,下面b++也会让a++,a++也会让b++,最终a=b=2
引用特性:
- 1.引用(取别名)可以对一个变量重复使用,也可以对一个别名再引用。
- 2.引用必须在其初始化时就使用,不能先创建一个引用在让引用指向其他值。
- 3.引用定义后不能改变指向。
-
注意:取别名的前提是不能放大权限。如果一个变量原来是const修饰的,那就不能用普通的引用来引用它,要用常引用。
-
引用的作用
-
做函数参数(输出型参数,参数会改变后返回)。在C语言中我们函数若要改变传参的值,传参必须传递地址,接收改变也必须都用指针。而在C++中,我们可以用引用作为函数的传参,这些形参就不是原参数的零时拷贝,而是原参数的别名,改变别名的值也会影响原参数。如果传参过大,引用也能减少空间的浪费,提高代码效率(以上功能指针都能实现,但是引用更简单)。
-
引用做函数参数的作用:1.做输出型参数,2.减少拷贝量,提高效率。
-
做函数返回值,可修改返回值。注意:当引用做函数返回值时,不能返回局部变量的引用。当使用static修饰的全局变量或者malloc开辟的变量(一个不会随着函数结束而被回收的变量),这些都可以用引用返回,然后对返回的变量修改。
-
引用做函数返回值的作用:1.修改返回值(不是局部变量),2.减少拷贝量,提高效率。
常引用
常引用,即在类型前面加上const,用于我们需要用到引用,但又不想改变引用的值的情况。在后面的拷贝构造函数中,我们需要用到引用来传参,但又不想引用的参数被改变,所以就用const。
常引用引用的对象可以是常量或者表达式。注意:表达式不能用普通的引用来引用,因为一个表达式的结果是一个临时变量,具有常属性,要引用的话只能用常引用。
整形提升/截断时产生的零时变量也具有常属性,可以被常引用引用。例如下图:
-
-
-
常引用是一种权限的缩小,只读,不写不改。
引用和指针的对比
引用和指针的不同点:
- 1.语法上引用是别名,不开空间;而指针是地址,需要开空间存地址。底层中引用和指针都会开辟空间(从汇编层面看,引用底层是用指针实现的)。
- 2.别名必须初始化给一个值,指针可以不初始化(指针不初始化可能会有野指针,但不用就行)。
- 3.指针可以改变指向,引用不行。
- 4.因为上面两个原因,所以引用相对安全,没有空引用,但有空指针。有野引用(函数返回值用引用,返回局部变量,局部变量被收回后导致出现野引用),也有野指针,但是野引用不常见,而野指针很容易出现。
- 5.引用和指针在sizeof中含义不同,sizeof(指针)返回值只有4/8(返回大小只跟操作系统位数有关),sizeof(引用)返回的是引用的类型大小。
- 6.加减:引用自加是引用实体加1,指针自加是往后偏移一个类型的大小。
- 7.有多级指针,但没有多级引用。
- 8.指针要访问到实体需要解引用,引用可以直接访问到实体(编译器自己会处理引用)
-
引用能够完全替换指针吗?
在C++中,引用不能完全替代指针。因为指针可以重新指向新的地址,而引用不行。引用只是对一些使用指针比较复杂的地方进行替代、优化,使代码更简单易懂。比如链表、二叉树都还是需要指针去连接。Java、Python都没有指针,只有引用,但它们的引用是可以重新改变指向的,所以不需要使用指针。
-