传指针和传指针引用的区别/指针和引用的区别(本质)

转自:http://blog.sina.com.cn/s/blog_673ef8130100imsp.html

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址(int &a的形式)。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

最后,总结一下指针和引用的相同点和不同点:

★相同点:

●都是地址的概念;

指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

★不同点:

●指针是一个实体,而引用仅是个别名;

●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

●引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有     的,  前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)

●引用不能为空,指针可以为空;

●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

●指针和引用的自增(++)运算意义不一样;

●引用是类型安全的,而指针不是 (引用比指针多了类型检查

一、引用的概念

引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
例如: Point pt1(10,10);
Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
pt1.offset(2,2);
pt1和pt2都具有(12,12)的值。
引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
初始化它。例如下面语句是非法的:
Point &pt3;
pt3=pt1;
那么既然引用只是某个东西的同义词,它有什么用途呢?
下面讨论引用的两个主要用途:作为函数参数以及从函数中返回左值。

二、引用参数

1、传递可变参数
传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。
所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现
两整数变量值交换的c程序如下:
void swapint(int *a,int *b)
{
int temp;
temp=*a;
a=*b;
*b=temp;
}

使用引用机制后,以上程序的c++版本为:
void swapint(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。

2、给函数传递大型对象
当大型对象被传递给函数时,使用引用参数可使参数传递效率得到提高,因为引用并不产生对象的
副本,也就是参数传递时,对象无须复制。下面的例子定义了一个有限整数集合的类:
const maxCard=100;
Class Set
{
int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素个数的最大值。
int card; // 集合中元素的个数。
public:
Set () {card=0;} //构造函数
friend Set operator * (Set ,Set ) ; //重载运算符号*,用于计算集合的交集 用对象作为传值参数
// friend Set operator * (Set & ,Set & ) 重载运算符号*,用于计算集合的交集 用对象的引用作为传值参数
...
}
先考虑集合交集的实现
Set operator *( Set Set1,Set Set2)
{
Set res;
for(int i=0;i<Set1.card;++i)
for(int j=0;j>Set2.card;++j)
if(Set1.elems[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}
由于重载运算符不能对指针单独操作,我们必须把运算数声明为 Set 类型而不是 Set * 。
每次使用*做交集运算时,整个集合都被复制,这样效率很低。我们可以用引用来避免这种情况。
Set operator *( Set &Set1,Set &Set2)
{ Set res;
for(int i=0;i<Set1.card;++i)
for(int j=0;j>Set2.card;++j)
if(Set1.elems[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}

三、引用返回值

如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:
double &max(double &d1,double &d2)
{
return d1>d2?d1:d2;
}
由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:
max(x,y)+=1.0;

注:int &a中的&本质就是“取地址”运算,在函数void swapint(int &a,int &b)中,&a要看成一个整体,看成是x的地址,故a就是x本身了

有区别,  
  无论你传值还是传指针,函数都会生成一个临时变量,  
  但传引用时,不会生成临时变量,  
   
  当你传值时,只可以引用值而不可以改变值,但传值引用时,可以改变值,  
  当你传指针时,只可以改变指针所指的内容,不可以改变指针本身,但传指针引用时,既可以改变指针所指的内容,又可以改变指针本身,  
   
  但传引用主要是它不生成临时变量,不进行返回值copy等,速度快。

数据结构的二叉排序树中有典型应用..

注:简单一点可以这么想,如果不用引用的话,被传递的参数本身是不能被修改的,  
  即使你传递的是指针,也只能修改指针指向的内容,不能修改指针本身。  
  如果要修改当前被传递的参数的话,要么再加一级指针,要么用引用。

原文地址:https://www.cnblogs.com/tsh292278/p/10318002.html

时间: 2024-08-07 13:23:30

传指针和传指针引用的区别/指针和引用的区别(本质)的相关文章

关于函数传参--传指针,传引用

今天和同学讨论到指针和引用的传递问题,有些想法从推理上讲是正确的,但是因为是推理,说出自己观点的时候不是那么有底气,本着实践是检验真理的唯一标准的原则,在电脑上敲了几段代码,验证了推理的正确性. 先上代码,再分析. 代码1: void Swap0(int a1,int b1){ int temp; temp=a1; a1=b1; b1=temp; } void Swap1(int *a1,int *b1){ //交换地址 int *temp; temp=a1; a1=b1; b1=a1; } v

C语言结构体,C语言结构体指针,java对象引用,传值,传地址,传引用

C语言结构体,C语言结构体指针,java对象引用,传值,传地址,传引用 传值 把实参的值赋值给行参 那么对行参的修改,不会影响实参的值 传地址 传值的一种特殊方式,只是他传递的是地址,不是普通的如int 那么传地址以后,实参和行参都指向同一个对象 传引用 真正的以地址的方式传递参数 传递以后,行参和实参都是同一个对象,只是他们名字不同而已 对行参的修改将影响实参的值 所谓变量是内存地址的一个抽象名字,在静态编译的程序中,所有变量名都会在编译时转换成内存地址,机器不知道变量名,只知道地址. C 语

malloc与new,C++中的指针与引用,C++struct与class的区别

一.struct与class的区别 1. struct与class的区别不大 在默认情况下,class默认的权限是private(私有的),struct默认的是public(共有的). 2.但是在C++中,struct进行了扩展,现在它已经不仅仅是一个包含不同数据类型的数据结构了,它包括了更多的功能. 二 .malloc与new,delete与free的区别 1.malloc与free是库函数里的函数,调用时要添加头文件,delete与new是C++中的运算符 2.malloc返回值是void*

内存(传值、传址、传引用)

前言: 最近对内存产生了兴趣.全是因为马士兵老师的一句Master key.马上要考二级了.大题构造函数比较多.形参有 int & x  这么写的.也有int *x 这么写的.还有普通 int x这么写的.我的乖乖这都是传的什么? int x 是 传值.int *x  是传址. int & x是传引用.那这三者传参数都有什么区别呢? 下面就用三个例子讲解 声明:下面堆栈的图其实是不正确的.八个基本类型(byte.short.int.long.char.float.double.boolea

引用,引用形参,指针形参与指向指针的引用形参,内存泄露及free相关

由做UVa133引发的一系列问题及讨论 1.引用类型    C++ Primer P51 引用就是对象的另一个名字,使用多个变量名指向同一地址.实际程序中,引用主要用作函数形参. 复合类型.不能定义引用类型的引用,但可以定义任何其他类型的引用. 格式: 类型名&  标示符=已声明的常变量; 2.引用形参    C++ Primer P201-205 非引用形参有普通的.指针形参.const形参(可传const对象或非const对象) 引用形参,3种情形:@修改实参,或返回多个值  @避免复制大型

Go语言的传参和传引用[转]

目录[-] 传参和传引用的问题 传slice不是传引用! 什么叫传引用? 为什么传slice不是传引用? 为什么很多人误以为slice是传引用呢? 传指针和传引用是等价的吗? 所有类型的函数参数都是传值的! 那Go语言有传引用的说法吗? 什么是引用类型, 和指针有何区别/联系 ? 总结 传参和传引用的问题 很多非官方的文档和教材(包括一些已经出版的图书), 对Go语言的传参和引用的讲解 都有很多问题. 导致众多Go语言新手对Go的函数参数传参有很多误解. 而传参和传引用是编程语言的根本问题, 如

C++中引用传递和指针传递函数参数的详解

先来分析指针这个东东: 从概念上讲,指针本质上就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 上面的图表示了程序运行时变量的值和地址,这时的内存长什么样子呢? 注意指针是一个变量,它当然有内存空间,里面存的就是一个地址,通过这个地址我们就能找到它所指向的对象. 说明:上图中两个字母p和n在最左边,代表什么?后面在介绍程序的编译过程中用到,先卖个官司.如果下面的写的东西你看不懂,没关系,往下看,我不相信你看完最后的编译原理的

Android的引用计数(强弱指针)技术及一些问题

Android C++框架层的引用计数技术 C++中对指针的使用时很头疼的事情,一个是经常会忘记free 指针,造成内存泄露,另外一个就是野指针问题:访问已经free掉的指针.程序debug工作的相当大部分,都是花费在这.Android中通过引用计数来自动管理指针的生命周期,动态申请的内存将会在不再需要时被自动释放(有点类似Java的垃圾回收),不用程序员明确使用delete来释放对象,也不需要考虑一个对象是否已经在其它地方被释放了,从而使程序编写工作减轻不少,而程序的稳定性也大大提高. And

引用计数智能指针

<a>C++ <span style="font-family:宋体;">智能指针具体解释</span></a> 一.简单介绍 因为 C++ 语言没有自己主动内存回收机制.程序猿每次 new 出来的内存都要手动 delete. 程序猿忘记 delete.流程太复杂.终于导致没有 delete.异常导致程序过早退出,没有运行 delete 的情况并不罕见. 用智能指针便能够有效缓解这类问题,本文主要解说參见的智能指针的使用方法.包含:std