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

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

int n=1; void foo(int i) { i++; } 

众所周知,函数foo()不能通过使用foo(n)来改变n的值。

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

为什么c / c ++只是为函数提供重复而不是直接将“真实”变量本身赋给函数?
这种范式的优点/好处是什么?


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

 void foo(int n) { int temp=n; //Do something to temp... } 

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

经过一段时间的思考。 我意识到为什么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 ++的设计者引入了复杂的机制来方便地进行权衡。
我对吗?

在这个问题上基本上是两种思想流派。

第一个是pass-by-value,其中为被调用函数创建值的副本

第二个是pass-by-reference,其中出现在被调用函数中的参数是原始的“别名”。 这意味着您对其所做的更改将反映在原始版本中。

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 

传递值通常是优选的,因为它限制了函数对“外部世界”的影响 – 封装,模块化和效果的本地化通常是一件好事。

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

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

大多数现代语言被定义为使用pass by value。 原因很简单:如果您知道函数无法更改本地状态,则可以显着简化代码推理。 如果希望函数能够修改局部状态,则总是可以通过非const引用传递,但是这种情况应该非常罕见。

已编辑以回复更新的问题:

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

想一想。 考虑f(10) 。 通过按值调用,编译器只需在堆栈上推送10 ,并且该函数只是在原位访问该值。 通过引用调用,编译器必须创建一个临时的,用10初始化它,然后将指针传递给该函数。 在函数内部,编译器必须在每次访问值时生成间接。

此外,防止function内部的修改并不能真正帮助实现可读性。 如果函数没有引用参数,你就知道它没有在函数内部查看它不能修改你作为参数传递的任何变量。 无论人们将来如何修改该function。 (人们甚至可以争辩说,不应该允许函数修改全局状态。这会使rand()的实现变得相当困难。但肯定会帮助优化器。)

因为C按值传递参数。

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

如果你真的想要一个函数来改变它的实际参数,你可以在C ++中通过引用传递它

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

这是为了确保该function不会改变原始值。

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

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

这样做的原因是您可以选择是否要更改以坚持您的变量。 如果您通过值传递,则可以确保它不会更改并导致程序出错。

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

int n = 1;

n = foo(n);

只需确保foo(int i)在修改后返回i。

C是值传递的一个原因是在FORTRAN中,它是传递引用,你可以用“CALL MYROUTINE(3)”之类的调用来调用子程序,子程序会改变值它的论点。 然后,在程序中的那一点之后,“3”将具有子程序给它的值。

当然,当这发生时,它引起了很大的混乱。 它使得很难找到错误,因为源代码做了一些与它看起来非常不同的东西。

因此,随着人们学习编程语言,设计语言时使用的原则之一就是避免使代码难以理解或使错误更容易发生的事情。 (这个原则并不总是成功应用,因为我们也倾向于赋予编程语言更强的表达能力,并使编译器能够优化代码。)