按引用传递与按值传递有什么区别?
参数“按引用”或“按值”传递是什么意思? 这些参数有何不同?
What does it mean to say that a parameter is passed "by reference" or "by value"? How do such parameters differ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
首先也是最重要的,CS 理论中定义的“按值传递与按引用传递”区别现已过时,因为最初定义为“按引用传递”的技术已经过时了很受青睐,现在很少使用。1
较新的语言2倾向于使用不同(但相似)的技术来实现相同的效果(见下文)这是造成混乱的主要根源。
造成混淆的第二个原因是在“通过引用传递”中,“引用”的含义比一般术语“引用”更窄(因为该短语早于它)。
现在,真实的定义是:
当参数通过引用传递时,调用者和被调用者对参数使用相同的变量。 如果被调用者修改参数变量,则效果对调用者的变量可见。
当参数按值传递时,调用者和被调用者有两个自变量具有相同的值。 如果被调用者修改了参数变量,则调用者看不到效果。
在这个定义中需要注意的事情是:
这里的“变量”是指调用者的(本地或全局)变量本身 - 即,如果我通过引用传递本地变量并分配给它,我'将更改调用者的变量本身,而不是例如它所指向的任何内容(如果它是指针)。
“按引用传递”中“引用”的含义。 与一般“引用”术语的区别在于,此“引用”是临时且隐式的。被调用者得到的是一个与原始变量“相同”的“变量” .具体如何实现这种效果是无关紧要的(例如,语言还可能公开一些实现细节——地址、指针、解引用——这都是无关紧要的;如果最终效果是这样,那么它是按引用传递的)。
现在,在现代语言中,变量往往是“引用类型”(另一个比“引用传递”晚发明的概念并受其启发),即实际的对象数据单独存储在某处(通常,在堆上),并且只有对它的“引用”才会保存在变量中并作为参数传递。3
传递此类引用属于按值传递,因为从技术上讲,变量的值是引用本身,而不是引用的对象。 但是,对程序的最终效果可以与按值传递或按引用传递相同:
正如您所看到的,这对技术与定义中的技术几乎相同,只是有一定程度的间接性:只需将“变量”替换为“引用对象”即可。
没有达成一致的名称对于他们来说,这会导致扭曲的解释,例如“按值调用,其中值是引用”。 1975 年,Barbara Liskov 提出了术语“call-by-object-sharing”(或者有时只是“通过共享来电”)尽管它从未完全流行起来。 此外,这两个短语都与原来的短语没有相似之处。 难怪旧术语最终在没有更好的情况下被重复使用,从而导致混乱。4
(我会使用术语“新”或“间接” “新技术的传递值/传递引用。)
注意:很长一段时间以来,这个答案常常说:
这大部分是正确的除了“引用”的狭义含义——它既是临时的又是隐式的(不是必须的,但是显式的和/或持久的是附加功能,不是按引用传递语义的一部分,如上所述)。 更接近的类比是给您一份文档的副本与邀请您处理原件。
1除非您使用 Fortran 或 Visual Basic 进行编程,否则这不是默认行为,并且在现代使用的大多数语言中,真正的按引用调用甚至是不可能的。
2相当多的老版本也支持它
3在几种现代语言中,所有类型都是引用类型。 这种方法由 CLU 语言于 1975 年首创,此后被许多其他语言采用,包括 Python 和 Ruby。 还有更多语言使用混合方法,其中一些类型是“值类型”,另一些类型是“引用类型”——其中包括 C#、Java 和 JavaScript。
4回收一个合适的旧术语本身并没有什么坏处,但是人们必须以某种方式弄清楚每次使用的含义。 不这样做正是令人困惑的地方。
First and foremost, the "pass by value vs. pass by reference" distinction as defined in the CS theory is now obsolete because the technique originally defined as "pass by reference" has since fallen out of favor and is seldom used now.1
Newer languages2 tend to use a different (but similar) pair of techniques to achieve the same effects (see below) which is the primary source of confusion.
A secondary source of confusion is the fact that in "pass by reference", "reference" has a narrower meaning than the general term "reference" (because the phrase predates it).
Now, the authentic definition is:
When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller's variable.
When a parameter is passed by value, the caller and callee have two independent variables with the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.
Things to note in this definition are:
"Variable" here means the caller's (local or global) variable itself -- i.e. if I pass a local variable by reference and assign to it, I'll change the caller's variable itself, not e.g. whatever it is pointing to if it's a pointer.
The meaning of "reference" in "pass by reference". The difference with the general "reference" term is that this "reference" is temporary and implicit. What the callee gets is a "variable" that is somehow "the same" as the original one. How specifically this effect is achieved is irrelevant (e.g. the language may also expose some implementation details -- addresses, pointers, dereferencing -- this is all irrelevant; if the net effect is this, it's pass-by-reference).
Now, in modern languages, variables tend to be of "reference types" (another concept invented later than "pass by reference" and inspired by it), i.e. the actual object data is stored separately somewhere (usually, on the heap), and only "references" to it are ever held in variables and passed as parameters.3
Passing such a reference falls under pass-by-value because a variable's value is technically the reference itself, not the referred object. However, the net effect on the program can be the same as either pass-by-value or pass-by-reference:
As you may see, this pair of techniques is almost the same as those in the definition, only with a level of indirection: just replace "variable" with "referenced object".
There's no agreed-upon name for them, which leads to contorted explanations like "call by value where the value is a reference". In 1975, Barbara Liskov suggested the term "call-by-object-sharing" (or sometimes just "call-by-sharing") though it never quite caught on. Moreover, neither of these phrases draws a parallel with the original pair. No wonder the old terms ended up being reused in the absence of anything better, leading to confusion.4
(I would use the terms "new" or "indirect" pass-by-value/pass-by-reference for the new techniques.)
NOTE: For a long time, this answer used to say:
This is mostly correct except the narrower meaning of "reference" -- it being both temporary and implicit (it doesn't have to, but being explicit and/or persistent are additional features, not a part of the pass-by-reference semantic, as explained above). A closer analogy would be giving you a copy of a document vs inviting you to work on the original.
1Unless you are programming in Fortran or Visual Basic, it's not the default behavior, and in most languages in modern use, true call-by-reference is not even possible.
2A fair amount of older ones support it, too
3In several modern languages, all types are reference types. This approach was pioneered by the language CLU in 1975 and has since been adopted by many other languages, including Python and Ruby. And many more languages use a hybrid approach, where some types are "value types" and others are "reference types" -- among them are C#, Java, and JavaScript.
4There's nothing bad with recycling a fitting old term per se, but one has to somehow make it clear which meaning is used each time. Not doing that is exactly what keeps confusing.
这是一种将参数传递给函数的方法。 通过引用传递意味着被调用函数的参数将与调用者传递的参数相同(不是值,而是标识 - 变量本身)。 按值传递意味着被调用函数的参数将是调用者传递的参数的副本。 值将相同,但身份(变量)不同。 因此,在一种情况下,对被调用函数完成的参数的更改会更改传递的参数,而在另一种情况下,只会更改被调用函数中参数的值(这只是一个副本)。 急急急:
ref
)。 Jon Skeet 在此处对此也有很好的解释。代码
因为我的语言是 C++,所以我将在这里使用它
,Java 中的示例也不会造成伤害:
维基百科
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
这家伙几乎做到了:
http://javadude.com/articles/passbyvalue.htm
It's a way how to pass arguments to functions. Passing by reference means the called functions' parameter will be the same as the callers' passed argument (not the value, but the identity - the variable itself). Pass by value means the called functions' parameter will be a copy of the callers' passed argument. The value will be the same, but the identity - the variable - is different. Thus changes to a parameter done by the called function in one case changes the argument passed and in the other case just changes the value of the parameter in the called function (which is only a copy). In a quick hurry:
ref
used at caller and called function). Jon Skeet also has a nice explanation of this here.Codes
Since my language is C++, i will use that here
And an example in Java won't hurt:
Wikipedia
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
This guy pretty much nails it:
http://javadude.com/articles/passbyvalue.htm
这里的许多答案(特别是得票最高的答案)实际上是不正确的,因为他们误解了“通过引用调用”的真正含义。 这是我试图澄清问题的尝试。
TL;DR
用最简单的话来说:
用隐喻术语来说:
“按值调用”和“按引用调用”的含义请
注意,这两个概念与引用类型的概念完全独立且正交(在 Java 中是
Object
的所有子类型,在 C# 中是所有class
类型),或指针的概念像 C 中的类型(在语义上等同于 Java 的“引用类型”,只是语法不同)。引用类型的概念对应于一个 URL:它本身既是一条信息,又是一个引用(一个指针,如果你会)其他信息。 您可以在不同的地方拥有同一个 URL 的多个副本,并且它们不会更改它们链接到的网站; 如果网站更新,则每个 URL 副本仍会指向更新的信息。 相反,在任何一处更改 URL 都不会影响该 URL 的任何其他书面副本。
请注意,C++ 有一个“引用”概念(例如
int&
),它不类似于 Java 和 C# 的“引用类型”,但是就像“通过引用调用”一样。 Java 和 C# 的“引用类型”以及 Python 中的所有类型都类似于 C 和 C++ 所谓的“指针类型”(例如int*
)。好的,这是更长、更正式的解释。
术语
首先,我想强调一些重要的术语,以帮助澄清我的答案,并确保我们在使用单词时所指的是相同的想法。 (实际上,我相信对此类主题的绝大多数混淆源于使用单词的方式未能完全传达预期的含义。)
首先,这里有一个函数声明的类似 C 语言的示例:
这是一个调用这个函数的例子:
使用这个例子,我想定义一些重要的术语:
foo
是一个在第1行声明的函数(Java坚持使所有函数成为方法,但概念是相同的,但不失一般性;C 和 C++ 对声明和定义进行了区分,我不会在这里讨论)param
是一个形式参数 到foo
,也在第 1 行声明arg
是一个变量,具体来说是一个局部变量在第 2 行arg
上声明和初始化的函数bar
的特定调用的参数 >foo
on line 3这里有两组非常重要的概念需要区分。 第一个是值与变量:
bar
函数中,在int arg = 1;
行之后,表达式arg
具有值1
。final
或 C# 的readonly
声明)或深度不可变(例如使用 C++ 的const
)。需要区分的另一对重要概念是参数与参数:
调用按值调用
>按值调用,函数的形式参数是为函数调用新创建的变量,并使用其参数的值进行初始化。
这与用值初始化任何其他类型的变量的工作方式完全相同。 例如:
这里
arg
和another_variable
是完全独立的变量——它们的值可以彼此独立地改变。 然而,在声明another_variable
时,它被初始化为与arg
保持相同的值 - 即1
。由于它们是自变量,因此对
another_variable
的更改不会影响arg
:这与
arg
和param 之间的关系完全相同
在我们上面的例子中,为了对称,我将在这里重复一下:这就像我们这样编写代码一样:
也就是说,按值调用的定义特征是被调用者(在本例中是
foo
)接收值作为参数,但对于来自 的变量的这些值有自己单独的变量调用者(在本例中为bar
)。回到上面的比喻,如果我是
bar
而你是foo
,当我打电话给你时,我会递给你一张带有值的纸上面写着。 您将这张纸称为param
。 该值是我在笔记本中写入的值(我的局部变量)的副本,位于我称为arg
的变量中。(顺便说一句:根据硬件和操作系统的不同,关于如何从一个函数调用另一个函数,存在各种调用约定。调用约定就像我们决定是否将值写入我的一块纸然后递给你,或者如果你有一张我写在上面的纸,或者我把它写在我们面前的墙上,这也是一个有趣的话题,但远远超出了范围。 。
通过引用调用
在通过引用调用中,函数的形式参数只是调用者作为参数提供的相同变量的新名称
回到上面的示例,它相当于:
由于
param
只是arg
的另一个名称 - 也就是说,它们是相同的变量 ,对param
的更改会反映在arg
中。 这是按引用调用与按值调用不同的基本方式。很少有语言支持按引用调用,但 C++ 可以这样做:
在这种情况下,
param
不仅仅具有与arg 相同的值 code>,它实际上是
arg
(只是名称不同),因此bar
可以观察到arg
有已增加。请注意,这不是 Java、JavaScript、C、Objective-C、Python 或当今几乎任何其他流行语言的工作方式。 这意味着这些语言不是通过引用调用,而是通过值调用。
附录:通过对象共享调用
如果您所拥有的是按值调用,但实际值是引用类型或指针类型,那么“值”本身并不是很有趣(例如,在 C 中它只是特定于平台的大小的整数)——有趣的是该值指向。
如果引用类型(即指针)指向的是可变的,那么可能会产生有趣的效果:您可以修改指向的值,并且调用者可以观察到指向的值的变化,即使调用者无法观察到指针本身的变化。
再次借用 URL 的类比,如果我们都关心的是网站而不是 URL,那么我向您提供网站 URL 的副本这一事实并不是特别有趣。 事实上,您在 URL 副本上乱涂乱画不会影响我的 URL 副本,这并不是我们关心的事情(事实上,在 Java 和 Python 等语言中,“URL”或引用类型值可以根本不能修改,只有它指向的东西可以)。
Barbara Liskov 在发明 CLU 编程语言(具有这些语义)时意识到现有术语“按值调用”和“按引用调用”对于描述这种新语言的语义并不是特别有用。 因此她发明了一个新术语:通过对象共享调用。
当讨论技术上按值调用的语言时,但使用的常见类型是引用或指针类型(即:几乎所有现代命令式、面向对象或多范式编程语言),我发现它不会那么令人困惑只需避免谈论按值调用或按引用调用即可。 坚持通过对象共享调用(或简单地通过对象调用),没有人会感到困惑。 :-)
Many answers here (and in particular the most highly upvoted answer) are factually incorrect, since they misunderstand what "call by reference" really means. Here's my attempt to set matters straight.
TL;DR
In simplest terms:
In metaphoric terms:
What "call by value" and "call by reference" don't mean
Note that both of these concepts are completely independent and orthogonal from the concept of reference types (which in Java is all types that are subtypes of
Object
, and in C# allclass
types), or the concept of pointer types like in C (which are semantically equivalent to Java's "reference types", simply with different syntax).The notion of reference type corresponds to a URL: it is both itself a piece of information, and it is a reference (a pointer, if you will) to other information. You can have many copies of a URL in different places, and they don't change what website they all link to; if the website is updated then every URL copy will still lead to the updated information. Conversely, changing the URL in any one place won't affect any other written copy of the URL.
Note that C++ has a notion of "references" (e.g.
int&
) that is not like Java and C#'s "reference types", but is like "call by reference". Java and C#'s "reference types", and all types in Python, are like what C and C++ call "pointer types" (e.g.int*
).OK, here's the longer and more formal explanation.
Terminology
To start with, I want to highlight some important bits of terminology, to help clarify my answer and to ensure we're all referring to the same ideas when we are using words. (In practice, I believe the vast majority of confusion about topics such as these stems from using words in ways that to not fully communicate the meaning that was intended.)
To start, here's an example in some C-like language of a function declaration:
And here's an example of calling this function:
Using this example, I want to define some important bits of terminology:
foo
is a function declared on line 1 (Java insists on making all functions methods, but the concept is the same without loss of generality; C and C++ make a distinction between declaration and definition which I won't go into here)param
is a formal parameter tofoo
, also declared on line 1arg
is a variable, specifically a local variable of the functionbar
, declared and initialized on line 2arg
is also an argument to a specific invocation offoo
on line 3There are two very important sets of concepts to distinguish here. The first is value versus variable:
bar
function above, after the lineint arg = 1;
, the expressionarg
has the value1
.final
or C#'sreadonly
) or deeply immutable (e.g. using C++'sconst
).The other important pair of concepts to distinguish is parameter versus argument:
Call by value
In call by value, the function's formal parameters are variables that are newly created for the function invocation, and which are initialized with the values of their arguments.
This works exactly the same way that any other kinds of variables are initialized with values. For example:
Here
arg
andanother_variable
are completely independent variables -- their values can change independently of each other. However, at the point whereanother_variable
is declared, it is initialized to hold the same value thatarg
holds -- which is1
.Since they are independent variables, changes to
another_variable
do not affectarg
:This is exactly the same as the relationship between
arg
andparam
in our example above, which I'll repeat here for symmetry:It is exactly as if we had written the code this way:
That is, the defining characteristic of what call by value means is that the callee (
foo
in this case) receives values as arguments, but has its own separate variables for those values from the variables of the caller (bar
in this case).Going back to my metaphor above, if I'm
bar
and you'refoo
, when I call you, I hand you a piece of paper with a value written on it. You call that piece of paperparam
. That value is a copy of the value I have written in my notebook (my local variables), in a variable I callarg
.(As an aside: depending on hardware and operating system, there are various calling conventions about how you call one function from another. The calling convention is like us deciding whether I write the value on a piece of my paper and then hand it to you, or if you have a piece of paper that I write it on, or if I write it on the wall in front of both of us. This is an interesting subject as well, but far beyond the scope of this already long answer.)
Call by reference
In call by reference, the function's formal parameters are simply new names for the same variables that the caller supplies as arguments.
Going back to our example above, it's equivalent to:
Since
param
is just another name forarg
-- that is, they are the same variable, changes toparam
are reflected inarg
. This is the fundamental way in which call by reference differs from call by value.Very few languages support call by reference, but C++ can do it like this:
In this case,
param
doesn't just have the same value asarg
, it actually isarg
(just by a different name) and sobar
can observe thatarg
has been incremented.Note that this is not how any of Java, JavaScript, C, Objective-C, Python, or nearly any other popular language today works. This means that those languages are not call by reference, they are call by value.
Addendum: call by object sharing
If what you have is call by value, but the actual value is a reference type or pointer type, then the "value" itself isn't very interesting (e.g. in C it's just an integer of a platform-specific size) -- what's interesting is what that value points to.
If what that reference type (that is, pointer) points to is mutable then an interesting effect is possible: you can modify the pointed-to value, and the caller can observe changes to the pointed-to value, even though the caller cannot observe changes to the pointer itself.
To borrow the analogy of the URL again, the fact that I gave you a copy of the URL to a website is not particularly interesting if the thing we both care about is the website, not the URL. The fact that you scribbling over your copy of the URL doesn't affect my copy of the URL isn't a thing we care about (and in fact, in languages like Java and Python the "URL", or reference type value, can't be modified at all, only the thing pointed to by it can).
Barbara Liskov, when she invented the CLU programming language (which had these semantics), realized that the existing terms "call by value" and "call by reference" weren't particularly useful for describing the semantics of this new language. So she invented a new term: call by object sharing.
When discussing languages that are technically call by value, but where common types in use are reference or pointer types (that is: nearly every modern imperative, object-oriented, or multi-paradigm programming language), I find it's a lot less confusing to simply avoid talking about call by value or call by reference. Stick to call by object sharing (or simply call by object) and nobody will be confused. :-)
在理解这两个术语之前,您必须了解以下内容。 每个物体都有两个东西可以使它被区分。
因此,如果您说
employee.name = "John"
,请知道关于name
有两件事。 它的值是“John”,它在内存中的位置是一些十六进制数字,可能如下所示:0x7fd5d258dd00
。根据语言的体系结构或对象的类型(类、结构等),您可以传输
"John"
或0x7fd5d258dd00
传递
"John"
称为按值传递。传递
0x7fd5d258dd00
称为按引用传递。 任何指向此内存位置的人都可以访问“John”的值。有关这方面的更多信息,我建议您阅读取消引用指针以及为什么选择结构(值类型)而不是类(引用类型)。
Before understanding the two terms, you must understand the following. Every object has two things that can make it be distinguished.
So if you say
employee.name = "John"
, know that there are two things aboutname
. Its value which is"John"
and also its location in the memory which is some hexadecimal number maybe like this:0x7fd5d258dd00
.Depending on the language's architecture or the type (class, struct, etc.) of your object, you would be either transferring
"John"
or0x7fd5d258dd00
Passing
"John"
is known as passing by value.Passing
0x7fd5d258dd00
is known as passing by reference. Anyone who is pointing to this memory location will have access to the value of"John"
.For more on this, I recommend you to read about dereferencing a pointer and also why choose struct (value type) over class (reference type).
这是一个例子:
Here is an example:
获取此信息的最简单方法是使用 Excel 文件。 举例来说,您在单元格 A1 和 B1 中有两个数字 5 和 2,并且您想在第三个单元格(假设为 A2)中找到它们的总和。
您可以通过两种方式执行此操作。
通过在单元格中输入 = 5 + 2 来将它们的值传递到单元格 A2。 在这种情况下,如果单元格 A1 或 B1 的值发生变化,A2 中的总和保持不变。
或者通过输入= A1 + B1将单元格 A1 和 B1 的“引用”传递给单元格 A2。 在这种情况下,如果单元格 A1 或 B1 的值发生变化,A2 中的总和也会发生变化。
The simplest way to get this is on an Excel file. Let’s say for example that you have two numbers, 5 and 2 in cells A1 and B1 accordingly, and you want to find their sum in a third cell, let's say A2.
You can do this in two ways.
Either by passing their values to cell A2 by typing = 5 + 2 into this cell. In this case, if the values of the cells A1 or B1 change, the sum in A2 remains the same.
Or by passing the “references” of the cells A1 and B1 to cell A2 by typing = A1 + B1. In this case, if the values of the cells A1 or B1 change, the sum in A2 changes too.
当通过引用传递时,您基本上是在传递一个指向变量的指针。 按值传递您正在传递变量的副本。
在基本用法中,这通常意味着按引用传递,对变量的更改将在调用方法中看到,而按值传递则不会。
When passing by reference you are basically passing a pointer to the variable. Pass by value you are passing a copy of the variable.
In basic usage this normally means pass by reference, changes to the variable will seen be in the calling method and in pass by value they won’t.
按值传递发送存储在您指定的变量中的数据的副本,而按引用传递则发送到变量本身的直接链接。
因此,如果您通过引用传递变量,然后更改传递到的块内的变量,则原始变量将被更改。 如果您只是按值传递,则原始变量将无法被您传递到的块更改,但您将获得调用时它包含的任何内容的副本。
Pass by value sends a copy of the data stored in the variable you specify, and pass by reference sends a direct link to the variable itself.
So if you pass a variable by reference and then change the variable inside the block you passed it into, the original variable will be changed. If you simply pass by value, the original variable will not be able to be changed by the block you passed it into, but you will get a copy of whatever it contained at the time of the call.
看看这张照片:
在第一种情况(通过引用传递)中,当函数内部设置或更改变量时,外部变量也会更改。
但在第二种情况下(按值传递),更改函数内部的变量不会对外部变量产生任何影响。
要阅读本文,请参阅此链接。
Take a look at this photo:
In the first case (pass by reference), when the variable is set or changed inside the function, the external variable also changes.
But in the second case (pass by value), changing the variable inside the function doesn't have any effect on the external variable.
For reading the article, see this link.
按值传递 - 函数复制变量并使用副本(因此它不会更改原始变量中的任何内容)
按引用传递 - 函数使用原始变量。 如果更改另一个函数中的变量,原始变量也会更改。
示例(复制并使用/自己尝试一下看看):
保持简单,偷看。 文字墙可能是一个坏习惯。
Pass by value - The function copies the variable and works with a copy (so it doesn't change anything in the original variable)
Pass by reference - The function uses the original variable. If you change the variable in the other function, it changes in the original variable too.
Example (copy and use/try this yourself and see):
Keep it simple, peeps. Walls of text can be a bad habit.
它们之间的主要区别在于值类型变量存储值,因此在方法调用中指定值类型变量会将该变量值的副本传递给该方法。 引用类型变量存储对对象的引用,因此将引用类型变量指定为参数会向方法传递引用该对象的实际引用的副本。 即使引用本身是按值传递的,该方法仍然可以使用它接收到的引用来与原始对象进行交互,并可能修改原始对象。 类似地,当通过 return 语句从方法返回信息时,该方法返回存储在值类型变量中的值的副本或存储在引用类型变量中的引用的副本。 返回引用时,调用方法可以使用该引用与引用的对象进行交互。 因此,实际上,对象总是通过引用传递。
在 C# 中,要通过引用传递变量,以便被调用的方法可以修改变量,C# 提供了关键字 ref 和 out。 将 ref 关键字应用于参数声明允许您通过引用将变量传递给方法 - 被调用的方法将能够修改调用者中的原始变量。 ref 关键字用于已在调用方法中初始化的变量。 通常,当方法调用包含未初始化的变量作为参数时,编译器会生成错误。 在参数前面加上关键字 out 将创建一个输出参数。 这向编译器表明参数将通过引用传递到被调用的方法中,并且被调用的方法将为调用者中的原始变量赋值。 如果该方法未在每个可能的执行路径中为输出参数赋值,则编译器会生成错误。 这还可以防止编译器为作为参数传递给方法的未初始化变量生成错误消息。 一种方法只能通过 return 语句向其调用者返回一个值,但可以通过指定多个输出(ref 和/或 out)参数来返回多个值。
请参阅此处的 C# 讨论和示例 链接文本
A major difference between them is that value-type variables store values, so specifying a value-type variable in a method call passes a copy of that variable's value to the method. Reference-type variables store references to objects, so specifying a reference-type variable as an argument passes the method a copy of the actual reference that refers to the object. Even though the reference itself is passed by value, the method can still use the reference it receives to interact with—and possibly modify—the original object. Similarly, when returning information from a method via a return statement, the method returns a copy of the value stored in a value-type variable or a copy of the reference stored in a reference-type variable. When a reference is returned, the calling method can use that reference to interact with the referenced object. So, in effect, objects are always passed by reference.
In c#, to pass a variable by reference so the called method can modify the variable's, C# provides keywords ref and out. Applying the ref keyword to a parameter declaration allows you to pass a variable to a method by reference—the called method will be able to modify the original variable in the caller. The ref keyword is used for variables that already have been initialized in the calling method. Normally, when a method call contains an uninitialized variable as an argument, the compiler generates an error. Preceding a parameter with keyword out creates an output parameter. This indicates to the compiler that the argument will be passed into the called method by reference and that the called method will assign a value to the original variable in the caller. If the method does not assign a value to the output parameter in every possible path of execution, the compiler generates an error. This also prevents the compiler from generating an error message for an uninitialized variable that is passed as an argument to a method. A method can return only one value to its caller via a return statement, but can return many values by specifying multiple output (ref and/or out) parameters.
see c# discussion and examples here link text
示例:
const &
通常是最好的。 您不会遭受建设和破坏惩罚。 如果引用不是 const,则您的界面建议它将更改传入的数据。Examples:
const &
is generally best. You don't incur the construction and destruction penalty. If the reference isn't const your interface is suggesting that it will change the passed in data.如果您不想在将原始变量传递给函数后更改其值,则应使用“按值传递”参数构造该函数。
那么该函数将只有该值,但没有传入变量的地址。 如果没有变量的地址,函数内部的代码就无法更改从函数外部看到的变量值。
但是,如果您想让函数从外部看到能够更改变量值,则需要使用按引用传递。 由于值和地址(引用)都被传入并且在函数内部可用。
If you don't want to change the value of the original variable after passing it into a function, the function should be constructed with a "pass by value" parameter.
Then the function will have only the value, but not the address of the passed in variable. Without the variable's address, the code inside the function cannot change the variable value as seen from the outside of the function.
But if you want to give the function the ability to change the value of the variable as seen from the outside, you need to use pass by reference. As both the value and the address (reference) are passed in and are available inside the function.
简而言之,按值传递就是它是什么,按引用传递就是它在哪里。
如果您的值是 VAR1 =“Happy Guy!”,您只会看到“Happy Guy!”。 如果 VAR1 变成“Happy Gal!”,你就不会知道这一点。 如果它是通过引用传递的,并且 VAR1 发生变化,那么您就会发生变化。
In short, Passed by value is WHAT it is and passed by reference is WHERE it is.
If your value is VAR1 = "Happy Guy!", you will only see "Happy Guy!". If VAR1 changes to "Happy Gal!", you won't know that. If it's passed by reference, and VAR1 changes, you will.
1. 按值传递/按值调用
在按值调用中,当您将值传递给
printvalue(x)
(即参数5
)时,它会被复制到void printvalue(int x)
。 现在,我们有两个不同的值5
和复制的值5
,这两个值存储在不同的内存位置。 因此,如果您在void printvalue(int x)
中进行任何更改,它不会反映回参数。2. 按引用传递/按引用调用
在按引用调用中,只有一处区别。 我们使用
&
即地址运算符。 通过做void printvalue(int &x)
我们引用的是x
的地址,它告诉我们它们都引用相同的位置。 因此,函数内部所做的任何更改都会反映在外部。既然您已经来到这里,您还应该了解...
3。 按指针传递/按地址调用
在按地址传递中,指针
int* x
保存传递给它的地址printvalue(&x)
。 因此,函数内部所做的任何更改都会反映在外部。1. Pass By Value / Call By Value
In call by value, when you pass a value to
printvalue(x)
i.e. the argument which is5
, it is copied tovoid printvalue(int x)
. Now, we have two different values5
and the copied value5
and these two values are stored in different memory locations. So if you make any change insidevoid printvalue(int x)
it won't reflect back to the argument.2. Pass By Reference/ Call By Reference
In call by reference, there's only one difference. We use
&
i.e. the address operator. By doingvoid printvalue(int &x)
we are referring to the address ofx
which tells us that it both refers to the same location. Hence, any changes made inside the function will reflect outside.Now that you're here, you should also know about ...
3. Pass By Pointer/ Call By Address
In pass by address, the pointer
int* x
holds the address passed to itprintvalue(&x)
. Hence, any changes done inside the function will reflect outside.按值传递意味着如何通过使用参数将值传递给函数。 在按值传递中,我们复制存储在我们指定的变量中的数据,并且它比按引用传递慢,因为数据是复制的。
或者我们对复制的数据进行更改。 原始数据不受影响。 在通过引用传递或通过地址传递时,我们发送到变量本身的直接链接。 或者传递一个指向变量的指针。 它更快,因为消耗的时间更少。
Pass by value means how to pass a value to a function by making use of arguments. In pass by value, we copy the data stored in the variable we specify, and it is slower than pass by reference because the data is copied.
Or we make changes in the copied data. The original data is not affected. And in pass by reference or pass by address, we send a direct link to the variable itself. Or passing a pointer to a variable. It is faster because less time is consumed.
下面是一个示例,演示了按值传递 - 指针值 - 引用之间的差异:
“按引用传递”方法有一个重要的限制。 如果参数被声明为通过引用传递(因此其前面带有 & 符号),则其对应的实际参数必须是变量。
指“按值传递”形式参数的实际参数一般可以是表达式,因此不仅可以使用变量,还可以使用文字,甚至可以使用函数调用的结果。
该函数无法将值放置在变量以外的位置。 它不能为文字分配新值或强制表达式更改其结果。
PS:您还可以在当前线程中查看 Dylan Beattie 的答案,其中用简单的文字进行了解释。
Here is an example that demonstrates the differences between pass by value - pointer value - reference:
The “passing by reference” method has an important limitation. If a parameter is declared as passed by reference (so it is preceded by the & sign) its corresponding actual parameter must be a variable.
An actual parameter referring to “passed by value” formal parameter may be an expression in general, so it is allowed to use not only a variable but also a literal or even a function invocation's result.
The function is not able to place a value in something other than a variable. It cannot assign a new value to a literal or force an expression to change its result.
PS: You can also check Dylan Beattie answer in the current thread that explains it in plain words.
问题是“对”。
没有人指出重要的一点。 在传递值时,会占用额外的内存来存储传递的变量值。
在传递引用时,值不会占用额外的内存(在某些情况下内存效率很高)。
The question is "vs".
And nobody has pointed to an important point. In passing with values, additional memory is occupied to store the passed variable values.
While in passing with a reference, no additional memory is occupied for the values (memory efficient in circumstances).