关于C#:为何使用&为带*的函数传递值

Why use & to pass value for function with *?

我想问一下作者,caf,从C语言中的函数和指针的理解

我意识到我不能在同一页上问这个问题。

我仍然对使用&;将指针的值传递给函数感到困惑。我一直认为Q只是传递Q的地址,如何将Q的值转换为int sqp(int*x)?


没有"翻译"。

你的功能

1
int sqp(int *x);

取一个参数,x,类型为int *,即"指向整数的指针"。

所以,要调用它,需要将指针传递给一个整数,即一个整数的地址。

&前缀运算符用于计算其参数的地址,因此可以执行以下操作:

1
2
int foo = 4711;
sqp(&foo);

用变量foo的地址调用sqp()函数。


在按引用调用的情况下,会传递一个地址,以便可以通过引用地址(即引用)进行更改;如果在参数中传递地址,则应该具有指向该地址的某种机制。指针是指向地址的东西,因此在调用时,如果传递了地址,则必须在定义中使用指针。离子指向它。例子。

1
2
3
4
5
6
7
calling(&a); //passing address

void calling(int *b) //Pointing to address of 'a' via pointer 'b'
{  
 //some code

}


就像你说的,&q将变量q的内存地址传递给函数,所以我们发送给函数的只是q的地址。函数不需要转换任何值,因为它直接访问原始值,因为它的地址存储在指针x中,并且每次您对*执行类似*x=7;的操作时,都会取消对变量的引用,这意味着它不修改变量x,而是修改任何ocx1〔2〕指向。


使用:

1
sqp(&q);

将EDOCX1的地址(0)作为函数int sqp(int *x)中的参数传递。

从现在开始,在这个函数内部,使用x就可以得到这个地址本身。

使用*x可以在内存中获得此地址中包含的值。

这就是我们如何在C中"模拟"pass by reference,通过值传递变量本身的地址作为函数中的参数。


那么让我们再看一下sqp函数定义:

1
int sqp( int *x ) { ... }

C中的声明基于表达式的类型,而不是对象;如果您有一个指向名为x的整数的指针,并且您希望访问被指向的整数值,则可以使用一元*运算符取消对x的引用,如下所示:

1
int y = *x;

表达式*x的类型是int,因此变量x的声明编写为

1
int *x;

当你听到有人使用"声明模仿使用"这个短语时,这就是他们的意思。

当我们调用函数时

1
y = sqp( &q );

表达式&q生成q的地址,表达式类型为int *sqp中的参数x接收该地址值。

因此,sqp中的表达式*x相当于调用函数中的表达式q;两个表达式在内存中引用同一对象,并且都计算为同一值。同样,sqp中的表达式x与调用函数中的表达式&q相等;两者都将计算到q的地址。


是的,&qq的地址。q的值不是"翻译的"—只是如果您有q的地址,您可以使用该地址访问对象q本身。


从链接问题的答案中稍微缩短示例:

1
2
3
4
5
6
7
8
void sqp(int *x) {
   *x = 10;
}

void foo() {
    int value = 42;
    sqp(&value);
}

所以sqp是一个函数,它希望通过参数返回数据,这意味着它必须知道在哪里写入数据。这个信息是一个指针——要使用的内存地址。当传递C语言时,不会自动传递指针,但是像sqp(value);这样的语句(如果编译器由于不兼容的类型而不禁止)会传递值,在本例中是42。然后,函数sqp将看到42并将其解释为地址,并尝试写入内存位置42,而该位置很可能不是数据应该到达的位置。

现在的问题是为什么编译器不能自己进行演绎。函数需要一个指向int的指针,我们提供了一个int,以便可以自动推导它。

我认为至少有两个理由不做扣除

  • 它使调用代码更清晰——&告诉读者我们正在传递地址,并且值可能会更改。
  • 在所有情况下都不可能扣除。也就是说,对于一个期望void *的函数,编译器可能不清楚在已经提供指针的情况下是否需要额外的级别。

嗯,你知道指针吗?我想你会的。^

传递论点有两种方法。传递值和传递引用。

也许您通常使用传递值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

void foo(int i)
{
    printf("[foo] `i` was %d
"
, i);
    i++;
    printf("[foo] Now `i` is %d
"
, i);
}

int main()
{
    int i = 0;
    printf("[main] `i` was %d
"
, i);
    foo(i);
    printf("[main] Now `i` is %d
"
, i);
}

输出为:(实况示例)

1
2
3
4
[main] `i` was 0
[foo] `i` was 0
[foo] Now `i` is 1
[main] Now `i` is 0

是的,main()i没有改变!为什么?

因为i是按值传递的。当foo(i)运行时,复制i的值,foo使用副本,而不是原来的i使用副本。所以不能改变。


但是,您已经看到了改变参数的函数——例如,scanf

1
2
3
4
5
int main()
{
    int i = 0;
    scanf("%d", &i);    /* `i` is changed!! */
}

如何改变?因为scanf使用pass-by-ref。看这个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

void foo(int *pi)
{
    printf("[foo] `i` was %d
"
, *pi);
    (*pi)++; /* please be careful ^o^ */
    printf("[foo] Now `i` is %d
"
, *pi);
}

int main()
{
    int i = 0;
    printf("[main] `i` was %d
"
, i);
    foo(&i);
    printf("[main] Now `i` is %d
"
, i);
}

输出为:(实况示例)

1
2
3
4
[main] `i` was 0
[foo] `i` was 0
[foo] Now `i` is 1
[main] Now `i` is 1

怎么可能?因为我们传递的是i的指针,而不是i的副本。fooi的指针,可以访问i的指针,main的指针。我们称之为参照传递。

希望它能帮助你!