在使用Go和C语言之前总是拿引用传递和值传递比较,很少拿引用传递和指针传递进行比较。今天跟一位同事讨论指针和引用的区别时,当时也比较发懵,不知道它们到底有什么区别? 后来查看资料之后,终于知道它们之间的区别了。现在趁着热乎劲儿,赶紧整理一下。

        在比较它们之间区别之前,先来说说什么是指针?

#include<stdio.h>

int main(void)
{
	int num = 7;
	int *p = &num;	// 初始化指针
	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 = &num;

	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 = &num;
	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”引用获取的是所指向变量(对象)的大小;而指针获取的是指针本身(指针变量)的大小;

        从性能来说,引用的性能肯定要比指针的性能要好(因为无需寻指操作)。

        现在应该明白指针和引用的区别了吧。

(完)