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
因为您将指针的值传递给方法,然后取消引用它以获取指向的整数.
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)
在我看来,这清楚地证明了指针是按值传递的.否则ptr
将NULL
在函数调用之后.
小智 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)
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)
小智 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 章。
在 C 中,要通过引用传递,您可以使用&
应该针对变量使用的地址运算符,但在您的情况下,由于您使用了指针变量p
,因此不需要在其前面添加地址运算符作为前缀。&i
如果您使用以下参数作为参数,那就是真的f(&i)
。
您还可以添加此内容以取消引用p
并查看该值如何匹配i
:
printf("p=%d \n",*p);
Run Code Online (Sandbox Code Playgroud)
在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)