1.0 - 指针和引用
1. 基本认识
指针是内存地址,指针变量指的是存储内存地址的变量,本质和其它的变量没有区别,只是其它变量位置存储的是值,指针变量位置存储的是一个地址。
做一个比喻,以 int a = 10 为例:申请了一块内存里面存储 int 类型的10,而变量名称 a 就相当于这块内存的一个标签,平时只要说到标签其实是指内存中存储的内容。
而引用:可以看作这个内存的第二个标签,和初始定义的变量名称地位等同。
指针和引用的区别:指针变量作为一个变量首先是符合变量的特征的,指针变量也是一块内存的标签并且这块内存中存储的地址或NULL;而引用更多作为第二标签存在。所以区别大致:1)指针变量可以赋值为NULL;但是引用不可以,引用必须连接到一块合法内存。2)指针可以在任何时候被初始化;引用必须在创建的时候就初始化。3)引用一旦指向一个对象就不能再指向另一个对象,指针变量可以随时修改内存中存储的地址值来更换指向的对象。
2. 指针&引用修饰数据类型
int 表示后面的变量是个普通变量,该普通变量标签标注的内存中存储的是一个int值;
int* 表示后面的变量是个指针变量,该指针变量标签对应内存块中存储的值是一个地址;
int& 表示后面的变量是个引用变量,是某块内存的第二标签,引用变量地位上和普通变量等同。【对引用变量赋值的时候遵循普通变量语法的赋值规则,但在底层中,引用变量被赋值之后不会开辟新的内存空间存储值,而是作为 赋值者对应的内存块 的第二个标签存在,这也是其经常被叫做别名的由来。】
但是注意:
对于字符指针而言,char* chPtr = &ch;当调用 chPtr 的时候,编译器会优先将其作为 字符串 处理,除非用 (void *)强转为指针。
#include <iostream> using namespace std; int main() { int a = 10; int* ptr = NULL; ptr = &a; // 使用 地址 对指针变量初始化 int& ref1 = a; // 对引用变量通过直接赋值的方式初始化 int& ref2 = *ptr; // 对引用变量通过 指针取值 的方式初始化 cout << "a=" << a; cout << "\nfinished" << endl; }
3. 指针&引用修饰变量
指针:*ptr 表示 拿到ptr标签标注内存地址的值然后寻址一次返回结果,**ptr表示 拿到ptr标签标注内存地址的值然后寻址两次返回结果,* 的个数指代寻址次数。
引用:&a 表示 获取变量a标注的内存的地址。
4. 指针&引用作为函数参数
指针作为函数形参:本质也是值传递,传入函数的指针只是原指针的一个拷贝。在函数内将拷贝指针指向另一块内存,原指针的指向性不受影响。但如果原指针和拷贝指针都指向同一块内存,则 原指针和拷贝指针任意一个对内存中的值进行修改,另一方都能识别到。
引用作为函数形参:这才是真正的地址传递,传过来的是实参本身,而不仅仅是一个拷贝,节约了空间和时间。理论上可以将任何函数需要的数据的引用传过来而不存在访问限制,所以,引用做形参相当于扩充了函数的可访问域。
#include <iostream> using namespace std; int x = 10; int y = 20; void doSomething(int* a) { a = &y; } int main() { int* a_ptr = &x; cout << "方法执行前,a_ptr指向的值为" << *a_ptr << endl; // 10 doSomething(a_ptr); cout << "方法执行后,a_ptr指向的值为" << *a_ptr << endl; // 10 }
5. 指针&引用作为(函数)返回值类型
对于函数返回值而言,需要了解:1)函数执行结束之后,函数内定义的局部变量等【除了堆内存中的内容】,都会自动清空。2)return语句之后的内容(值、指针或引用),在函数执行结束之前,会将其复制一份然后返回。
因此:
普通值作为函数返回类型:返回基本变量或object,return的时候会将其复制一份来使用,虽然原基本变量或原object会被析构,但是复制的这一份会一直存在。
指针作为函数返回值类型:拷贝指针 然后返回。反正就拷贝了个指针,至于指针指向的内容后续什么结果,这就不归这里管了。
引用作为函数返回值类型:拷贝引用,并返回。类似于参数传递的地址传递,也是 把某块内存的引用复制然后返回了,至于这块内存后面会不会被回收,也不归这管。
注:因为指针引用只管返回地址,并不关注地址的寻址结果,所以,【 函数返回值 不要返回 局部变量(占用栈内存) 的指针或引用。】
6. 指向类的指针&引用
调用类属性时:指针用 -> 调用object的属性或方法;引用可以当作object的变量名,直接用 . 来调用。(引用在用法上,和普通的基本变量,类变量没区别,只是效果不同而已。)
7. C++指针的算数运算
指针变量之间可以进行 ++ 、--、+、- 运算。
++、--:以 int* ptr = 10; 为例,ptr++ 会使ptr指针向后移动4个字节,同理,-- 使ptr指针向前移动4个字节。移动几个字节取决于指针变量的类型,如:int - 4Byte,char - 1Byte。
+、- :指针和整数n操作,表示指针移动对应n个元素大小的长度;指针和指针相减:返回之间相差的元素个数,指针与指针相加没有意义。
8. 泛型指针 void*
void* 可以指代任何类型的指针,作用类似于泛型。