11-30 7,507 views
在使用Go和C语言之前总是拿引用传递和值传递比较,很少拿引用传递和指针传递进行比较。今天跟一位同事讨论指针和引用的区别时,当时也比较发懵,不知道它们到底有什么区别? 后来查看资料之后,终于知道它们之间的区别了。现在趁着热乎劲儿,赶紧整理一下。
在比较它们之间区别之前,先来说说什么是指针?
#include<stdio.h> int main(void) { int num = 7; int *p = # // 初始化指针 printf("%d 的地址是%p\n", num, p); return 0; }
int *p 定义了一个指向int类型指针p(使用*符号把p声明为指针),并初始化p使其指向int类型的变量num,这里&num中的&是取地址操作符,当&作用于一个对象上时,它返回该对象的地址。这里指针p指向了num所对应的地址。
什么是解引用? 什么是指针赋值?
#include<stdio.h> int main(void) { int num = 7; int *p = # printf("数值%d所在的地址是%p\n", num, p) printf("指针p所执行的地址为%p,该地址上所保存的值为%d\n", p, *p); *p = 100 printf("指针p所指向的地址为 %p , 该地址上所保存的值为%d\n", p, num"); return 0; }
这里的*不再是”声明指针”的意思了,而是”解引用”操作符,它返回指针p所指向的对象。
我们可以对*p赋值,从而改变p所指向地址上所保存的值,从而改变此地址所存储的变量num的值;当然,我们也可以给指针p赋值,使其指向另外一个地址(这样就改变了在解引用时获取的左值)。
#include<stdio.h> int main(void) { int num = 7, another = -5; int *p = # p = &another; printf("%d\n", *p); // 此时p指向了another,所以输出了another的值,即-5 return 0; }
现在咱们知道了指针的概念,接下来咱们说说关于引用的概念。
严格意义上说,在C和Go语言中并没有引用的概念。引用概念在C++、Java中才有的。引用总是指向一个对象,没有所谓的null引用。引用其实就是一个别名。
// 伪代码 int m; int &n = m;
n 相当于m的别名,对n的操作就是对m的操作。打个比方:有个人中文名叫雪松,它的别名是”阿松”。所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。
现在咱们知道引用的概念了吧,那么顺便拓展一下,在使用引用时的一些规则:
1. 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
2. 不能有NULL引用,引用必须与合法存储单元关联(指针则可以指向NULL,空指针)。
3. 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象,上面的实例已经说明该验证)。
// 伪代码 int i = 5; int j = 6; int &k = i; k = j
以上伪码中,k被初始化为i的引用。语句k=j并不能将k修改为j的引用,只是把k的值改变为6。由于k是i的引用,所以i的值也变成了6。
在C++中有按值传递、按指针传递和按引用传递,所以下面通过C++实例来看这三种方式的实现。
按值传递:
void Func1(inx x) { x = x + 10; } int n = 0; Func1(n); count << "n=" << n << end; // n = 0
在函数Fun1内对x值的改变不会影响全局变量n的值。因为x和n指向的是不同的内存空间。
按指针传递:
void Fun2(int *x) { (*x) = (*x) + 10; } int = 0; Fun2(&n); count << "n=" << n << end; // n = 10
由于Fun2 *x 指向的是全局变量n的指针,对Fun2函数变量x的修改也会影响全局变量n的值,因为它们指向同一块儿内存空间。在Fun2函数还有一个变量x,该变量的内容就是*x指向的地址。
引用传递:
void Fun3(inxt &x) { x = x + 10; } int n = 0; Fun3(n); count << "n=" << n << end; // n = 10
函数Fun3内的x是全局变量n的引用,x和n是同一个东西,改变x等于改变n,所以n的值为10。
它们大概是这样的理解:
值: A->A1 指针: A -> B -> A 引用传递: A -> B(B alias A)
现在咱们知道了引用和指针概念,并且写了3个伪码实例,现在总结一下它们的区别。
相同点:
1. 指针指向一块儿内存,它的内容是所指内存的地址;引用是某块内存的别名。
不同点:
1. 指针是一个实体,而引用仅是一个别名;
2. 引用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
4. 引用没有const,指针有const,const的指针不可改变;
5. 引用不能为空,指针可以为空;
6. “sizeof”引用获取的是所指向变量(对象)的大小;而指针获取的是指针本身(指针变量)的大小;
从性能来说,引用的性能肯定要比指针的性能要好(因为无需寻指操作)。
现在应该明白指针和引用的区别了吧。
(完)