C++入门篇之值传递,指针传递和引用传递的那些事

      最近在自学C++,一边学习一边在心里将C++与C语言和Java进行比较。毫无疑问,作为以C语言为基础,和C语言同一个爹的一门编程语言,C++自然与C原因有很多相似之处,例如C++的变量传递就沿用了C语言中的值传递和指针传递两种。此外,C++还引入了一种新的传递方式——引用传递。下面我们将来探讨一下C++的这三种变量传递方式的本质。

1. 值传递

	int x = 1;
	int y = x;
	cout << "y=" << y << endl;
	cout << "&y=" << &y << endl;
	cout << "&x=" << &x << endl;
        以上是使用C++编写的一段代码,学过C语言的朋友应该很容易猜到结果:

           在上述运行结果中,我们可以看到y=1,但是x和y的地址却不相同,这说明x和y不是同一个变量。于是,我们得出结论,值传递的本质是在内存中开辟一块区域y,对变量x生成一个副本并保存在y中,为变量y。

2. 指针传递

	int x = 1;
	int *y = &x;
	cout << "*y=" << *y << endl;
	cout << "y=" << y << endl;
	cout << "&x=" << &x << endl;

           上述C++代码使用的y是指针,并将其指向变量x。运行的结果如下:

            我们可以看到,*y的值和x是一样的,而y的内容则是和x的地址一致,这说明了,C++中的指针和C语言的是一样的,指向一个变量,其在内存中保存的·1是所指变量在内存中的地址。

3. 引用

        好,前面简单地说了一下C++中的值传递和指针传递两中传递形式,下面就来讲一下C++新引入的一种传递方式——引用。

           简单地说,引用的本质有点类似指针,但使用却和值传递一样。

	int x = 1;
	int &y = x;
	cout << "y=" << y << endl;
	cout << "&y=" << &y << endl;
	cout << "&x=" << &x << endl;

         这是C++中使用引用的代码,我们可以看到引用的声明方法就是在变量名前加一个'&',然后其使用就跟普通的变量一样。我们来看一下运行结果:

        我们可以看到,y=1,而且x和y的地址竟然一模一样!这意味着,引用不会产生一个新的副本,而是指向所引用的变量,这一点和指针是一致的!既然如此,那么我们改变引用的值,原变量会不会改变呢?答案是一定的,如上例,引用y和变量x使用的是同一块内存空间,那么改变引用y的值,势必也会改变x的值!简单地说,引用就是给变量起一个别名!

        说到这里,可能有人会问,那引用和指针除了使用上有区别,还有毛线区别啊!答案是“用适当的工具做恰如其分的事情”。为什么这样说,因为引用的优势及其与指针的区主要是体现在函数的参数传递和返回值上的,而正是这些优势使得引用的存在有了其必要性。下面来简单说说引用于指针的区别。

1. 引用在声明的时候就必须初始化(指针任何时候都可以初始化);

2. 不能有NULL引用(指针可以指向NULL);

3. 引用一旦被初始化,就不能改变引用的关系(指针任何时候都可以改变所指的对象)。

	int a = 1;
	int &k = a;
	int j = 2;
	k = j;
        上述程序中的最后一句k = j并不是将k的引用改为j,而是将k的值,也就是a的值改成2,k和a的引用关系不变。 这看起来像是在玩文字游戏,没有体现出引用的价值。正如上面所说,引用的优势体现在函数参数传递和返回值上。我们继续举个栗子:

void exchange(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
        这是一个以引用作为参数的交换函数,学过C的朋友也肯定知道,在C中实现这样一个功能需要使用指针。加入我们使用指针来实现的话,那么exchange函数中的形参a和b也应该是一个指针,在调用这个函数的时候传入的实参会产生一个副本传递给exchange函数的形参,这需要一个拷贝过程。好像有点难以理解对吧,没事,我们看代码:

void exchange(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
        上述代码是使用指针来实现的exchange函数,加入我们这样来调用它:exchange(a, b)。其中a和b都是一个int型指针,那么参数传递过程是这样的:exchange函数的形参在编译的时候会变成 int *_a, int *_b,所以参数传递实质上是 _a = a, _b = b,于是这个过程就相当于exchange函数在栈中开辟了两块区域,分别为 _a和_b,然后将a和b的内容拷贝过去。

        而使用引用则可以免去了这个过程。为什么?正如前面所说,引用的本质就是给变量起一个别名,引用者和被引用者其实都是同一个东西,既然是同一个东西,又怎么会存在拷贝这个过程了,因此在exchange函数中直接给a和b赋值也是可以的。这就是引用的价值——在函数参数传递的时候省去了拷贝这一过程!

        引用在函数返回值上的价值也是类似的。下面简单的讲述一下C语言中函数返回值的处理过程:
1. 值传递:

        将变量的值拷贝到存储函数返回值的内存中,然后由接收函数返回值的变量接收这个值,这里就由存在着拷贝过程。

2.  指针传递:

        此处假设指针所指向的内存是动态分配的,那么返回指针的实质就是将指针所存储的地址值拷贝出来,存储到接收该值的指针中,这也存在着拷贝过程。

        于是,如果我们使用引用传递的话,因为可以省去这个拷贝过程,自然也能使函数的效率有所提高。但是,返回引用和返回指针一样有一个需要注意的地方,就是不能返回局部变量(栈变量)的引用/指针,因为局部变量在函数结束后就会自动消亡。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值