我们在用户输入期间使用 & 符号,但为什么我们在 C 中的赋值期间不需要它?

We use ampersand during user input but Why we don't need this during assignment in C?

我们在用户输入时使用 & 运算符。这意味着我们正在将特定值分配给特定变量的内存地址。但是在赋值期间,我们不需要&符号。在没有任何内存地址规范的情况下如何传递值?示例代码如下。

#include<stdio.h>

int main()
{
    int a, b, total;
    scanf("%d%d", &a, &b); //& for memory address
    total = a+b;           //how the value is being tranfarred to total without any memory address?   
    printf("%d", total);

    return 0;
}

赋值是一种 C 语言结构。

C 知道赋值不是对其左侧操作数的值起作用,而是对其地址*起作用。你不需要明确地说 &

对于用户定义的函数,尤其是无原型的旧式函数(未指定参数类型)和可变参数函数,如 scanf,C 无法知道他们想要什么——他们可能想要地址,或者他们可能同样需要该值,因此您必须通过在前面加上或不在前面加上和号来指定它。

现在有一个原型函数,例如:

void take_address(int *x);

理论上你可以扩展语言,这样

void use_take_address(void){ int x=42;  take_address(x); }

会隐含地获取参数的地址(毕竟 C++ 对引用做了类似的事情),但它会,可以说,伤害 可读性。

有了&x你可以肯定这个函数理论上至少可以修改x;没有 & 你可以或多或少地确定它不能(除非 x 是一个数组)。

这是一种语言设计选择。


*这实际上不是 100% 准确。赋值也可能与没有地址的基于寄存器的变量一起工作,并且在 C 中对变量使用 & 实际上会使它不能被显式标记为 register,但这些是细节一个好的优化器可以通过。

变量是一个抽象单元,具有与之关联的地址。 使用 int var 等语法声明的变量表示位于特定地址 &var.

上的值

scanf 期望指向变量的指针,即地址,这就是您使用&符号的原因。这是必需的,因为当您将变量传递给函数时(没有&符号),您只传递它们的值,而不是实际变量的地址信息。 有些人喜欢说,当你将一个变量传递给一个函数时,该函数取变量的的"a copy"。

如果你想 decalre 指针(代表其特定类型地址的变量,而不是值)你这样做: int* var; 该变量将用于尝试访问类型为 int 的另一个变量,方法是将其地址分配给它。 int* var = &some_int

以下面的场景为例。你想创建一个函数,将一些值存储在传递给它的变量中。为此,您必须像这样定义函数:

void foo (int* var)
{
*var = 1; // * is the de-reference operator which shows the value of the address `var` and we assign the value to 1.
}

scanf 函数必须访问正在读取值的 对象 。所有 C 函数参数都是按值传递的,所以如果你写

int a, b;
scanf("%d%d", a, b); // THIS IS WRONG

scanf 函数只能看到 ab 函数被调用时的值。它将无法修改 a.

赋值需要一个左值作为它的左操作数。左值(稍微简化)是指定对象的表达式;变量名是最常见的一种左值。由于赋值运算符 = 内置于该语言中,因此它可以有适用于它的特殊规则。特别是,= 的 LHS 上的左值标识了被分配给的对象;它不会产生该对象的(先前)值。这就是语言定义赋值的方式。

例如,如果你写:

a = b;

ab 都是左值,但由于它们的上下文,它们被区别对待。 a指的是名称为a的对象。 b 也引用一个对象,但在该上下文中它产生该对象的当前值。

如果赋值是作为函数调用实现的,它必须获取被赋值对象的地址:

int assign(int *lhs, int rhs);
assign(&a, b);

语言可能 需要赋值的 LHS 地址,但只允许目标对象的名称更方便。

(为了解释上面的简化,当前标准对 lvalue 的定义是 "an expression (with an object type other than void) that potentially designates an object"。词 "potentially" 在那里是因为,例如,*ptr 其中 ptr 是一个指针,即使 ptr 的当前值为 NULL 也是左值。作为左值是一个编译时概念。试图将一个值赋给*ptr 是合法的,但有未定义的行为。)