什么是在C中传递的byValue和byReference参数?

时间:2013-12-07 14:31:52

标签: c

我不明白这意味着什么。如果我试着猜测我会说byValue参数传递就是当你根据变量的值传递一个参数时,所以我在想:

if (a == 1){
 PassAnArgumentOrSomething()
}

然而,这可能是错误的:/

至于参考,我不知道。

如果有人能帮助我,那就太棒了:)

6 个答案:

答案 0 :(得分:4)

除了数组和函数(见下文)之外,C总是传递`by value':每个参数的值的副本被传递给函数;该函数无法修改传递给它的实际参数:

void foo(int j) {
  j = 0;  /*  modifies the copy of the argument received by the function  */
}

int main(void) {
  int k=10;
  foo(k);
  /*  k still equals 10  */
}

如果你想要一个函数来修改它的参数,你可以使用指针参数获得所需的效果:

void foo(int *j) {
  *j = 0;
}

int main(void) {
  int k=10;
  foo(&k);
  /*  k now equals 0  */
}

有时在其他语言中称为“通过引用传递”。

答案 1 :(得分:2)

没有通过引用传递c语言

按值传递:表示您正在创建变量的临时副本并发送到参数。

通过引用传递(c语言中没有这样的概念):意味着您在调用时只是为原始变量指定了另一个名称,并且没有创建变量的临时副本。

按值调用:

int foo(int temp)
{
    /.../
}
int main()
{
    int x;
    foo(x); /* here a temporary copy of the 'x' is created and sent to the foo function.*/

}

通过引用调用(c语言中没有这样的概念)

int foo(int& temp)
{
   /.../
}
int main()
{
    int x;
    foo(x); /* here no temporary copy of 'x' is being created rather the variable *temp* in the calling function is just another name of the variable a in the main function*/
}

答案 2 :(得分:1)

按值传递参数意味着您要传递副本:

void f(int x) 
{ 
    x = 7;
    // x is 7 here, but we only changed our local copy
}

void g()
{
    int y = 3;
    f(y);
    // y is still 3 here!
}

通过引用传递参数意味着您没有传递副本,而是通过某种方式引用原始变量。在C中,所有参数都是按值传递的,但通常用来获得与通过引用传递相同的效果的方法是传递指针:

void f(int *x_ptr) { *x_ptr = 7; }

void g()
{
    int y = 3;
    f(&y);
    // y is 7 here 
}

以这样的方式传递数组,使其看起来类似于传递引用,但实际发生的事情更复杂。例如:

void f(int a[]) { a[0] = 7; }

void g()
{
    int b[3] = {1,2,3};
    f(b);
    // b[0] is 7 here! looks like it was passed by reference.
}

这里实际发生的是数组b被隐式转换为指向第一个元素的指针(这称为衰变)。 int a[]参数的f表示法实际上是指针的语法糖。上面的代码相当于:

void f(int *a) { a[0] = 7; }

void g()
{
    int b[3] = {1,2,3};
    f(&b[0]);
    // b[0] is 7 here
}

答案 3 :(得分:0)

按值传递值是传递值本身;它会复制该值,并且您在新函数中所做的任何更改都不会保存到原始变量中:

void foo(int num)
{
    num = 5; // Does not save to the original variable that was passed when foo was called
...
}

通过引用传递传递变量的位置;它允许新函数直接编辑原始变量:

void bar(int * num)
{
    *num = 5; // Changes the variable in the original function
...
}

答案 4 :(得分:0)

深入解释

每当程序加载时,它会得到一个所谓的地址空间的内存区域,它被分成不同的区域

  1. 代码/文字:包含程序语句(语句集合)。
  2. 全局:包含全局变量(如果有)。
  3. 常量:用于常量或字面存储。
  4. :用于动态内存需求。
  5. 堆栈:函数将其用于变量。
  6. 考虑一个如此定义的函数

    void doSomething(int x)
    {
       x++;
    }//end of function
    

    在另一个函数或主函数中被称为doSomething(5)或doSomething(y)。

    这里 x 是用于“doSomething”功能的局部变量。它在堆栈区域的某处获得它的主页(内存位置)。

    当doSomething(5)被称为 5 被复制到 x 的内存或doSomething(y)被称为 value / content y (不同的内存位置)会被复制到 x的内存。无论在 x 上应用什么操作,都不会影响 y 的内容/值。由于它的记忆位置不同。

    每当执行流程到达功能结束时 x die /被销毁。无论x的值是什么,都无法访问/可用。简而言之,更新丢失且y不受影响(未反映变更)。

    这就是所谓的按值调用

    现在 考虑另一个如此定义的函数

    void doSomething(int *x)
    {
        (*x)++;
    }
    

    被称为doSomething(& y)

    这里 x 被称为指针(概念上称为引用*)。它也会在堆栈区域的某个地方回家 当doSomething(& y)被称为地址y 被复制到 x的位置块时。由于此 x 是特殊变量,因此称为指针,其中包含地址,并且据说 x表示/指向y

    当应用(* x)++ 时,这里*是间接运算符,它将 x 引用 context 即ie。 (* x)++ 会间接地将y的值更改为1. x的值本身不会发生任何事情。

    每当执行流程到达功能结束 * x死亡/被销毁时,正如预期的那样 更改 y (间接),它在堆栈区域的某处仍然存在(更改被反映)。

    也不是这次doSomething(& 5)或doSomething(任何文字)不可能因为非法来获取任何文字的地址。

    这就是所谓的Call by Reference / Call by Pointer。

    请注意,Call by Reference在C ++中具有另一种含义,但在概念上保持不变。

答案 5 :(得分:0)

让我们先看一下“调用”函数。

在C中,函数的参数通常是“按值”。下面,在致电sqrt(x)后,x的值sqrt()未更改为x副本,因此永远无法获得能力影响x

y = sqrt(x);
// x did not change
printf("%f is the square root of %f\n", y, x);

函数的数组参数似乎是“通过引用”。调用fgets()后,预计buf会被更改。 fgets()没有收到char数组的副本,但是“引用”。因此fgets()可能会影响数组的内容。

char buf[80] = { 0 };  // array 80 of char
printf("Before <%s>\n", buf);   // "<>"
fgets(buf, sizeof buf, stdin);
printf("After <%s>\n", buf);    // "<Hello World!>"

现在让我们来看看“接收”部分:功能。

类型doubleintstruct类型的函数参数按值接收。这里f的值是上面x副本。对f所做的任何更改都不会影响调用代码中的x

double sqrt(double f) {
  double y;
  ... // lots of code
  return y;
}

现在是棘手的一点,这是C中有很多讨论的地方。

下面的s中的参数fgets()未分配上面的buf(char的数组80),而是为s分配了指针类型派生自bufbuf的第一个元素的地址。通过了解buf(通过s)数组元素的地址,fgets()会影响上面打印的内容。

char *fgets(char * restrict s, int n, FILE * restrict stream) {
  // code
  s[i] = ThisAndThat();
  // code
  return s;
}

现在让我们看看如何调用fgets()

char *p = malloc(80);
*p = '\0';
printf("Before <%s>\n", p);   // "<>"
fgets(p, 80, stdin); 
printf("After <%s>\n", p);    // "<Hello World!>"

在第二个例子中,p是“指向char的指针”。它由传递给fgets()fgets()已通过s收到p副本

中心思想:fgets()如果收到“数组第一个元素的地址”或“指向char的指针”的副本,则不会知道。在这两种情况下,它都将s视为“指向char的指针”。

我们假设fgets()做了以下事情。在s更改之前,它会影响s指向的数据。然后s指针改变了。 s本地变量,此分配不会更改调用例程变量bufp

char *fgets(char * restrict s, int n, FILE * restrict stream) {
  // lots of code
  s[0] = '\0';
  // more code
  s = NULL;
  return s;
}

注意:还有其他问题,例如将函数作为参数传递,并在要考虑的结构中封装数组。