如果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确实使用指针通过引用实现了参数传递。

在实现参数传递时,编程语言的设计者使用三种不同的策略(或语义模型):将数据传输到子程序,从子程序接收数据,或者两者都做。这些模型通常分别称为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章。

您的示例之所以能够工作,是因为您将变量的地址传递给了一个使用解引用操作符操作其值的函数。

虽然C不支持引用数据类型,但您仍然可以通过显式传递指针值来模拟引用传递,如您的示例所示。

c++引用数据类型功能较弱,但被认为比继承自C的指针类型更安全。这将是您的示例,改编为使用c++引用:

void f(int &j) {
  j++;
}

int main() {
  int i = 20;
  f(i);
  printf("i = %d\n", i);

  return 0;
}

我认为C实际上支持引用传递。

大多数语言要求语法糖通过引用而不是值传递。(例如,c++在参数声明中要求&)。

C也需要语法糖。在形参类型声明中是*,在实参中是&。*和&是C语言中引用传递的语法。

现在有人可能会说,真正的引用传递应该只要求参数声明的语法,而不是参数方面的语法。

但是现在出现了c#,它支持引用传递,并且在参数和参数方面都需要语法糖。

C没有by-ref传递的参数导致表达它的语法元素显示底层技术实现,这根本不是一个参数,因为这或多或少适用于所有实现。

唯一剩下的论点是,在C中传递ref不是一个单一的特征,而是结合了两个现有的特征。(获取ref的参数为&,期望ref的类型为*。)例如,c#确实需要两个语法元素,但它们不能单独使用。

这显然是一个危险的论点,因为语言中的许多其他特征是由其他特征组成的。(类似c++中的字符串支持)

C中没有引用传递,但是p“指向”i,你通过值传递p。

在C语言中,一切都是值传递。指针的使用给我们一种通过引用传递的错觉,因为变量的值发生了变化。但是,如果您要打印指针变量的地址,您将看到它不会受到影响。地址值的副本被传递给函数。下面是一个演示片段。

void add_number(int *a) {
    *a = *a + 2;
}

int main(int argc, char *argv[]) {
   int a = 2;

   printf("before pass by reference, a == %i\n", a);
   add_number(&a);
   printf("after  pass by reference, a == %i\n", a);

   printf("before pass by reference, a == %p\n", &a);
   add_number(&a);
   printf("after  pass by reference, a == %p\n", &a);

}

before pass by reference, a == 2
after  pass by reference, a == 4
before pass by reference, a == 0x7fff5cf417ec
after  pass by reference, a == 0x7fff5cf417ec