13

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

int n=1;

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

众所周知,函数 foo() 不能通过n使用 foo(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++ 的设计者引入了复杂的机制来权衡便利。
我对吗?

4

9 回答 9

11

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

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

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

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

值传递通常更可取,因为它限制了函数对“外部世界”的影响——封装、模块化和本地化通常是一件好事。

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

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

于 2012-07-31T08:53:12.073 回答
5

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

编辑以回应更新的问题:

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

想一想。考虑f(10)。使用按值调用,编译器只是10压栈,而函数只是在原地访问值。通过引用调用,编译器必须创建一个临时对象,用 初始化它10,然后将指向它的指针传递给函数。在函数内部,编译器每次访问该值时都必须生成一个间接寻址。

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

于 2012-07-31T08:51:02.450 回答
3

因为 C 按值传递参数。

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

于 2012-07-31T08:45:54.903 回答
1

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

void foo(int& i)
{
    i++;
}
于 2012-07-31T08:49:42.860 回答
0

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

于 2012-07-31T08:49:57.413 回答
0

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

于 2012-07-31T08:49:58.320 回答
0

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

这样做的原因是您可以选择是否希望更改与您的变量保持一致。如果您按值传递,您可以确定它不会改变并导致程序出错。

于 2012-07-31T08:51:46.570 回答
0

C 是按值传递的一个原因是,在 FORTRAN 中,它是按引用传递的,您可以使用“CALL MYROUTINE(3)”之类的调用来调用子例程,并且子例程会更改值其论点。然后,在程序中的那个点之后,“3”将具有子程序赋予它的值。

自然,这件事发生时,引起了很大的混乱。它使错误很难找到,因为源代码所做的事情与它看起来所做的非常不同。

因此,随着人们对编程语言的了解,设计语言时使用的原则之一是避免使代码难以理解或更容易出现错误的事情。(这个原则并不总是成功地应用,因为我们也很想赋予编程语言更多的表达能力,并使编译器能够优化代码。)

于 2012-07-31T09:34:01.590 回答
-1

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

整数 n = 1;

n = foo(n);

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

于 2012-07-31T08:51:56.837 回答