C语言是否支持“按引用传递”?

8

我听说在C语言中可以通过"按值传递"或"按引用传递"方式传递参数。但是在一本书中提到,我们可以通过这两种方式传递参数,但实际上没有"按引用传递",但我实际上大多数情况下都是通过"按引用传递"传递参数。

那么为什么会有人问:"C语言甚至有按引用传递吗?"

非常感谢您的详细说明。


3
C语言中没有传递引用的方式。 - Oliver Charlesworth
你从哪里“听说”的?在C语言中如何实现“按引用传递”?(你可能错了) - Suvarna Pattayil
@SuvP 在 "c" 中没有传递引用这一概念,但是传递引用意味着我们通过指针传递地址来访问数据,但我的问题是,当我们通过传递地址来访问数据时,为什么会说没有 "传递引用"。而我们通过按值调用或按引用调用访问相同的数据。 - Varun Chhangani
2个回答

25

C参数总是按值传递而不是按引用传递。但是,如果您将对象的地址视为对该对象的引用,则可以通过按值传递该引用。例如:

void foo(int *x)
{
    *x = 666;
}

在评论中你问道:

既然我们可以通过值传递来传递所有参数,为什么在C语言中我们还需要指针呢?

因为在一种只支持按值传递的语言中,缺少指针将是一种限制。这意味着你无法编写像这样的函数:

void swap(int *a, int *b)
{
    int temp = *a;
    *b = *a;
    *a = temp;
}
在Java中,例如,无法编写该函数,因为它仅具有传值而没有指针。
在C++中,您可以使用引用编写此函数,如下所示:
void swap(int &a, int &b)
{
    int temp = a;
    b = a;
    a = temp;
}

同样地,在 C# 中:

void swap(ref int a, ref int b)
{
    int temp = a;
    b = a;
    a = temp;
}

3
如果没有指针,你就无法 “伪造” 引用传递。或者,如 Kerrek 所说(比我表述更清晰),没有指针,你将无法自己组装引用语义。 - David Heffernan
1
@BertieWheen 不是的。那些类型已经是引用。这是一个非常常见的误解。当您将对象作为参数传递时,您是通过值传递引用。在Java中,您也无法编写对象的交换函数。请阅读此内容:https://dev59.com/EXVD5IYBdhLWcg3wQJOT - David Heffernan
我明白你的意思。然而,在那种情况下,“并且没有指针”这部分是不正确的,如果你认为每个对象实际上都是一个指向对象的指针。 - Bertie Wheen
1
@BertieWheen 我的理解是,Java实现使用指针,但Java语言本身没有指针。无论如何,在Java中你不能实现swap,对吧? - David Heffernan
1
名字到底有什么意义呢?在C++和C#的实现中,不是地址本身被复制到函数局部变量堆栈中,而是通过移动堆栈指针引用堆栈或堆上的内存块吗?除了语法之外,我没有看到任何必要的实现上的差异。在编程层面,“按引用传递”与传递指针只是概念上的区别,而不是变量传递的基本机制。 - huggie
显示剩余9条评论

18
“引用语义”这个概念是一个抽象的、理论性的概念,其意思是你可以通过将数据的引用提供给函数来修改现有数据。问题是语言是否能够“实现”引用语义。在C语言中,您可以使用指针获得引用语义。这意味着您可以获得所需的行为,但需要从各种组件(指针类型、取地址运算符、解引用运算符、将指针作为函数参数作为“按值”传递)中自行组装它。相比之下,C++包含本地引用类型,因此直接在语言中实现了引用语义。其他语言则采用不同的方法。例如,在Python中,默认情况下许多东西都是引用(当b是列表时,例如a=b和a=b[:]之间存在区别)。语言提供引用与值语义的方式及其实现方式是语言设计的深刻部分。

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