在C和C++中,传递引用的含义是什么?

11
我对C和C++中 "按引用传递" 的含义感到困惑。
在C中,没有引用的概念。因此,我猜 "按引用传递" 意味着传递一个指针。但是,为什么不称之为 "按指针传递" 呢?
在C ++中,我们既有指针又有引用(以及类似迭代器之类的东西)。那么,这里的 "按引用传递" 是什么意思?

7
请参见以下两个链接,分别介绍了指针变量和引用变量的区别,以及在C++中通过引用传递参数的方式:https://dev59.com/VHVD5IYBdhLWcg3wL4mMhttps://dev59.com/VXE95IYBdhLWcg3wn_Vr - Schore
1
一般来说,引用是访问变量的一种方式,允许更改它所引用的值... 在 C 中,您可以对指针进行取消引用,因此术语“引用”也是有效的... - W.F.
1
@Olaf 啊,我以为今天我已经用完所有的标志了 :) - Schore
5
不受欢迎的答案是:这些都是困惑的所谓计算机科学家发明的胡言乱语。在计算机或实际机器代码中,不存在所谓的“引用”或“指针”,只有值和地址。你可以随意称呼一个地址,但这并不会改变它只是一个原始数字的事实。当你将某物传递给函数时,你的计算机会提供通过数据寄存器或堆栈传递值的副本的选项,或者通过索引寄存器传递数据的地址的选项。在现实世界中不存在其他类型的计算机。 - Lundin
1
“引用(reference)”这个词,根据你所处的位置和所做的事情而有不同的含义 - 它被过度重载了。例如,如果您正在尝试反向工程/调试他人的C++代码,则传递的引用变量是一个恼人且愚蠢的模糊概念,它专门设计用于防止维护和增强开发人员知道是否在不查找其声明的情况下传播给调用者更改变量值。在C中,它必须在前面加一个星号,以便立即知道。 - Martin James
显示剩余7条评论
10个回答

20

在口语中,“按引用传递”意味着,如果被调用者修改了其参数,则会影响到调用者,因为被调用者看到的参数 参考 来自调用者看到的值。

这个短语与实际的编程语言无关,也与如何调用它们(指针、引用等)无关。

在C++中,使用引用 指针可以实现按引用传递。在C语言中,只能通过传递指针来实现按引用传递

“按值传递”:

void foo( int x )
{
    // x is a *copy* of whatever argument foo() was called with
    x = 42;
}

int main()
{
    int a = 0;
    foo( a );
    // at this point, a == 0
}

"按引用传递",C语言风格:

void foo( int * x )
{
    // x is still a *copy* of foo()'s argument, but that copy *refers* to
    // the value as seen by the caller
    *x = 42;
}

int main()
{
    int a = 0;
    foo( &a );
    // at this point, a == 42
}

严格来说,在 C 语言中不存在按引用传递。你可以通过按值传递变量,或通过按值传递指向该变量的指针来实现。


1
好的一点是,实际上任何参数都是按值传递的,只是使用C++引用时不太明显。 - 463035818_is_not_a_number
@tobi303:实际上,C++引用就是按引用传递。这就是为什么C++引用不能是可变参数函数中的最后一个命名参数:当您使用va_start(它旨在获取堆栈上最后一个命名参数的地址,以便您可以从那里访问下一个参数)时,C++引用会指向调用者的堆栈帧中的变量。不用说,这不会按预期工作。(在一些调试“乐趣”之后我发现了这个问题。)指针按预期工作(指针按值传递)。 - DevSolar
然而,数组传递的工作方式类似于引用,即使它在技术上是按值传递的:void foo(int bar[]);可以使用int baz[42]; foo(baz);调用,并且调用者将看到更改后的数组内容。从技术上讲,函数参数衰减为指针,在函数签名和调用中都是如此,因此在技术上是通过值传递指针,但可见效果是通过引用传递数组。 - cmaster - reinstate monica
@cMaster:嗯,但是你不能在C中传递一个数组,对吧?因为它会衰变成一个指针。这就是为什么你不能在被调用的函数中使用sizeof来计算数组的大小...因为它是按值传递的指针。;-) - DevSolar
@Rajesh:指针是自己的数据对象(您可以获取指针的地址,该地址与所指向的对象的地址不同)。引用仅是别名,一个不同的名称,对实际数据对象的引用。您可以将其称为ak,但它是相同的对象 - DevSolar
显示剩余3条评论

6
在C语言中,没有引用(reference)。也就是说,没有引用变量。但是你可以使用指针(pointer)来引用对象。因此,从抽象的角度来看,指针是“引用”。
但是为什么不称之为通过指针传递(pass by pointer)呢?其实你可以这样称呼它。引用是一个比指针更通用的术语。当你想要讨论抽象概念并忽略实现细节时,使用更通用的术语往往更好。你会称之为通过引用传递(pass by reference),就像你称一个变量为“整数”而不是“int32_t”的原因一样。
在C++中,我们既有指针和引用(以及类似迭代器的东西)。那么在这里,“通过引用传递”意味着什么呢?这取决于上下文。通常情况下,它意味着函数参数是一个引用变量,但它也可能是一个指针、迭代器、引用包装器...任何引用对象的东西。

参考是一个抽象的概念,存在于C和C++之外;甚至超越编程。在C++中,该术语与引用变量含义不明确,上下文和惯例(并非普遍适用)决定了其意义。


1
我喜欢在那个抽象概念中加入“处理”这个术语。希望更多的人能够这样做。 - Lightness Races in Orbit

3

在C语言中,没有任何引用变量,但是你可以使用指针来传递引用。

在维基百科上,有这样的定义。在按引用调用评估(也称为按引用传递),函数接收对用作参数的变量的隐式引用,而不是其值的副本。因此,这个术语是由Thomas提到的一种参数传递类型。所以是的,由于C比C++更早,这个想法也比C++更早。

然而,在C++中,指针和引用都可以用于传递给函数(按地址调用和按引用调用)。实际上它们的工作方式是相同的,只有一些差异。

  • 一旦创建了引用,就不能将其后续引用另一个对象;这通常使用指针完成。
  • 引用不能为NULL。指针通常被设置为NULL以表示它们没有指向任何有效的东西。
  • 声明引用时必须进行初始化。指针没有这样的限制。

通过这些差异,如果你使用按引用调用而不是按指针调用,你可以减少出现空指针错误等问题的可能性。


3

让我们消除你的困惑。

C语言中没有引用(reference)。因此,我猜传递引用意味着传递一个指针。但为什么不称之为传递指针呢?

因为在C语言中,每个参数都是按值传递(pass-by-value)。即使是指针参数也是一份拷贝。但它包含(或者说指向)相同的值——内存地址。这就是你可以改变它所指向的变量而不是指针本身的原因。由于它是一份拷贝,无论你做什么都不会影响调用者层面上的指针。

C++中,我们既有指针又有引用(以及类似迭代器的东西)。那么,这里的传递引用是什么意思?

这意味着,参数是调用者层面上变量的别名,而不是拷贝,这使得我们可以改变它。

希望这有所帮助。


1
"

"按引用传递"(或称为“引用调用”)是一种在调用函数时传递参数的术语,这个想法比C++还要早。它不一定要使用C++的"引用"。C语言没有内置机制来实现这一点,因此必须使用指针。

"

1
假设你需要给房子涂漆...
按值传递: 你将一份房子的复制品交给油漆工 => 需要很多努力(可能需要在轨道上移动)
按引用传递: 你将你的房子地址交给油漆工,这样他就可以来涂漆了。

2
不完全正确。如果您使用“按值传递”的方式来粉刷房子,那么油漆工会得到一个副本来进行粉刷,而您将保留原始未经过油漆的房子。 - DevSolar
你说得对,我想强调传递值的努力和引用的优势... - V. Sambor
@DevSolar,然后一旦房屋的副本被粉刷,画家就会将其炸毁。 - Jabberwocky
2
@MichaelWalz:实际上,他只会把它留在那里,直到有其他的建筑物取代它。你仍然可以去参观它,但如果你被新结构压扁了,那就是你自己的错,因为没有提前警告。;-) - DevSolar
@MichaelWalz 这位画家应该是某种恐怖分子。 - V. Sambor

1

“引用”一般是指一个实例在引用另一个实例。因此,从更广泛的意义上讲,指针也可以被视为引用的一种可能实现。在C++中,“引用”只是称之为“引用”,因为除了引用一些内容之外,它们没有其他功能。

按引用传递通常用于与按值传递区分开来。无论是通过指针还是引用方式,这通常只是一个细节问题。然而,在C++引用中,函数参数的目的更加明确。例如:

int foo(int& a);         // pass-by-reference
int foo(const int& a);   // is pratically pass-by-value 
                         // (+ avoiding the copy of the parameter)

另一方面,与指针相比,使用引用时,在调用处很难确定是按值传递还是按引用传递。例如:

int x;
int y = foo(x);  // could be pass-by-value or pass-by-reference
int z = foo(&x); // obviously pass-by-reference (as a pointer)

“实际上是按值传递”这种说法毫无意义。避免精确复制意味着按值传递与此无关。 - Lightness Races in Orbit
@LightnessRacesinOrbit 我的意思是,它就像按值传递参数一样,因为它不能在函数内部更改,我找不到更好的词来描述这个。 - 463035818_is_not_a_number

0
只是为了补充答案,引用并不意味着按地址引用。编译器可以使用任何方法来引用变量。

-1
当你通过引用传递参数时,你是直接使用变量的地址而不是变量的值。如果你使用一个引用参数,你将得到传入变量的地址。
从这里开始,你可以随意操纵它,因为如果你在函数中更改引用,传入的变量将会发生变化。这是一种更容易处理大量数据的方法,它真的只是节省了内存等等。

-2

C语言中有两个概念

1. 值传递 - 这里传递的是值的副本,因此函数外部的实际值不会改变。

2. 引用传递 - 这里传递的是实际操作数的地址,因此它将全局更改这些值。

C++中有两个概念

1. 值传递 - 它与C相同,实际值不会改变,这些值的作用域仅限于函数。

2. 引用传递 - 传递实际操作数的地址,因此它将全局更改这些值,这意味着如果值发生更改,则会影响整个程序。

在引用传递中,传递操作数的地址,因此称为引用传递而不是指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接