大学初识指针和引用,一知半解。最近想重新学习C++,发现自己对指针和引用的了解透彻了许多,遂记之以温习。
&
和*
实际上各有两种含义:出现在定义中时,作为运算符时
&
用于定义往往只在函数形参中使用,表示引用,如void func (int& x, int& y) ...
&
作为运算符表示取地址操作,例如int* p = &x
*
用于定义中时表示定义一个指针型变量,例如int* p
或者int *p
*
作为运算符时表示间接取值,即通过地址间接而不是通过变量名直接获取值,如(*p)++
作为运算符
&
和*
分别称之为取地址运算符和间接取值运算符。
&
是一个一元运算符,是一个运算符,它的作用是取出变量的地址,取出的是地址,地址的类型会带上*
,例如int
型的变量x
的地址(例如0x61fe44
)的值的类型就是int*
,这个值不能被保存到int
类型中(因为int
和int*
是两种不同的数据类型),那么这个地址值怎么保存呢?这里定义了指针类型用于保存地址的值。上面例子中我们可以定义int指针类型用于保存int类型的变量的地址(通过&
获取),即int *p = &x
。其实int *p
这种写法容易引起误解,int* p
就明显一点,但是前者似乎更通用。上面的定义已经表明了:p
是一个int*
类型(即int指针类型),它保存的是变量x
的内存地址,因此可以直接通过指针访问变量x
存储的值,方法是*p
,所以实际上*p
和x
都能访问到相应地址块上的值,这里*
使得我们可以间接通过地址p
访问值,所以叫间接寻址运算符。这里注意体会int*
中的*
和*p
中的*
意义是不完全相同的:前者表明这是变量(p
)是一个指针型变量,后者是一种运算符,所谓运算,就从一个状态出发得到新的状态,这里就是指从地址出发计算得到了值
1 | int x = 1000; |
用于参数定义
*
用于参数定义时表示定义一个指针型变量,这十分容易理解。
那么&
用于参数定义时表示什么意思呢?引用!
下面以常见的三种函数参数传递方式为例说说引用的用法。
参数传递有三种常见方式:值传递、指针传递、引用传递
不得不说时隔这么多年,我总算理解了三种参数传递的方式的基本区别,真笨。
假设我们现在需要对一个整型变量x
进行加1操作,三种参数传递的解决方案如下:
值传递:值传递即按照普通方式定义形参,此时会对变量进行复制,以保证函数内部不会修改实参的任何信息,这样的参数传递方式当然不能直接修改实参的值,它返回的实际上是一块新的内存区域
1
2
3
4
5int f (int v) {return ++v;}
int x = 1;
int y = f(x);
cout << x; // 1
cout << y; // 2指针传递:指针传递实际上传递的不是变量名称,而是变量指向的内存区域,这个区域怎么表示呢?当然用一个地址来表示啦。这个地址怎么获取呢?当然是用 取地址运算符& 啦。对于指针传递来说,形参定义为一个指针型变量,而实参也是一个指针型变量(地址),所以指针传递将会直接修改原内存块的值,这导致函数执行后我们再通过相同的方式取访问变量(实际上是访问变量指向的内存块的值),它的值已经发生了改变
1
2
3
4
5void addone (int* p) {(*p)++;}
int x = 1;
cout << x; // 1
addone(&x);
cout << x; // 2引用传递:指针传递实际上并不优雅,它直接让程序接触到了内存地址。与其如此,我们为什么不直接定义一个类似于值传递中的但是又不用对实参进行复制的形参呢?这个形参本质上还是一个非指针数据类型,但是它能直接修改实参的值,就相当于给实参定义了一个别名,不论通过实参本身修改值还是通过这个别名修改值都是等价的。这种方式称之为引用,通过
&
实现,&
作为引用含义时常常出现在函数形参中(&
还可作为运算符使用),它表示形参实际上是实参的一个别名,对形参的任何修改都将等价于对实参的修改,例如形参int& x
定义的就是对某个整形实参的引用,此时传递的实参也不需要像指针传递那样需要先获取地址,程序本身规避了对地址进行直接操作1
2
3
4
5void addone (int& v) {++v;}
int x = 1;
cout << x; // 1
addone(x);
cout << x; // 2
*
和&
的其它高级用法以后遇到了再温习吧~