The scanf
function has to access the object into which a value is being read. All C function arguments are passed by value, so if you wrote
int a, b;
scanf("%d%d", a, b); // THIS IS WRONG
the scanf
function would only be able to see the values of a
and b
as they were when the function was called. It would have no way to modify a
.
Assignment requires an lvalue as its left operand. An lvalue (to simplify slightly) is an expression that designates an object; the name of a variable is the most common kind of lvalue. Since the assignment operator =
is built into the language, it can have special rules that apply to it. In particular, the lvalue on the LHS of the =
identifies the object being assigned to; it doesn't yield the (previous) value of that object. That's how assignment is defined by the language.
For example, if you write:
a = b;
both a
and b
are lvalues, but they're treated differently because of their context. a
refers to the object whose name is a
. b
also refers to an object, but in that context it yields the current value of that object.
If assignment were implemented as a function call, it would have to take the address of the object being assigned to:
int assign(int *lhs, int rhs);
assign(&a, b);
The language could have required an address for the LHS of an assignment, but allowing just the name of the target object is much more convenient.
(To explain the simplification above, the current standard's definition of lvalue is "an expression (with an object type other than void) that potentially designates an object". The word "potentially" is there because, for example, *ptr
where ptr
is a pointer is an lvalue even if the current value of ptr
is NULL
. Being an lvalue is a compile-time concept. Attempting to assign a value to *ptr
is legal, but has undefined behavior.)