[转]C/C++语言中值传递、指针传递和引用传递
在C/C++语言中值传递、指针传递和引用传递(C++ only)这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把这三种方式描述清楚。没时间看分析的直接看简述就可以了。
简述
表格是一种比较直接的表达方式,列个表格可以对这三种方式一目了然,假设调用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 b
。a b
和x 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
就是x
,a
就是&x
。函数内部要想修改其数值就要使用*a
取数值,打印其地址直接打印a
就可以了。
函数内部对a b
的操作实际上是操作x y
所在的内存空间,所以函数内的修改会影响到外部x y
的数值。
引用传递
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++语言中值传递、指针传递和引用传递相关推荐
- C语言中函数和指针的參数传递
C语言中函数和指针的參数传递 近期写二叉树的数据结构实验.想用一个没有返回值的函数来创建一个树,发现这个树就是建立不起来,那么我就用这个样例讨论一下c语言中指针作为形參的函数中传递中隐藏的东西. 大家 ...
- c语言的指针和java引用传递参数,java传参数是传值还是引用
1.基参数是本数据类型 传递是值(或者说值得副本). 2.参数是对象的话传递的是对象引用的副本.(1.修改引用副本指向新对象不会影响原来对象,2.修改引用指向的对象的属性会修改成功,3.如果传递时st ...
- C语言中的函数指针、函数的直接/间接调用、C# 委托(自定义委托、内置泛型委托、委托的实例化、委托的一般使用(模板方法、回调方法)、泛型委托、多播委托、同步/异步使用委托)
文章目录 C语言中的函数指针 函数的直接调用与间接调用 Java中没有与委托对应的功能实体 C# 委托 C# 自定义委托类型 C# 内置泛型委托类型 委托的实例化 委托也支持泛型的使用 委托的一般使用 ...
- 什么是值传递,什么是引用传递。为什么说Java中只有值传递。
关于这个问题,在StackOverflow上也引发过广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的.还有的人可能知道Java中的参数传递是值传递,但是说不出来为什么. ...
- C语言中的野指针问题
C语言中的野指针问题 一.野指针 1.指针变量中的值是非法内存地址,进而形成野指针 2.野指针不是NULL指针,是指向不可用内存地址的指针 3.NULL指针并无危害,很好判断,也很好调试 4.C语言中 ...
- C语言和C++语言中的泛型指针
C语言和C++语言中的泛型指针 首次,在说泛型指针之前,先说说特定指针,特定指针,顾名思义,就是有明确的类型的指针,如:int * ,char * ,float * ,short* ,student* ...
- c语言如何用指针操作一维字符数组,C语言中数组和指针的互操作
C是一种怀旧的语言,因为它的历史很久远,然而自从各种面向对象的编程语言的相续出现让它的影响力日减.当然了,这是无可非议的,但是C的高效性是其他语言无妨比拟的,所以我们有必要把握其中的精华与奥妙,也就有 ...
- C++ 高效编程:pass-by-value(值传递)与pass-by-reference(引用传递)
C++在定义函数传参时,常用pass-by-value(值传递)与pass-by-reference(引用传递)两种形式,两种参数传递具体实现方式为: 值传递(pass-by-value) 值传递(p ...
- 什么是值传递,什么是引用传递?
1.什么是值传递,什么是引用传递? 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数. 引用传递(pass by ...
最新文章
- EditText中的几个常用属性
- 如何创建启动界面Splash Screen
- no Bloomberg, wind, ceic, csmar at cambridge
- c#和VB混用出现的错误
- vue-cli proxy中跨域中pathRewrite配置理解
- 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 21丨报告系统状态的连续日期【难度困难】​
- java数组更新_java刷新数组到jList
- linux浏览器打开pdf文件,linux下的pdf浏览器(可加批注)
- Xcode 6.0中彻底关闭ARC
- mouseover与mouseenter、 mouseout与mouseleave的区别
- 8月7日 使用Jquery做表格的隔行变色,点击事件
- 使用Xtrabackup来备份你的mysql
- 为什么会有Memlink? redis
- Linux检测内存泄露的脚本
- LINUX下载编译libssh2
- matlab仿真软件 R2017a版本下载
- mysql正则mybatis中用法_SQL 正则表达式及mybatis中使用正则表达式
- redhat7 安装 docker
- 大一计算机ppt知识点,大一计算机总复习_图文.ppt
- 【网络安全】GitHub项目监控,teemo子域名查询
热门文章
- QItemSelectionModel——视图选择
- SpringBoot学习总结(个人笔记)
- cds5516舵机控制程序_[电力世界]中的应用程序CDS
- SQL Server实例的十大安全注意事项
- nlp中bpe_缓冲池扩展(BPE)–内存中OLTP:内存挑战
- 对警报线程池的警报线程_审核和警报SQL Server作业状态更改(启用或禁用)
- 报告正在使用哪些Reporting Services数据集字段?
- oracle ola_Ola HallengrenSQL Server维护解决方案–数据库完整性检查
- 华为手机使用应用沙盒动态修改分辨率参数
- Excel 2007 Open XML文件结构~~~1