指针 & 引用
*a 和&a 有什么区别?
&a:其含义就是“变量a的地址”。
*a:用在不同的地方,含义也不一样。
1.在声明语句中,*a只说明a是一个指针变量,如int*a;
2.在其他语句中,*a前面没有操作数且a是一个指针时,*a代表指针a指向的地址内存放的数据,如b=*a;
3.*a前面有操作数且a是一个普通变量时,*a代表乘以a,如c=b*a。
引用和指针的区别?
1) 指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。
2) 引用在定义的时候必须进行初始化,并且不能够改变。指针在定义的时候不一定要初始化,并且指向的空间可变。(注:引用的值不能为NULL)。指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变。
3) 有多级指针,但是没有多级引用,只能有一级引用。
4) 指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用是引用的变量值加1)
5) sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。(为4)
6) 引用访问一个变量是直接访问,而指针访问一个变量是间接访问。 作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用的修改都会改变引用所指向的对象;(指针被解除引用就是它所指向的变量了,解引用操作符是*, 例如某指针变量p, 解引用就是*p, 也就是p所指向的变量了)。
7) 使用指针前最好做类型检查,防止野指针的出现。
8) 从汇编层次上看,引用底层是通过指针实现的。(即通过汇编指令完成被引用变量地址对引用的赋值。
9) 作为参数时也不同,传指针的实质是传值,传递的值是指针的地址;传引用的实质是传地址,传递的是变量的地址。
10)可以有指针常量,但是没有引用常量。
11)如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。(局部对象在生命期结束时被析构,引用指向未分配的内存导致内存泄漏)。
C++中的指针参数传递和引用参数传递
1) 指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(形参指针变了,实参指针不会变)。
2) 引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。
3) 引用传递和指针传递是不同的,虽然他们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将应用不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量(地址),那就得使用指向指针的指针或者指针引用。
4) 从编译的角度来讲,程序在编译时分别将指针和引用添加到符号表上,符号表中记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
野指针及其避免方式
野指针:指向内存被释放的内存或者没有访问权限的内存的指针。
指针变量声明时没有被初始化会形成野指针,即指向随机的地址空间。解决办法:指针声明时初始化,可以是具体的地址值,也可让它指向NULL。
指针p被free或者delete之后,没有置为NULL也会形成野指针。解决办法:指针指向的内存空间被释放后指针应该指向NULL。
指针操作超越了变量的作用范围。解决办法:在变量的作用域结束前释放掉变量的地址空间并且让指针指向NULL。