概念
指针是一个变量,里面存储的是指向内存存储单元的一个地址。
1 | int a = 5; |
打印结果:变量 a 的内存地址: 0x7ffdaea1eb0c 值: 5 变量 b 的地址:0x7ffdaea1eb08
a 就是个变量,ptr 是指针变量,ptr 里面存储的是 a 的内存地址。
引用是一种特殊的指针,可以理解为是对一个变量起了个别名。
1 | int b=5; |
打印结果:
1 | 变量 b 的地址:0x7ffdd17efcd4 |
不同点
1、指针是一个对象,而引用不是。所以引用不可以为空,创建的时候,必须初始化,指针可以在任何时候被初始化。
2、指针可以有多级,但是引用只能一级(int **p 正确,而 int &&p 不正确)。
3、指针的值初始化之后可以改变,可以指向其他存储单元,引用初始化之后就不能再改变。
4、”sizeof 引用”得到的是所指向的变量 (对象) 的大小,而”sizeof 指针”得到的是指针本身的大小。
5、如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏。
6、指针和引用的自增(++)运算意义不一样。(一个地址 + 1,一个值 + 1)
指向指针的引用
1 | int i = 42; |
打印结果:
1 | 0x7ffe7289e394 |
复杂表达式从右向左一个一个阅读,离变量名最近的符号是对变量类型有直接影响,这里 *(&ref), 因此 ref 是一个引用,然后 (&ref) 是一个指针。
与 const 结合
1、const 和引用
常量的引用,必须也是一个常量。
1 | const int ci=1024;// 这是一个常量 |
变量的引用
1 | int i=42; // 一个变量,未初始化 |
常量引用指向变量的时候,即便变量修改了值,常量引用依旧指向的是当初的那个变量的值,不离不弃。
2、const 和指针
就是将指针定义为不可更改的常量。
顶层 const:表示地址本身是常量
底层 const:表示数据是常量
1 | int num_b = 2; |
从上面的实验可以了解到,底层 const 虽然值是不可以改变的,但是可以通过指针地址的变动,从而修改里面的值。
顶层 const 指向的地址无法改变,那如果我指向一个 const 类型的变量,直接修改它的值,是不是就能变相修改 const 变量的值了呢,答案是不行的。
1 | const double z = 3.14; |
作为函数参数
让指针或者引用作为函数参数来传递,是为了减少对实参的副本拷贝。
我的理解是指针和引用作为函数参数,都可以达到想要的效果,引用可以看作是对实参起了个别名,操作的是同一个对象。
函数参数是指针的函数:
1 | void testPoint(int *p) |
函数参数是引用的函数:
1 | void testRef(int& ref) |
指针函数和函数指针
函数指针:
一种特殊的指针,指向函数入口
1 | /* |
指针函数:
一个函数,返回值是指针
1 | class Hello |
上面是用 new 的方式生成了一个 hello 实例,然后返回了这个实例的指针,乍看上去,应该出了作用域就应该被回收了,但是没有,并打印出了 name,
如果是简单类型,就回收了。
1 | int *function(int a){ |
原因应该是用了 new,则需要显式 delete,否则内存不释放,就 GG 了。
那不用 new 这种显式声明呢?
1 | class Hello |
不声明 new,出了作用域,对象马上灭亡,所以空指针。
指向数组
1 | char x[] = {'a','b','c','\0'}; |
一个 Array 类型的变量,其实本质上是一个指向数组第一个元素的指针。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章