如果C语言不支持通过引用传递变量,为什么这样做呢?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
输出:
$ gcc -std=c99 test.c
$ a.exe
i = 21
如果C语言不支持通过引用传递变量,为什么这样做呢?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
输出:
$ gcc -std=c99 test.c
$ a.exe
i = 21
当前回答
我认为C实际上支持引用传递。
大多数语言要求语法糖通过引用而不是值传递。(例如,c++在参数声明中要求&)。
C也需要语法糖。在形参类型声明中是*,在实参中是&。*和&是C语言中引用传递的语法。
现在有人可能会说,真正的引用传递应该只要求参数声明的语法,而不是参数方面的语法。
但是现在出现了c#,它支持引用传递,并且在参数和参数方面都需要语法糖。
C没有by-ref传递的参数导致表达它的语法元素显示底层技术实现,这根本不是一个参数,因为这或多或少适用于所有实现。
唯一剩下的论点是,在C中传递ref不是一个单一的特征,而是结合了两个现有的特征。(获取ref的参数为&,期望ref的类型为*。)例如,c#确实需要两个语法元素,但它们不能单独使用。
这显然是一个危险的论点,因为语言中的许多其他特征是由其他特征组成的。(类似c++中的字符串支持)
其他回答
您的示例之所以能够工作,是因为您将变量的地址传递给了一个使用解引用操作符操作其值的函数。
虽然C不支持引用数据类型,但您仍然可以通过显式传递指针值来模拟引用传递,如您的示例所示。
c++引用数据类型功能较弱,但被认为比继承自C的指针类型更安全。这将是您的示例,改编为使用c++引用:
void f(int &j) {
j++;
}
int main() {
int i = 20;
f(i);
printf("i = %d\n", i);
return 0;
}
P是一个指针变量。它的值是i的地址。当你调用f时,你传递p的值,它是i的地址。
将指针称为引用(如Java和Javascript所做的)与引用传递(pass-by-reference)是完全不同的用法。C不支持引用传递。下面是重新编写的示例,以显示它不是真正地通过引用传递值,而是通过值传递指针。
#include <stdio.h>
void f(int *j) {
int k = (*j) + 1;
j = &k;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
printf("j = %d\n", *p);
printf("i(ptr) = %p\n", &i);
printf("j(ptr) = %p\n", p);
return 0;
}
这是输出
i = 20
j = 20
i(ptr) = 0x7ffdfddeee1c
j(ptr) = 0x7ffdfddeee1c
如您所见,值保持不变,但更重要的是指针也没有改变。然而,c++允许通过引用传递。下面是通过c++编译器实现的相同示例,但在头文件中添加了&号,使其成为引用参数。
#include <stdio.h>
void f(int *&j) { // note the & makes this a reference parameter.
// can't be done in C
int k = (*j) + 1;
j = &k;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
printf("j = %d\n", *p);
printf("i(ptr) = %p\n", &i);
printf("j(ptr) = %p\n", p);
return 0;
}
这是输出
i = 20
j = 21
i(ptr) = 0x7ffcb8fc13fc
j(ptr) = 0x7ffcb8fc13d4
注意,我们可以改变实际的指针!
作为参考,The Dragon Book是一本关于编译器的经典计算机科学教科书。因为它是有史以来最受欢迎的编译器书籍(至少在我上大学的时候是这样,也许我错了),我猜绝大多数设计语言或编写编译器的人都是从这本书中学习的。本书的第一章非常清楚地解释了这些概念,并解释了为什么C语言只采用值传递。
代码片段(有微小修改)
void add_number(int * const a) {
*a = *a + 2;
}
在c++中也存在,在语义上等价于
void add_number(int &a) {
a = a + 2;
}
在这两种情况下,编译器都希望生成相同的add_number函数二进制代码。现在,当您将一个整数视为一个值时,该值将由它的引用传递,在上面的模式中,引用在技术上显示为指针。
结论 C支持通过引用传递实例的语义。 即使在技术上使用int *a你也传递了*a,它是一个引用。
你不是通过引用传递int型,而是通过值传递指向int型的指针。不同的语法,相同的意思。