概念

   首先从概念上来说一下这几种函数传参方式及区别:
   1、值传递:形参是实参的拷贝,改变函数形参的值并不会影响外部实参的值,这是最常用的一种传参方法,也是最简单的一种传参方法,只需要传递参数,返回值那是return考虑的;
   2、指针传递:指针传递参数从本质上来说也是值传递,它传递的是一个地址。【值传递过程中,被调函数的形参作为被调函数的局部变量来处理,即在函数内的栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成了实参的一个副本(记住这个,函数内参数的是实参的副本)】。由于指针传递的是外部实参的地址,当被调函数的形参值发生改变时,自然外部实参值也发生改变。
   3、引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是栈中存放的是由主调函数放进的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中实参变量(实参和形参通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会详细说)。因此,形参的任何改动都会直接影响到实参。

实例

先从简单的例子开始:
  1. 值传递:例子略过。
  2. 指针传递:
  1. void swap(int *a,int *b)
  2. {
  3. int temp;
  4. temp=*a;
  5. *a=*b;
  6. *b=temp;
  7. cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;
  8. cout<<"*a=" <<*a<<" ,"<<"*b="<<*b<<endl;
  9. cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;
  10. }
(刚上大学的时候就接触过的例子,交换值)调用:
  1. int main(){
  2. int x=1;
  3. int y=2;
  4. cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;
  5. cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;
  6. swap(&x,&y);
  7. }
一定要记住这种调用方式

  1. swap(&x,&y);

如指针传递的概念上所述,传地址给形参。

形如:int *a = &x;//用于指针传递,a有自己独立的内存地址,存储的内容是x的地址,*a是存x的值。
输出结果:

传入值的各变量的初始状态(地址状态):
               
从上图关系可以知道:a(b)是一个指向外部实参地址的指针,*a(*b)是指针的内容,如果改变了*a(*b)也必然导致外部实参的改变。
 
交换后:
       *a=2,*b=1;
       
       
这样的结果是由于a或者b指针指向x或者y的地址的缘故,因此由于*a,*b值得交换导致外部实参发生变化。
 
 
        思考一下,下面的操作能否实现值得变化?
        简单测试代码:

  1. int change(char* name){
  2. cout<<"*******CHANGE--BEFORE******"<<endl;
  3. cout<<"name=" <<name<<endl;
  4. cout<<"*name=" <<&name<<endl;
  5. name="alter";
  6. cout<<"*******CHANGE--AFTER********"<<endl;
  7. cout<<"name=" <<name<<endl;
  8. cout<<"*name=" <<&name<<endl;
  9. return 1;
  10. }
  11. int main()
  12. {
  13. char *str = "this is a test";
  14. cout<<"******MAIN--BEFORE*****"<<endl;
  15. cout<<"str=" <<str<<endl;
  16. cout<<"*str=" <<&str<<endl;
  17. change(str);
  18. cout<<"*****MAIN--AFTER*****"<<endl;
  19. cout<<"str=" <<str<<endl;
  20. cout<<"*str=" <<&str<<endl;
  21. return 1;
  22. }

执行结果:(打印的输出的时候,有点错误,*str应该为 &str)

    从结果中发现,并未达到改变值得效果,为什么?这个测试代码和本文开始的疑问是一样的,那就进一步分析:
    
    传入值的各变量的初始状态(地址状态):
     
   执行赋值操作

  1. name="alter";
    系统首先需要给字符串“alter”分配内存空间(地址),然后指针才指向其地址。
       
 
 所以*str并没有发生变化,因此最后打印出来的仍是“this is a test”,这也解释了我开始时的迷惑!
 
另一种成功传递参数的指针调用方法----指针的指针:

  1. void my_malloc(void** p, int size)
  2. {
  3. *p = malloc(sizeof(int)*size);
  4. }
  5. int main()
  6. {
  7. int *a;
  8. my_malloc(&a , 10);
  9. return 1;
  10. }
执行结果:(有些参数没有用,只是为了打印出来看看)
当我们没有执行到给*p分配空间的时候:
执行malloc(size) 后的图如下:
 
   赋值给*p后:由于p指向&a即a的地址,*p则指向a的地址里的值,现在又要把分配的内存指向*p,所以,a的值即为新分配的内存!(这个比较难转圈
   
    
    然后,我们就给指针a 分配内存成功了。
     3、引用传递:

  1. void swapref(int &a,int &b)
  2. {
  3. cout << "******************before swapref:******************"<<endl;
  4. cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;
  5. cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;
  6. int temp;
  7. temp=a;
  8. a=b;
  9. b=temp;
  10. cout << "******************after swapref:******************"<<endl;
  11. cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;
  12. cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;
  13. }
  14. int main(){
  15. int x=1;
  16. int y=2;
  17. cout<<"******MAIN--BEFORE*****"<<endl;
  18. cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;
  19. cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;
  20. //swap(&x,&y);
  21. swapref(x, y);
  22. cout<<"*****MAIN--AFTER*****"<<endl;
  23. cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;
  24. cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;
  25. }
一定要记住这种调用方式

  1. swapref(x, y);
形如:int &a=x; //用于引用传递,可以理解为a就是x,x就是a,只不过名字不一样

执行结果:

    这个具体就不分析了,记住引用传递实参和形参是一样的,只是名字不同而已。
 
 
总结:
       本文重点还是在参数传指针方面,指针确实令人头疼,今天遇到了,会出错,弄明白以后,等过段时间,又忘了,又遇到错误,再来看,这样不断反复,希望能不断的提升,对指针的认识不断的加深!
       写了一下午,边琢磨、边参考、边实验,希望对你有用!错误之处敬请见谅!
 

c++中函数参数传递(值传递、指针传递,引用传递)进一步认识的更多相关文章

  1. C语言中函数参数传递

    C语言中函数参数传递的三种方式 (1)值传递,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对形参的改变不会影响到函数外的变量的值.(2)地址传递,就是把 ...

  2. Java 为值传递而不是引用传递

    ——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...

  3. 【Qt】信号和槽对值传递参数和引用传递参数的总结

    在同一个线程中 当信号和槽都在同一个线程中时,值传递参数和引用传递参数有区别: 值传递会复制对象:(测试时,打印传递前后的地址不同) 引用传递不会复制对象:(测试时,打印传递前后的地址相同) 不在同一 ...

  4. java是值传递,还是引用传递?

    原文地址:http://blog.csdn.net/zxmzfbdc/article/details/5401960  java到底是值传递,还是引用传递?以前国内的java开发者有过很多争论,由于& ...

  5. python关于入参中,传入的是指针还是引用

    偶然看到别人的代码,发现有的会传入参数之后,做一次copy,试验一下,关于入参中,传入的是指针还是引用先说自己的结论:1.如果传入的是简单的类型,那么传入应该是引用的数值,2.假如传入的是df这种类型 ...

  6. C语言中函数参数传递的本质是值传递

    数组名做函数参数进行传递时,实际上是是一份该指针的拷贝. 给形参赋予其他值,并不影响实参的值. 类似于: int *p = a;    //a为数组名 p = b;          //b为数组名 ...

  7. c语言 函数传输传递的三种方式(值、指针、引用)

    本文摘自<彻底搞定c指针> 一.三道考题开讲之前,我先请你做三道题目.(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?)考题一,程序代码如下:void Exchg1(int x, in ...

  8. java中的参数传递——值传递、引用传递

    参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递. 在 Java 应用程序中永远不会传递对象,而只传递对象引用.因此是按引用传递对象.Java 应用程序按引用 ...

  9. java中函数是值传递还是引用传递?

    相信有些同学跟我一样,曾经对这个问题很疑惑.在网上也看了一些别人说的观点,评论不一.有说有值传递和引用传递两种,也有说只有值传递的,这里只说下个人见解 先看一个例子 public class Test ...

随机推荐

  1. GDI+绘制图形和画刷填充图形

    GDI+可以再Windows窗体应用程序中以编程方式绘制图形等. 可以在VS里新建项目-Windows窗体应用程序-建一个窗体.首先引入命名空间using System.Drawing.Imaging ...

  2. Servlet 3.0 介绍

    1. 概述 注解代替 web.xml 配置文件 异步处理 对上传的支持 2. 注解代替 web.xml 配置文件 使用方法 在 Servlet 类上添加 @WebServlet(urlPatterns ...

  3. 如何搭建一个 Git 版本控制服务端?

    Gogs 下载和安装 https://github.com/gogits/gogs # 下载二进制压缩包 不检查服务器证书 root@cheungxiongwei:~# wget --no-check ...

  4. maven的安装以及查看是否安装成功

    Maven安装教程详解   一.准备工作 1.确定电脑上已经成功安装jdk7.0以上版本 2.win10操作系统 3.maven安装包            下载地址:http://maven.apa ...

  5. spring 项目tomcat 8.0.2 发布报错:Could not initialize class org.hibernate.validator.engine.ConfigurationImpl

    tomcat 8 项目发布遇到的错 [ERROR] -- ::, org.springframework.web.servlet.DispatcherServlet - Context initial ...

  6. orange安装文档

    一.Orange简介    Orange是一个基于 OpenResty/Nginx 的 API Gateway,提供 API 及 “自定义规则” 的监控和管理,如访问统计.流量切分.AB 测试.API ...

  7. seaborn(matplotlib)画图,linux系统中文乱码等问题解决

    data = pd.read_json(json.dumps(issue_dpl)) # set pic size plt.figure(figsize=(13, 5)) sns.set_style( ...

  8. Python API:openstack

    OpenStack 是一个越来越流行的.用于部署基础架构即服务 (IaaS) 云的开源解决方案.OpenStack 附带了一个仪表板 Web 应用程序,非常适合执行手动任务,比如启动单个虚拟机 (VM ...

  9. MVC4 中使用 Area 和 注意的地方

    在MVC项目中经常会使用到Area来分开不同的模块让项目结构更加的清晰. 步骤如下:  项目 –> 添加 -> 区域 (Area)  输入 Admin 添加成功后 Area包含:创建一个空 ...

  10. try catch 事务不会滚

    在spring机制中,在配置事务后,如果采用try catch 捕获异常后,因为异常已经被捕获,所以事务不会滚,从而产生许多脏数据.解决办法: 1.在catch中抛出异常,(throw new Run ...