通过C中的引用传递

aks*_*aks 200 c pointers pass-by-reference

如果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;
}
Run Code Online (Sandbox Code Playgroud)

产量

$ gcc -std=c99 test.c
$ a.exe
i = 21 
Run Code Online (Sandbox Code Playgroud)

tva*_*son 308

因为您将指针的值传递给方法,然后取消引用它以获取指向的整数.

  • 度f(p); - >这是否意味着通过价值?**然后取消引用它以获得指向的整数.** - >请你提供更多解释. (4认同)
  • @bapi,取消引用指针意味着"获取此指针引用的值". (4认同)
  • 使用指针时,关键事实是**指针的副本** 被传递到函数中。该函数然后使用该指针,而不是原始指针。这仍然是按值传递,但它有效。 (2认同)
  • @Danijel可以将不是任何副本的指针传递给函数调用。例如,调用函数 `func`: `func(&amp;A);` 这会将指向 A 的指针传递给函数,而不复制任何内容。它是按值传递,但该值是一个引用,因此您可以“按引用传递”变量 A。无需复制。说它是按引用传递是有效的。 (2认同)

Ely*_*Ely 109

这不是传递参考,而是像其他人所说的那样传递价值.

C语言无一例外都是按值传递的.将指针作为参数传递并不意味着通过引用传递.

规则如下:

功能无法更改实际参数值.


让我们试着看一下函数的标量和指针参数之间的区别.

标量变量

这个简短的程序使用标量变量显示pass-by-value.param被称为形式参数,variable在函数调用时称为实际参数.注意param函数中的递增不会改变variable.

#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;
}
Run Code Online (Sandbox Code Playgroud)

结果是

I've received value 111
variable=111
Run Code Online (Sandbox Code Playgroud)

传递参考的错觉

我们稍微改变了一段代码.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;
}
Run Code Online (Sandbox Code Playgroud)

结果是

I've received value 111
variable=112
Run Code Online (Sandbox Code Playgroud)

这让你相信参数是通过引用传递的.它不是.它是通过值传递的,param值是一个地址.int类型值增加了,这就是让我们认为它是一个pass-by-reference函数调用的副作用.

指针 - 按值传递

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

#include <stdio.h>

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

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

    function2(ptr);
    printf("ptr's address %d\n", ptr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

示例结果:

param's address -1846583468
ptr's address -1846583468
Run Code Online (Sandbox Code Playgroud)

在我看来,这清楚地证明了指针是按值传递的.否则ptrNULL在函数调用之后.

  • “ptr's address”不正确:您打印指针,它是变量的地址,而不是它的地址,这将是 'printf("ptr's address %d\n", &amp;ptr);' 。传递引用的技术层就是传递指针,而不是幻觉!在function2中,*param实际上是一个引用。 (3认同)

小智 69

在C中,通过传递变量的地址(指针)并在函数内取消引用该地址来读取或写入实际变量来模拟传递引用.这将被称为"C风格传递参考".

资料来源:www-cs-students.stanford.edu


Ale*_*ler 49

因为上面的代码中没有pass-by-reference.使用指针(例如void func(int* p))是pass-by-address.这是C++中的pass-by-reference(在C中不起作用):

void func(int& ref) {ref = 4;}

...
int a;
func(a);
// a is 4 now
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢_pass-by-address_ 答案。更有意义。 (3认同)
  • 在这种情况下,地址和参考号是同义词。但是你可以使用这些术语来区分两者,但这并不忠实于它们的原始含义。 (3认同)

Dan*_*llo 27

您的示例有效,因为您将变量的地址传递给使用dereference运算符操作其值的函数.

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

C++引用数据类型功能较弱,但被认为比从C继承的指针类型更安全.这将是您的示例,适用于使用C++引用:

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

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

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 维基百科的文章是关于C++而不是C.在C++之前存在引用,并且不依赖于特殊的C++语法. (2认同)
  • @Roger:好点……我从答案中删除了对 C++ 的显式引用。 (2认同)

ant*_*upe 12

按值传递指针(地址位置).

这就像是说"这里是我希望你更新数据的地方."


小智 7

简短回答:是的,C 确实使用指针通过引用实现参数传递。

在实现参数传递时,编程语言的设计者使用三种不同的策略(或语义模型):将数据传输到子程序,从子程序接收数据,或两者兼而有之。这些模型通常相应地称为输入模式、输出模式和输入输出模式。

语言设计者设计了几种模型来实现这三种基本参数传递策略:

Pass-by-Value(in 模式语义) Pass-by-Result(out 模式语义) Pass-by-Value-Result(inout 模式语义) Pass-by-Reference(inout 模式语义) Pass-by-Name(inout 模式语义)语义)

按引用传递是 inout 模式参数传递的第二种技术。运行时系统不是在主例程和子程序之间来回复制数据,而是向子程序发送对数据的直接访问路径。在此策略中,子程序可以直接访问数据,有效地与主例程共享数据。这种技术的主要优点是它在时间和空间上绝对高效,因为不需要复制空间,也没有数据复制操作。

C 中的参数传递实现:C 使用指针作为参数来实现按值传递和按引用传递(inout 模式)语义。指针被发送到子程序,并且根本不复制任何实际数据。然而,由于指针是主程序数据的访问路径,因此子程序可能会改变主程序中的数据。C 采用了 ALGOL68 中的这种方法。

C++ 中的参数传递实现:C++ 还使用指针以及一种称为引用类型的特殊指针来实现引用传递(inout 模式)语义。引用类型指针在子程序内隐式取消引用,但它们的语义也是按引用传递。

因此,这里的关键概念是引用传递实现了数据的访问路径,而不是将数据复制到子程序中。数据访问路径可以是显式解引用指针或自动解引用指针(引用类型)。

有关更多信息,请参阅 Robert Sebesta 所著的《Concepts of Programming Languages》一书,第 10 版,第 9 章。


Ans*_*ssi 6

p是指针变量.它的值是i的地址.当你调用f时,你传递 p 的值,这是i的地址.


Pav*_*sky 6

C中没有传递引用,但是p"引用"i,并且您通过值传递p.


t0m*_*13b 5

在 C 中,要通过引用传递,您可以使用&应该针对变量使用的地址运算符,但在您的情况下,由于您使用了指针变量p,因此不需要在其前面添加地址运算符作为前缀。&i如果您使用以下参数作为参数,那就是真的f(&i)

您还可以添加此内容以取消引用p并查看该值如何匹配i

printf("p=%d \n",*p);
Run Code Online (Sandbox Code Playgroud)


Aru*_*esh 5

在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
Run Code Online (Sandbox Code Playgroud)