按值传递 vs. 按指针传递
按值传递还是指针传递?
变量赋值有两种方式:按值传递、按"指针"传递(指针也常称为"引用")。不同的编程语言赋值的方式不一样,例如Python是按"指针"传递的,Go是按值传递的。
注意,"指针"加了引号,因为它不是真正的按指针拷贝,见下文分析。
参数传值其实也是变量赋值的过程,只不过参数是函数的本地变量而已。
按值传递的意思是每次赋值都拷贝内存中完整的数据结构对象,这时在内存中会保存两份内容完全相同,但地址不同的数据对象。
按"指针"传递的意思是每次赋值都只拷贝内存中数据结构对象的地址,这个地址占用一个机器字长(一个机器字长,在32位cpu上为32bit共4字节,64位则64bit共8字节),当然有些数据结构除了指针还包括其它属性,这时可能会占用数个机器字长。总之,按"指针"传递时,由于只拷贝一份能表示数据对象的属性(比如地址),拷贝的内容非常少,速度非常快。但必须注意,拷贝"指针"后,内存中只有一份数据对象,但将有两份完全相同的指向内存中数据对象的"指针",无论是通过哪个"指针"去修改数据对象,都会影响另一个。

对于那些不支持操作指针的语言,通常会将按"指针"传递称为"浅拷贝(shallow copy)",然后额外提供一个函数或工具实现按指传递,这称为"深拷贝(deep copy)"。
例如:
a=10
b=a
首先会在内存中划分一个格子用来创建数据对象10,然后将这个数据对象的地址保存到变量a中。

如果是按值拷贝的语言,则会在内存中拷贝一份数据对象10的副本,再将这个副本数据对象的地址保存到b中。

显然,a和b保存的地址是不一样的,内存中也有两份内容完全相同的数据对象10。所以,修改a的值时不会影响b的值,修改b的值时不会影响a。
如果是按"指针"拷贝的语言,则会直接拷贝a中的地址并保存到b中。

因为a和b的地址都一样,所以,修改a的值会影响b,修改b的值会影响a。
也许你已经发现了,按"指针"传递时,虽然a、b保存的地址相同,但如果a=11,a将指向新的数据对象,而b仍然指向10,即b=10,修改a并没有影响b。这是因为数值是不可变的,无法在原始的内存地址处修改,也就是无法将10替换成11,所以只要想修改这种不可变的对象就一定会创建新数据对象。对此,有两方面需要说明。
一方面,有些数据对象是可以在原始内存地址处直接进行替换修改的(例如python中的列表)。假设,某编程语言对数值也是可原处修改的,那么a=11将会在内存中将10替换成11,而不会新创建另一个数据对象11。

另一方面,上面的"按指针传递"并非是真正的按指针传递,而是按引用传递,或者说是按地址传递。这就是前文"按指针传递"中的"指针"都加上了引号的原因。
真正的指针是额外保存的,是占用空间的,和变量不同(变量保存了地址,在栈空间中),它是保存在堆内存中的。对于支持指针操作的语言(如C、C++、Go等),需要使用语法独立生成数据对象的指针,这类语言一般都能直接在原处修改数据对象。例如:
a=10
b=&a
其中b=&a表示生成a所指向(因为a保存了地址)数据对象的一个额外的指针,这个指针中保存了数据对象的地址,然后将这个指针赋值给b,这时b保存的是指针的地址,而不是数据对象的地址。

这时,修改a,或者修改b都会影响另一方,因为支持指针操作的语言一般都支持原处修改:
a=11
print(*b) /* 输出11 */
其中*b表示解除指针的引用,也就是取得数据对象的内容。
再回到按"指针"传递的拷贝方式,虽然它不是真正的拷贝指针,而是拷贝地址,但对于那些支持原处修改的数据对象,它们达到的效果和真实的指针传递是一样的。例如,数组、python的列表。
# 以下为python代码:
L1=[1,2,3,4]
L2=L1
L2[0]=11
print(L1) # 输出:[11,2,3,4]

可变对象的原处修改
支持指针操作的语言,通过指针修改数据时,是直接在原始地址块上修改为新数据的。例如:
func main() {
a := 10
println(a)
println(&a)
println("---------------")
*(&a) = 20
println(a)
println(&a)
}
结果:
10
0xc042085f48
---------------
20
0xc042085f48

但是python中的可变对象(比如列表),虽然俗称"原处修改",但并非真的原处修改,而是在堆内存中新创建一个数据对象,并将它作为可变对象的一部分,所以可变对象整体的地址没有改变,但内部元素的地址已经改变了,也就是旧的元素对象被回收。
>>> L=[222,333,444,555]
>>> id(L),id(L[1])
(44652184, 43798256)
>>> L[1]=3333
>>> id(L),id(L[1])
(44652184, 43798240)
按值传递 vs. 按指针传递的更多相关文章
- php数组时按值传递还是按地址传递
php数组时按值传递还是按地址传递 一.总结 1.数组都是按值:php普通变量和数组的赋值(=)是按值传递,对象的赋值(=)是按址传递 2.对象和按值和按址:对象的clone(用clone关键字)是按 ...
- [转] C++的引用传递、指针传递参数在java中的相应处理方法
原文出处:[http://blog.csdn.net/conowen/article/details/7420533] 首先要明白一点,java是没有指针这个概念的. 但是要实现C++的引用传递.指针 ...
- C语言指针传递详解
传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问,要在某个函数中修改数据,需要用指针传递数据,当数据是需要修改的指针的时候,就要传递指针的指针,传递参数(包括指针)的时候,传递 ...
- 【转载】C++ 值传递、指针传递、引用传递详解
原文链接:http://www.cnblogs.com/yanlingyin/ 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形 ...
- 从cocos2dx中寻找函数指针传递的方法
目的 看到群里有个朋友搞了好几天函数指针传递,没搞好.所以写一篇文章,旨在从cocos2dx中帮朋友们找到如何传递指针. 旧版本的函数指针传递 全局函数函数指针调用 一般在C++11之前,我们一般是这 ...
- 转:C++中引用传递与指针传递区别
从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有 ...
- C++中值传递、指针传递、引用传递的总结
C++中值传递.指针传递.引用传递的总结 指针传递和引用传递一般适用于:函数内部修改参数并且希望改动影响调用者.对比值传递,指针/引用传递可以将改变由形参"传给"实参(实际上就 ...
- (转)C++ 值传递、指针传递、引用传递详解
一直以来对函数的值传递引用传递理解很模糊,这篇文章可以说是给自己扫盲了. 值传递:实参不会发生改变,是因为形参传递的是不是实参的源地址(形参和实参地址不一样).不影响实参 指针传递:本质也是值传递,只 ...
- C++ 值传递、指针传递、引用传递详解
C++ 值传递.指针传递.引用传递详解 最近写了几篇深层次讨论数组和指针的文章,其中提到了“C语言中,所有非数组的形式参数传递均以值传递形式” 数组和指针背后——内存角度 语义"陷阱&quo ...
随机推荐
- CentOS6.9安装Python-3.6.3
CentOS6.9上默认安装的python版本是2.6的.因为系统自带的python会被系统很多软件环境依赖使用,所以不要卸载原来的Python版本,根据需要进行安装新版本即可,本人此处安装的是3.6 ...
- Python踩坑之 sys.argv[-1]代表什么
平台:win10+python 3.7.0 一.sys说明: sys.argv这个函数是我们写python脚本中最常用的一个函数. sys是Python的一个「标准库」,也就是官方出的「模块」,是「S ...
- 64位版本为什么叫amd64,而不是intel64
64位版本为什么叫amd64,而不是intel64? 首先了解下常见的几个架构: X86是一个指令集,是刚有个人电脑时候的什么8086,286,386的那个兼容的指令集. “x86-64”,有时会 ...
- Reading | 《TensorFlow:实战Google深度学习框架》
目录 三.TensorFlow入门 1. TensorFlow计算模型--计算图 I. 计算图的概念 II. 计算图的使用 2.TensorFlow数据类型--张量 I. 张量的概念 II. 张量的使 ...
- UML系统建模的分析和应用
一.基本信息 标题:UML系统建模的分析和应用 时间:2016 出版源:无线互联科技 领域分类:统一建模语言 二.研究背景 问题定义:统一建模语言的分析应用 难点:掌握和理解相关系统的业务环境,掌握良 ...
- cobbler学习
note.youdao.com/share/?id=2f8383d6e9824929012b041f069da26e&type=note#/ IPADDR=192.168.86.4 TYPE= ...
- Solutions and Summay for Linked List Naive and Easy Questions
1.Remove Linked List Elements package linkedlist; /* * Question: Remove all elements from a linked l ...
- 项目Alpha冲刺(团队1/10)
项目Alpha冲刺(团队1/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...
- JS跨域调用之document.domain--相同基础域名页面之间的调用
利用document.domain 实现跨域: 前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域 Javascript出于对 ...
- Ubuntu16.04 + gtx1060 + cuda8.0 + cudnn5.1 + caffe + Theano + Tensorflow
参考 ubuntu16.04+gtx1060+cuda8.0+caffe安装.测试经历 ,细节处有差异. 首先说明,这是在台式机上的安装测试经历,首先安装的win10,然后安装ubuntu16.04双 ...