在C/C++语言中值传递、指针传递和引用传递(C++ only)这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把这三种方式描述清楚。没时间看分析的直接看简述就可以了。

简述

值传递就是最普通的传递方式,比如函数定义为fun(int a),在调用的地方有int x=6, 使用fun(x)就可以了。这种方式在fun(int a)函数内部的对a的修改 不能 导致外部x的变化。
指针传递其实也就是地址传递,函数定义为fun(int *a),形参为指针,这就要求调用的时候传递进去一个参数的地址,例如int x=6; fun(&x)。 这种方式在fun(int a)函数内部的对a的修改 导致外部x的变化。
引用传递只有C++支持,相比前两种方式用的比较少,但也非常有用。引用传递函数定义为fun(int &a),这里&符号是引用而不是取地址的意思,调用方式和值传递类似,例如int x=6; fun(x)。 但是这种方式在fun(int a)函数内部的对a的修改 导致外部x的变化。

表格是一种比较直接的表达方式,列个表格可以对这三种方式一目了然,假设调用fun函数之前都有定义int x=6,这三种方式异同如下表所示:

传递方式 函数定义 函数调用 函数内对a修改的影响
值传递 fun(int a) fun(x) 外部x不变
指针传递 fun(int *a) fun(&x) 外部x同步更改
引用传递(C++) fun(int &a) fun(x) 外部x同步更改

分析

下面三部分代码都尝试在swap函数内对输入参数进行数值交换,通过打印其数值和指针来分析。

值传递

函数内部使用这个参数,对这个参数的修改对函数外的原始数据不起作用。

示例:

#include <stdio.h>void swap(int a, int b){printf("swap enter\n");printf("a = %d, ptr = %p\n", a, &a);printf("b = %d, ptr = %p\n", a, &b);int tmp = b;b = a;a = tmp;printf("a = %d, ptr = %p\n", a, &a);printf("b = %d, ptr = %p\n", b, &b);printf("swap leave\n");
}int main() {int x = 1;int y = 2;printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);swap(x, y);printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);return 0;
}

运行结果:

x = 1, ptr = 000000000022FE4C
y = 2, ptr = 000000000022FE48
swap enter
a = 1, ptr = 000000000022FE20
b = 1, ptr = 000000000022FE28
a = 2, ptr = 000000000022FE20
b = 1, ptr = 000000000022FE28
swap leave
x = 1, ptr = 000000000022FE4C
y = 2, ptr = 000000000022FE48

结果表明:
swap函数内部a b的数值进行交换,但是没有影响到x y的值。swap函数形参a b所指向的内存地址和外部x y的地址不一样。
实质:
swap为形式参数 a b创建了内存空间,main函数调用swap函数的时候,把x y的值copy给新创建的 a ba bx y分别在不同的内存位置中,因而对这个新创建的 a b 操作不会影响外部的 x y的值。

带有返回值的函数,比如int fun(){int x=7; return x},外部调用方式为int a=fun();,这时是把x的数值copy了一份给外部a所在的内存空间,并释放了x所在的内存空间(系统自动分配的栈内存),在fun函数调用后即使知道x的内存地址也可能取不到相应的数据。
返回值为指针的函数,比如char *fun(){...; return str;},函数中待返回的变量必须是使用malloc等函数手动申请空间(堆内存)的数据,且外部使用后要手动释放。因为系统自动申请的栈内存会在函数调用后自动释放。

指针传递(地址传递)

形参为指向实参地址的指针,当对形参的指向操作时,就相当于操作实参本身。

示例:

#include <stdio.h>void swap(int *a, int *b){printf("swap enter\n");printf("a = %d, ptr = %p\n", *a, a);printf("b = %d, ptr = %p\n", *a, b);int tmp = *b;*b = *a;*a = tmp;printf("a = %d, ptr = %p\n", *a, a);printf("b = %d, ptr = %p\n", *b, b);printf("swap leave\n");
}int main() {int x = 1;int y = 2;printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);swap(&x, &y);printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);return 0;
}

运行结果:

x = 1, ptr = 000000000022FE4C
y = 2, ptr = 000000000022FE48
swap enter
a = 1, ptr = 000000000022FE4C
b = 1, ptr = 000000000022FE48
a = 2, ptr = 000000000022FE4C
b = 1, ptr = 000000000022FE48
swap leave
x = 2, ptr = 000000000022FE4C
y = 1, ptr = 000000000022FE48

结果表明:
swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。
实质是:
swap函数形式参数其实是一个指针,可能把fun(int *a)写成fun(int* a)就比较容易理解了,形参a为地址指针。*a就是xa就是&x。函数内部要想修改其数值就要使用*a取数值,打印其地址直接打印a就可以了。
函数内部对a b的操作实际上是操作x y所在的内存空间,所以函数内的修改会影响到外部x y的数值。

引用传递

引用传递的形参加一个&符号,这个形参相当于实参的一个别名,对形参的操作都相当于对实参的操作。
注意形参带&符号的引用传递在C语言中是不可用的,只有C++中支持。
C语言中函数参数总是通过值传递,可以通过显式传递指针值模拟引用传递。

Function parameters are always passed by value. Pass-by-reference is simulated in C by explicitly passing pointer values. – https://en.wikipedia.org/wiki/C_(programming_language)

示例:

#include <stdio.h>void swap(int &a, int &b){printf("swap enter\n");printf("a = %d, ptr = %p\n", a, &a);printf("b = %d, ptr = %p\n", a, &b);int tmp = b;b = a;a = tmp;printf("a = %d, ptr = %p\n", a, &a);printf("b = %d, ptr = %p\n", b, &b);printf("swap leave\n");
}int main() {int x = 1;int y = 2;printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);swap(x, y);printf("x = %d, ptr = %p\n", x, &x);printf("y = %d, ptr = %p\n", y, &y);return 0;
}

运行结果:

x = 1, ptr = 000000000022FE4C
y = 2, ptr = 000000000022FE48
swap enter
a = 1, ptr = 000000000022FE4C
b = 1, ptr = 000000000022FE48
a = 2, ptr = 000000000022FE4C
b = 1, ptr = 000000000022FE48
swap leave
x = 2, ptr = 000000000022FE4C
y = 1, ptr = 000000000022FE48

结果表明:
函数内对形参的使用方式和值传递相同,产生的效果和指针传递相同。
swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。

实质是:
形式参数前加&符号,这个形参相当于实参的一个别名,对这个形参的操作等同于对实参的操作,有点类似快捷方式。a等同于x,比如fun(int &a)函数内对a的操作和值传递的函数fun(int a)中对形参的操作一样,但是修改形参同时也是修改实参。

[转]C/C++语言中值传递、指针传递和引用传递相关推荐

  1. C语言中函数和指针的參数传递

    C语言中函数和指针的參数传递 近期写二叉树的数据结构实验.想用一个没有返回值的函数来创建一个树,发现这个树就是建立不起来,那么我就用这个样例讨论一下c语言中指针作为形參的函数中传递中隐藏的东西. 大家 ...

  2. c语言的指针和java引用传递参数,java传参数是传值还是引用

    1.基参数是本数据类型 传递是值(或者说值得副本). 2.参数是对象的话传递的是对象引用的副本.(1.修改引用副本指向新对象不会影响原来对象,2.修改引用指向的对象的属性会修改成功,3.如果传递时st ...

  3. C语言中的函数指针、函数的直接/间接调用、C# 委托(自定义委托、内置泛型委托、委托的实例化、委托的一般使用(模板方法、回调方法)、泛型委托、多播委托、同步/异步使用委托)

    文章目录 C语言中的函数指针 函数的直接调用与间接调用 Java中没有与委托对应的功能实体 C# 委托 C# 自定义委托类型 C# 内置泛型委托类型 委托的实例化 委托也支持泛型的使用 委托的一般使用 ...

  4. 什么是值传递,什么是引用传递。为什么说Java中只有值传递。

    关于这个问题,在StackOverflow上也引发过广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的.还有的人可能知道Java中的参数传递是值传递,但是说不出来为什么. ...

  5. C语言中的野指针问题

    C语言中的野指针问题 一.野指针 1.指针变量中的值是非法内存地址,进而形成野指针 2.野指针不是NULL指针,是指向不可用内存地址的指针 3.NULL指针并无危害,很好判断,也很好调试 4.C语言中 ...

  6. C语言和C++语言中的泛型指针

    C语言和C++语言中的泛型指针 首次,在说泛型指针之前,先说说特定指针,特定指针,顾名思义,就是有明确的类型的指针,如:int * ,char * ,float * ,short* ,student* ...

  7. c语言如何用指针操作一维字符数组,C语言中数组和指针的互操作

    C是一种怀旧的语言,因为它的历史很久远,然而自从各种面向对象的编程语言的相续出现让它的影响力日减.当然了,这是无可非议的,但是C的高效性是其他语言无妨比拟的,所以我们有必要把握其中的精华与奥妙,也就有 ...

  8. C++ 高效编程:pass-by-value(值传递)与pass-by-reference(引用传递)

    C++在定义函数传参时,常用pass-by-value(值传递)与pass-by-reference(引用传递)两种形式,两种参数传递具体实现方式为: 值传递(pass-by-value) 值传递(p ...

  9. 什么是值传递,什么是引用传递?

    1.什么是值传递,什么是引用传递? 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数. 引用传递(pass by ...

最新文章

  1. EditText中的几个常用属性
  2. 如何创建启动界面Splash Screen
  3. no Bloomberg, wind, ceic, csmar at cambridge
  4. c#和VB混用出现的错误
  5. vue-cli proxy中跨域中pathRewrite配置理解
  6. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 21丨报告系统状态的连续日期【难度困难】​
  7. java数组更新_java刷新数组到jList
  8. linux浏览器打开pdf文件,linux下的pdf浏览器(可加批注)
  9. Xcode 6.0中彻底关闭ARC
  10. mouseover与mouseenter、 mouseout与mouseleave的区别
  11. 8月7日 使用Jquery做表格的隔行变色,点击事件
  12. 使用Xtrabackup来备份你的mysql
  13. 为什么会有Memlink? redis
  14. Linux检测内存泄露的脚本
  15. LINUX下载编译libssh2
  16. matlab仿真软件 R2017a版本下载
  17. mysql正则mybatis中用法_SQL 正则表达式及mybatis中使用正则表达式
  18. redhat7 安装 docker
  19. 大一计算机ppt知识点,大一计算机总复习_图文.ppt
  20. 【网络安全】GitHub项目监控,teemo子域名查询

热门文章

  1. QItemSelectionModel——视图选择
  2. SpringBoot学习总结(个人笔记)
  3. cds5516舵机控制程序_[电力世界]中的应用程序CDS
  4. SQL Server实例的十大安全注意事项
  5. nlp中bpe_缓冲池扩展(BPE)–内存中OLTP:内存挑战
  6. 对警报线程池的警报线程_审核和警报SQL Server作业状态更改(启用或禁用)
  7. 报告正在使用哪些Reporting Services数据集字段?
  8. oracle ola_Ola HallengrenSQL Server维护解决方案–数据库完整性检查
  9. 华为手机使用应用沙盒动态修改分辨率参数
  10. Excel 2007 Open XML文件结构~~~1