将变量传递给函数时,为什么函数只获取变量的副本/副本?
int n=1;
void foo(int i)
{
i++;
}
Run Code Online (Sandbox Code Playgroud)
众所周知,函数foo()不能通过n使用foo(n)来改变它的值.
当然我们可以传递变量的地址来对参数变量进行一些更改.
但是你不觉得这有点不方便吗?
为什么c/c ++只是为了给函数提供重复而不是直接将"真实"变量本身赋给函数?
这种范式的优点/好处是什么?
更新:
我已经阅读了@ paxdiablo的回答.我认为他的"封装,模块化和效果本地化"的解释是好的.
但在我的方式,它也可以保留参数参数的值.它还可以实现封装.通过这种方式:(假设函数可以直接获取"真实"变量而不是默认的重复)
void foo(int n)
{
int temp=n;
//Do something to temp...
}
Run Code Online (Sandbox Code Playgroud)
在我的方式中,当你想要改变传入的参数值时,可以消除复杂的机制,例如"通过引用传递"或指针.这就是好处.
经过一段时间的思考.我意识到为什么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....}
}
Run Code Online (Sandbox Code Playgroud)
因此,c/c ++的设计者引入了复杂的机制来方便地进行权衡.
我对吗?
在这个问题上基本上是两种思想流派.
第一个是pass-by-value,其中为被调用函数创建值的副本.
第二个是pass-by-reference,其中出现在被调用函数中的参数是原始的"别名".这意味着您对其所做的更改将反映在原始版本中.
C通常是按值传递的语言.您可以通过传递变量的地址来模拟传递引用,然后使用它来修改原始变量:
void setTo42 (int *x) { *x = 42; }
:
int y;
setTo42 (&y);
// y is now 42
Run Code Online (Sandbox Code Playgroud)
但是更多的是将指针传递给变量值,而不是通过引用传递变量本身.
C++有真正的引用类型,可能是因为很多人在使用C指针时遇到问题:-)它们的完成如下:
void setTo42 (int &x) { x = 42; }
:
int y;
setTo42 (y);
// y is now 42
Run Code Online (Sandbox Code Playgroud)
传递值通常是优选的,因为它限制了函数对"外部世界"的影响 - 封装,模块化和效果的定位通常是一件好事.
在模块化和代码管理方面,能够任意修改传入的任何参数几乎与全局变量一样糟糕.
但是,有时您需要传递引用,因为更改传入的其中一个变量可能是有意义的.
大多数现代语言被定义为使用按值传递。原因很简单:如果您知道函数无法更改您的本地状态,则可以大大简化有关代码的推理。如果希望函数能够修改局部状态,则始终可以通过非常量引用进行传递,但是这种情况很少见。
编辑以回答更新的问题:
不,你不对。按值传递是传递参数的最简单机制。通过引用传递或复制/复制输出更为复杂(当然,Algol的表达式替换最复杂)。
考虑一会儿。考虑一下f(10)。通过按值调用,编译器仅压10入堆栈,而函数仅就地访问该值。通过按引用调用,编译器必须创建一个临时文件,使用进行初始化10,然后将指向它的指针传递给该函数。在函数内部,编译器每次访问该值时都必须生成一个间接寻址。
同样,保护函数内部不受修改并不会真正提高可读性。如果该函数不使用任何参考参数,则无需查看函数内部就可以知道它无法修改作为参数传递的任何变量。无论将来有人如何修改此功能。(甚至可能会争辩说,不应允许函数修改全局状态。这会使实现变得rand()相当困难。但是肯定会对优化器有所帮助。)