如果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 

当前回答

你所做的是传递值,而不是传递引用。 因为你正在将变量'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实际上支持引用传递。

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

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

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

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

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

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

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

这不是引用传递,而是其他人所说的值传递。

C语言毫无例外地采用值传递。传递指针 作为参数并不意味着引用传递。

规则如下:

函数不能改变实际的参数值。

(以上引自《K&R》一书)


让我们试着看看函数的标量形参和指针形参之间的区别。

标量变量

这个简短的程序展示了使用标量变量的值传递。参数被称为形式参数,函数调用时的变量被称为实际参数。注意在函数中增加参数并不会改变变量。

#include <stdio.h>

void function(int param) {
    printf("I've received value %d\n", param);
    param++;
}

int main(void) {
    int variable = 111;

    function(variable);
    printf("variable %d\m", variable);
    return 0;
}

结果是

I've received value 111
variable=111

引用传递的错觉

我们稍微改变了这段代码。Param现在是一个指针。

#include <stdio.h>

void function2(int *param) {
    printf("I've received value %d\n", *param);
    (*param)++;
}

int main(void) {
    int variable = 111;

    function2(&variable);
    printf("variable %d\n", variable);
    return 0;
}

结果是

I've received value 111
variable=112

这使您相信参数是通过引用传递的。但事实并非如此。它通过值传递,参数值是一个地址。int类型的值增加了,这是副作用,使我们认为这是一个引用传递函数调用。

指针——按值传递

我们如何证明那个事实?好吧,也许我们可以尝试标量变量的第一个例子,但我们使用地址(指针)而不是标量。让我们看看这是否有帮助。

#include <stdio.h>

void function2(int *param) {
    printf("address param is pointing to %d\n", param);
    param = NULL;
}

int main(void) {
    int variable = 111;
    int *ptr = &variable;

    function2(ptr);
    printf("address ptr is pointing to %d\n", ptr);
    return 0;
}

结果将是两个地址相等(不要担心确切的值)。

结果示例:

address param is pointing to -1846583468
address ptr   is pointing to -1846583468

在我看来,这清楚地证明了指针是按值传递的。否则,函数调用后ptr将为NULL。

指针和引用是两个不同的东西。

有几件事我没有看到有人提到。

指针是某物的地址。指针可以像其他变量一样存储和复制。因此,它有一个大小。

引用应该被视为某个东西的别名。它没有大小,不能存储。它一定是指什么。不能为空或更改。好吧,有时候编译器需要将引用存储为指针,但这是实现细节。

有了引用,你就不会有指针的问题,比如所有权处理、空检查、使用时取消引用。

您正在按值传递一个指针(地址位置)。

这就像是在说“这里有我想让你更新的数据”。

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

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

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

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

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

  return 0;
}