如果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++引用:
void f(int &j) {
j++;
}
int main() {
int i = 20;
f(i);
printf("i = %d\n", i);
return 0;
}
其他回答
简单回答:是的,C确实使用指针通过引用实现了参数传递。
在实现参数传递时,编程语言的设计者使用三种不同的策略(或语义模型):将数据传输到子程序,从子程序接收数据,或者两者都做。这些模型通常分别称为in模式、out模式和inout模式。
语言设计者设计了几个模型来实现这三个基本参数传递策略:
值传递(在模式语义中) 结果传递(out模式语义) 值-结果传递(inout模式语义) 引用传递(inout模式语义) 名称传递(inout模式语义)
Pass-by-reference is the second technique for inout-mode parameter passing. Instead of copying data back and forth between the main routine and the subprogram, the runtime system sends a direct access path to the data for the subprogram. In this strategy the subprogram has direct access to the data effectively sharing the data with the main routine. The main advantage with this technique is that its absolutely efficient in time and space because there is no need to duplicate space and there is no data copying operations.
C中的参数传递实现: C使用指针作为参数实现了值传递和引用传递(inout模式)语义。指针被发送到子程序,根本不复制实际数据。然而,由于指针是主例程数据的访问路径,子程序可以改变主例程中的数据。C采用了ALGOL68的方法。
c++中的参数传递实现: c++还使用指针实现了引用传递(inout模式)语义,也使用了一种特殊类型的指针,称为引用类型。引用类型指针在子程序内部隐式地解引用,但它们的语义也是引用传递的。
这里的关键概念是引用传递实现了数据的访问路径,而不是将数据复制到子程序中。数据访问路径可以是显式解引用指针或自动解引用指针(引用类型)。
有关更多信息,请参阅Robert Sebesta所著的《编程语言的概念》,第10版,第9章。
将指针称为引用(如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语言只采用值传递。
你所做的是传递值,而不是传递引用。 因为你正在将变量'p'的值发送给函数'f'(在main中为f(p);)
在C语言中,同样的程序通过引用传递看起来像,(!!这个程序给出了2个错误,因为C不支持引用传递)
#include <stdio.h>
void f(int &j) { //j is reference variable to i same as int &j = i
j++;
}
int main() {
int i = 20;
f(i);
printf("i = %d\n", i);
return 0;
}
输出:
3:12: error: expected ';', ',' or ')' before '&' token void f(int &j); ^ 9:3: warning: implicit declaration of function 'f' f(a); ^
“通过引用传递”(通过使用指针)从一开始就存在于C语言中。你为什么不这么认为?
因为你传递了一个指向变量p的指针(内存地址)到函数f中。换句话说,你传递的是一个指针而不是一个引用。