c++引用和指针的区别

                            相信看了这篇博客,你会对c++的参数传递有更深的了解

1、按值传递

简单来说,在给一个函数传递参数时,该函数获得的参数只是你传递的参数的副本,彼此之间分开存储,不共享一片内存。

举个例子

void swap(int x,int y)
{
    int temp=x;
    x=y;
    y=temp;
}
int main()
{
    int a=3;
    int b=4;
    swap(a,b);
    cout<<"a="<<a<<", b="<<b<<endl;
}
结果输出"a=3, b=4"。

显然,swap函数并没有起到作用,为什么呢?因为在调用swap(a,b);的时候,传递swap函数的形参x和y的并不是a和b本身,而是存储在另一个地方的a和b的值,通俗地讲,也就是a和b的值的副本。你无法通过对副本的操作去改变本体。

编译后的汇编代码

	call	___main
	movl	$3, -12(%ebp)
	movl	$4, -16(%ebp)
	movl	-16(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	-12(%ebp), %eax
	movl	%eax, (%esp)
	call	__Z4swapii

	subl	$16, %esp
	movl	8(%ebp), %eax
	movl	%eax, -4(%ebp)
	movl	12(%ebp), %eax
	movl	%eax, 8(%ebp)
	movl	-4(%ebp), %eax
	movl	%eax, 12(%ebp)

在底层上,a和b存储在内存中,在调用swap函数的之前,main函数会把a和b的值的压入栈中,接着调用swap函数,swap函数便可以拿栈中的值进行运算,swap函数返回后,控制又回到main函数上。栈中的a和b的值交换,并不会改变存储在内存中a和b本身的值。


2、指针传递

简单来说,在给一个函数传递参数的时候,该函数获得的是你传递参数的地址的值,任何对该地址的操作,都会引起参数的改变。

举个例子

void swap(int *x,int *y)
{
    int temp=*x;
    *x=*y;
    *y=temp;
}
int main()
{
    int a=3;
    int b=4;
    swap(&a,&b);
    cout<<"a="<<a<<", b="<<b<<endl;
}
结果输出"a=4, b=3"。

swap函数起作用了,来看看发生了什么,传递给swap函数的形参x和y的是参数a和b的地址,而swap函数直接对两个参数的地址进行解引用,意味着直接在存储a和b的内存上改变a和b的值,所以main函数中a和b的值会发生改变。

在底层上,指针传递的实现和按值传递的实现几乎是一样的,不同的是指针传递是main函数把a和b的地址压入栈中,而按值传递是main函数把a和b的值压入栈中,前者调用的函数拿到的是参数的地址,后者调用的函数拿到的仅仅是参数的值,而且该值存储在与参数存储内存不一样的地方,仅仅是一个副本。


3、引用传递

简单来说,引用传递在底层上的实现跟指针传递是一样的,但C++为引用传递添加了一点东西,使得引用传递有自己的特点。

1)、当引用被创建时,它必须被初始化(指针则可以在任何时候被初始化)

2)、一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用(指针则可以在任何时候指向另一个对象)。

3)、不可能有NULL引用。必须确保引用是和一块合法的存储单元关联(指针可以置为NULL)。


下面的汇编代码对应上面指针传递的main函数代码,也对应于上面引用传递的的main函数代码,两者的产生的汇编代码是等价的。

	call	___main
	movl	$3, -28(%ebp)
	movl	$4, -32(%ebp)
	leal	-32(%ebp), %eax
	movl	%eax, 4(%esp)
	leal	-28(%ebp), %eax
	movl	%eax, (%esp)
	call	__Z4swapRiS_

	subl	$16, %esp
	movl	8(%ebp), %eax
	movl	(%eax), %eax
	movl	%eax, -4(%ebp)
	movl	12(%ebp), %eax
	movl	(%eax), %edx
	movl	8(%ebp), %eax
	movl	%edx, (%eax)
	movl	12(%ebp), %eax
	movl	-4(%ebp), %edx
	movl	%edx, (%eax)

举个例子

void swap(int &x,int &y)
{
    int temp=x;
    x=y;
    y=temp;
}
int main()
{
    int a=3;
    int b=4;
    swap(a,b);
    cout<<"a="<<a<<", b="<<b<<endl;
}
结果输出"a=4, b=3"。

本质上,引用传递在底层上和指针传递的实现方式是一样的,我们可以认为引用仅仅是语法上的一种不同方法(有时称为“语法糖”)。什么是语法糖,举个例子,a[i]和*(a+i)本质上是一样的,但a[i]的可读性更强,比*(a+i)更加直观容易理解,语法糖使得程序更加不容易出错。

同样的,引用传递虽然在底层的实现上和指针传递一样,但是从语言来说,引用不等于指针,因为c++给引用赋予了一些特性,这些特性使得引用传值在某些方面比指针传值要好,比如你不必担心参数是否被初始化了(编译器强迫它初始化),也不必知道怎样对它间接引用(这由编译器做)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值