Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当将变量传递给函数时,为什么函数只获取变量的副本?_C++_C - Fatal编程技术网

C++ 当将变量传递给函数时,为什么函数只获取变量的副本?

C++ 当将变量传递给函数时,为什么函数只获取变量的副本?,c++,c,C++,C,将变量传递给函数时,为什么函数只获取变量的副本 int n=1; void foo(int i) { i++; } 众所周知,函数foo()不能通过使用foo(n)来更改n的值 当然,我们可以传递变量的地址来对参数变量进行一些更改。 但是你不觉得这有点不方便吗 为什么c/c++设计为只给函数一个副本,而不是直接给函数一个“实”变量本身? 这种模式的优点/好处是什么 更新: 我已经读了@paxdiablo的答案。我认为他的“效果的封装、模块化和本地化”解释很好。 但在我看来,它也可以

将变量传递给函数时,为什么函数只获取变量的副本

int n=1;

void foo(int i)
{
    i++;
}
众所周知,函数foo()不能通过使用foo(n)来更改
n
的值

当然,我们可以传递变量的地址来对参数变量进行一些更改。
但是你不觉得这有点不方便吗

为什么c/c++设计为只给函数一个副本,而不是直接给函数一个“实”变量本身?
这种模式的优点/好处是什么


更新:
我已经读了@paxdiablo的答案。我认为他的“效果的封装、模块化和本地化”解释很好。
但在我看来,它也可以保留参数参数的值。它还可以实现封装。通过这种方式:(假设函数可以直接获取“real”变量,而不是默认情况下的重复变量)

以我的方式,当您想要更改传入参数的值时,可以消除复杂的机制,例如“通过引用传递”或指针。这就是好处

经过一段时间的思考。我意识到为什么c/c++没有像我建议的那样设计,只是因为我的方式不合理
以我的方式,如果一个函数有一长串的变量,它会变得很糟糕。我认为更方便的方法实际上是不方便的:
你必须这样写:

void foo(int a,int b,double c,float d,char s...)
{
    int temp1=a;
    int temp2=b;
    double temp3=c;
    float temp4=d;
    char temp5=s;
    ...
    //Do something to temp{1,2,3,4,5....}

}
因此,c/c++的设计者引入了复杂的机制,以方便地进行权衡。

我说得对吗?

因为C按值传递参数


来自Kernighan&Richtie第二版:(1.8按值调用)在C中,所有函数参数都是通过“值”传递的。

如果您确实希望函数更改其实际参数,可以在C中通过引用传递它++

void foo(int& i)
{
    i++;
}

这是为了确保函数不会更改原始值

我想一个原因是效率,直接访问值比通过指针访问更有效。另一个优点是选择,即C/C++方式,您可以选择通过值或指针传递参数,而您的方式只能选择通过指针传递参数。但最重要的是,通过值传递意味着函数与代码的其余部分隔离,对函数内部变量的更改不会影响代码的其余部分。相信我,如果不是这样的话,你会遇到更多的bug,编码也会变得更加困难。

大多数现代语言都被定义为使用传递值。原因是 简单:如果您知道,它可以显著简化关于代码的推理 函数不能更改您的本地状态。如果希望函数能够修改本地状态,则始终可以传递非常量引用,但这种情况应该非常罕见

编辑以回答更新的问题:

不,你不对。传递值是传递参数的最简单机制。通过引用传递或复制/复制更复杂(当然,Algol的表达式替换是最复杂的)

想一想。考虑<代码> f(10)< /代码>。通过值调用,编译器只需在堆栈上推送
10
,函数只需就地访问值。通过引用调用,编译器必须创建一个临时函数,用
10
初始化它,然后将指向它的指针传递给函数。在函数内部,编译器必须在每次访问该值时生成一个间接寻址


此外,保护函数不受内部修改并不能真正提高可读性。如果函数不接受引用参数,则不必查看函数内部就知道它无法修改作为参数传递的任何变量。不管将来有人如何修改函数。(有人甚至会争辩说,不应允许函数修改全局状态。这将使
rand()
的实现变得相当困难。但肯定会帮助优化器。)

为了更改参数的值,需要使用“&”符号通过引用传递


这样做的原因是,您可以选择是否希望更改与变量保持一致。如果通过值传递,则可以确保该值不会更改并在程序中导致错误。

根据您尝试执行的操作,您可以执行以下操作:

int n=1

n=foo(n)


只需确保foo(inti)在修改后返回i即可。

关于这个问题,基本上有两种观点

第一个是传递值,其中为被调用函数创建值的副本

第二种是通过引用传递,其中被调用函数中出现的参数是原始函数的“别名”。这意味着您对其所做的更改将反映在原始文档中

C通常是一种传递值语言。通过传递变量的地址,然后使用该地址修改原始地址,可以模拟按引用传递:

void setTo42 (int *x) { *x = 42; }
:
int y;
setTo42 (&y);
// y is now 42
但这更多的是通过值传递指向变量的指针,而不是通过引用传递变量本身

C++有真正的引用类型,可能是因为太多人在使用C指针时遇到问题:-)它们的操作如下:

void setTo42 (int &x) { x = 42; }

:
int y;
setTo42 (y);
// y is now 42
传递值通常更可取,因为它限制了函数对“外部世界”的影响——封装、模块化和效果本地化通常是一件好事

在模块化和代码管理方面,能够任意修改传入的任何参数几乎与全局变量一样糟糕


但是,有时您需要通过引用传递,因为更改传入的一个变量可能是有意义的。

C是通过值传递的一个原因是,在FORTRAN中,这是通过引用传递的,您可以使用类似“call MYROUTINE(3)”的调用调用子例程,并且子例程
void setTo42 (int &x) { x = 42; }

:
int y;
setTo42 (y);
// y is now 42