精简版:

指针:变量,独立,可变,可空,替身,无类型检查;

引用:别名,依赖,不变,非空,本体,有类型检查;

完整版:

1. 概念

  指针从本质上讲是一个变量,变量的值是另一个变量的地址,指针在逻辑上是独立的,它可以被改变的,包括指针变量的值(所指向的地址)和指针变量的值对应的内存中的数据(所指向地址中所存放的数据)。

  引用从本质上讲是一个别名,是另一个变量的同义词,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化(先有这个变量,这个实物,这个实物才能有别名),而且其引用的对象在其整个生命周期中不能被改变,即自始至终只能依附于同一个变量(初始化的时候代表的是谁的别名,就一直是谁的别名,不能变)。

2. C++中的指针参数传递和引用参数传递

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

  引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。

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

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

3. 总结

相同点:

  都是地址的概念

不同点:

  指针是一个实体(替身);引用只是一个别名(本体的另一个名字)

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

  引用不能为空(有本体,才有别名);指针可以为空;

  sizeof 引用,得到的是所指向变量的大小;sizeof 指针,得到的是指针的大小;

  指针 ++,是指指针的地址自增;引用++是指所指变量自增;

  引用是类型安全的,引用过程会进行类型检查;指针不会进行安全检查;

1. 值传递

 1 void f( int  p){2     printf("\n%x",&p);3     printf("\n%x",p);4     p=0xff;5 }6 void main()7 {8     int a=0x10;9     printf("\n%x",&a);
10     printf("\n%x\n",a);
11     f(a);
12     printf("\n%x\n",a);
13 }

通过上例我们可以看到,int a=0x10,存放的地址为0x12ff44,值为10,当调用f(a)时,传递给p的值为10,但是p的地址为0x12fef4,当改变p=0xff,时是改变地址为0x12fef4中的内容,并没有改变0x12ff44中的内容,所以调用f(a),后a的值仍然为0x10,所以值传递无法改变变量的值。示意图如下:

2. 引用传递

 1 void f( int & p){2     printf("\n%x",&p);3     printf("\n%x",p);4     p=0xff;5 }6 void main()7 {8     int a=0x10;9     printf("\n%x",&a);
10     printf("\n%x\n",a);
11     f(a);
12     printf("\n%x\n",a);
13 }

通过上面引用传递传递案例我们可以看到,调用f(a)时,传递给p的是a的地址,所以p和a的地址都是0X12ff44,所以p就是a,改变p当然能改变a。示意图如下:

3. 指针传递

 1 void f( int*p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     f(&a);
13     printf("\n%x\n",a);
14 }

通过指针传递的案例我们可以看到,调用f(&a)是将a的地址0x12ff44传递给p,则*p就指向了a的内容,改变*p后,a的内容自然就改变了,示意图如下:

4. 指针的引用传递

 1 void f( int*&p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     int *b=&a;
13     printf("\n%x",&b);
14     printf("\n%x",b);
15     printf("\n%x\n",*b);
16     f(b);
17     printf("\n%x\n",a);
18 }

为了使用指针的引用传递我们要新建一个指针b,然后将b的引用传递给p,其实p就是b的一个拷贝,*p=*b都指向a,所以改变*p的内容也就改变a的内容。示意图如下:

我们再来看一下如果不用指针的引用传递会出现什么结果

 1 void f( int*p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     int *b=&a;
13     printf("\n%x",&b);
14     printf("\n%x",b);
15     printf("\n%x\n",*b);
16     f(b);
17     printf("\n%x\n",a);
18     printf("\n%x\n",b);
19 }

从结果中我们可以看到调用f(b)时,传递给p的是b的内容,但是&b,和&p是不一样的,虽然*p和*b都指向a。示意图如下:

作者: ZH奶酪——张贺 
Q Q: 1203456195 
邮箱: cheesezh@qq.com

精简版:

指针:变量,独立,可变,可空,替身,无类型检查;

引用:别名,依赖,不变,非空,本体,有类型检查;

完整版:

1. 概念

  指针从本质上讲是一个变量,变量的值是另一个变量的地址,指针在逻辑上是独立的,它可以被改变的,包括指针变量的值(所指向的地址)和指针变量的值对应的内存中的数据(所指向地址中所存放的数据)。

  引用从本质上讲是一个别名,是另一个变量的同义词,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化(先有这个变量,这个实物,这个实物才能有别名),而且其引用的对象在其整个生命周期中不能被改变,即自始至终只能依附于同一个变量(初始化的时候代表的是谁的别名,就一直是谁的别名,不能变)。

2. C++中的指针参数传递和引用参数传递

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

  引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。

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

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

3. 总结

相同点:

  都是地址的概念

不同点:

  指针是一个实体(替身);引用只是一个别名(本体的另一个名字)

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

  引用不能为空(有本体,才有别名);指针可以为空;

  sizeof 引用,得到的是所指向变量的大小;sizeof 指针,得到的是指针的大小;

  指针 ++,是指指针的地址自增;引用++是指所指变量自增;

  引用是类型安全的,引用过程会进行类型检查;指针不会进行安全检查;

1. 值传递

 1 void f( int  p){2     printf("\n%x",&p);3     printf("\n%x",p);4     p=0xff;5 }6 void main()7 {8     int a=0x10;9     printf("\n%x",&a);
10     printf("\n%x\n",a);
11     f(a);
12     printf("\n%x\n",a);
13 }

通过上例我们可以看到,int a=0x10,存放的地址为0x12ff44,值为10,当调用f(a)时,传递给p的值为10,但是p的地址为0x12fef4,当改变p=0xff,时是改变地址为0x12fef4中的内容,并没有改变0x12ff44中的内容,所以调用f(a),后a的值仍然为0x10,所以值传递无法改变变量的值。示意图如下:

2. 引用传递

 1 void f( int & p){2     printf("\n%x",&p);3     printf("\n%x",p);4     p=0xff;5 }6 void main()7 {8     int a=0x10;9     printf("\n%x",&a);
10     printf("\n%x\n",a);
11     f(a);
12     printf("\n%x\n",a);
13 }

通过上面引用传递传递案例我们可以看到,调用f(a)时,传递给p的是a的地址,所以p和a的地址都是0X12ff44,所以p就是a,改变p当然能改变a。示意图如下:

3. 指针传递

 1 void f( int*p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     f(&a);
13     printf("\n%x\n",a);
14 }

通过指针传递的案例我们可以看到,调用f(&a)是将a的地址0x12ff44传递给p,则*p就指向了a的内容,改变*p后,a的内容自然就改变了,示意图如下:

4. 指针的引用传递

 1 void f( int*&p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     int *b=&a;
13     printf("\n%x",&b);
14     printf("\n%x",b);
15     printf("\n%x\n",*b);
16     f(b);
17     printf("\n%x\n",a);
18 }

为了使用指针的引用传递我们要新建一个指针b,然后将b的引用传递给p,其实p就是b的一个拷贝,*p=*b都指向a,所以改变*p的内容也就改变a的内容。示意图如下:

我们再来看一下如果不用指针的引用传递会出现什么结果

 1 void f( int*p){2     printf("\n%x",&p);3     printf("\n%x",p);4     printf("\n%x\n",*p);5     *p=0xff;6 }7 void main()8 {9     int a=0x10;
10     printf("\n%x",&a);
11     printf("\n%x\n",a);
12     int *b=&a;
13     printf("\n%x",&b);
14     printf("\n%x",b);
15     printf("\n%x\n",*b);
16     f(b);
17     printf("\n%x\n",a);
18     printf("\n%x\n",b);
19 }

从结果中我们可以看到调用f(b)时,传递给p的是b的内容,但是&b,和&p是不一样的,虽然*p和*b都指向a。示意图如下:

作者: ZH奶酪——张贺 
Q Q: 1203456195 
邮箱: cheesezh@qq.com 
出处: http://www.cnblogs.com/CheeseZH/ 
* 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

出处: http://www.cnblogs.com/CheeseZH/ 
*本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

C++中值传递、引用传递与指针传递的区别相关推荐

  1. C++ 中的:“引用” 和“取地址符”的区别和作用

    引用 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样. &作为引用的时候,必须在定义时候就进行初始化,若不进行初始化则会编译报错. int N; int &r ...

  2. 在c语言中文件的指针是什么,C语言中文件描述符和文件指针的本质区别

    1,首先了解进程运行时默认打开的文件指针以及打开的文件 /* Standard streams. / extern struct _IO_FILE stdin; / Standard input st ...

  3. C++ 值传递、指针传递、引用传递

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105113129 值 ...

  4. c++值传递,指针传递,引用传递以及指针与引用的区别

    值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入, 不能传出.当函数内部需要修改参数,并且不希望这个改变影 ...

  5. 值传递,引用传递,指针传递

    一.值传递.引用传递及指针传递         1    值传递 不能改变实参变量的值 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形参 ...

  6. 值传递,指针传递,引用传递

    而关于值传递,指针传递,引用传递这几个方面还会存在误区, 所有我觉的有必要在这里也说明一下~ 下文会通过例子详细说明哦 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角 ...

  7. C++ 值传递、指针传递、引用传递详解

    值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入, 不能传出.当函数内部需要修改参数,并且不希望这个改变影 ...

  8. C专家编程--指针和数组(三) 值传递 指针传递 引用传递

    可以先看下这两篇文章 http://blog.csdn.net/yusiguyuan/article/details/12357381 http://blog.csdn.net/yusiguyuan/ ...

  9. PHP 怎样理解go指针,golang指针传递和值传递的区别是什么?

    Go允许通过指针(有时称为引用)和值来传递参数.在这篇文章中,我们将比较两种方法,特别注意可能影响选择的不同情境. 指针传递与值传递 严格地说,go方法或函数只有一种传递方式,那就是值传递.每次将一个 ...

  10. 引用和指针的区别?传引用比传指针安全,为什么?如果我使用常量指针难道不行吗?

    引用和指针的区别 (1) 引用在创建的同时必须初始化,即引用到一个有效的对象:而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值. (2) 不存在NULL引用,引用必须与合法的存储单元关联 ...

最新文章

  1. 滴滴AI负责人叶杰平:你的每一次出行,都已有AI落地的助力 | MEET 2020
  2. 查看linux显示文件大小,Linux下查看占用最大的文件和文件夹大小
  3. js之数据类型及类型转换
  4. idea无法启动Tomcat
  5. Microsoft SQL Server Desktop Engine安装过程中遇到的问题(2)
  6. RF工具ride使用
  7. 【工具分享】AWVS 13 Linux版
  8. 矩阵分析与应用(二)————梯度分析与最优化
  9. 简单二阶有源滤波电路分析
  10. VBA实战(7) -字典(Dictionary)
  11. 【⚠️windows删除文件夹抽风了⚠️】“错误0x80070091:目录不是空的”问题处理
  12. 亿发软件:中大型仓库进出货管理系统解决方案,定制软件让仓储作业高效便捷
  13. Nodejs base64编码与解码
  14. spss分析方法-多个独立样本检验(转载)
  15. 堆在计算机中的作用,堆(数据结构)_百度百科
  16. 普通石粉的用途_“石粉”的多种用途
  17. hpe服务器自动启动关闭,HPE服务器设置U盘启动安装
  18. 熊猫烧香专杀工具的编写
  19. 【产品经理】身为产品经理的你,该如何持续改进产品?
  20. 在 Android 系统源码中自定义系统服务(Custom System Service in AOSP)

热门文章

  1. arecord录制音频和aplay播放音频用法说明
  2. 吉富营:如何在互联网上赚钱的门道
  3. 移动端浮层scroll时,禁止后面的网页也scroll的解决方法
  4. 高等数学(第七版)同济大学 习题7-1 个人解答
  5. Oracle数据库习题整理
  6. 国内国外主流的CMS
  7. 【d3dx9_42.dll下载】d3dx9_42.dll如何修复
  8. Eclipse+多国语言包插件+Tomcat插件+Lomboz插件+Myeclipse插件的安装与配置
  9. 【数据结构导论】第 1 章:概论
  10. Part1:使用 TensorFlow 和 Keras 的 NeRF计算机图形学和深度学习——计算机图形学世界中相机的工作原理