Assignment Operators in C

One of the fundamental operations in a programming language is assignment. Through this operation, it is possible to copy the value of an expression into a variable.

In the C language, there is the simple assignment operator = that allows assigning the value of an expression to a variable.

Moreover, to simplify code writing, C also provides compound assignment operators such as +=, -=, *=, /=, and %= which assign the result of a composed expression to a variable.

In this lesson, we will explore what the assignment operators in C are and how they work.

Simple Assignment

The simple assignment operator is the most basic assignment operator in the C language. This operator assigns the value of an expression to a variable.

int a = 5;

In general, the simple assignment operator has the following syntax:

v = e;

When the control flow reaches the simple assignment operator, the expression e is evaluated. Then the result is copied into v.

The expression e can be a literal constant, a variable, or a more complex expression.

For example:

x = 4;                  // the value 4 is copied into x
y = x;                  // the value of x is copied into y
z = 3 * x + 2 * y;      // the value 20 is copied into z

In general, the C language requires that e and v be of the same type. If they are not, the compiler will try to convert the value of e into the type of v, if possible. For example:

double x = 3.14;
int y;

y = x;                  // y now has the value 3
x = 4;                  // x now has the value 4.0

In this example, the compiler converted the value of x from double to int when copying it into y. Therefore, the value 3.14 was truncated to 3. Then, the compiler converted the value 4 from int to double when copying it into x. These conversions are done automatically by the compiler since these are numeric values. In future lessons, we will see how to explicitly convert values from one type to another.

Assignment as an Expression

In many programming languages, assignment is a statement. In C, assignment is an expression and therefore returns a value. So, when we use the assignment operator, the expression e is evaluated and its result is copied into v. Then, the result of the expression e is returned as the value of the assignment operator.

Since the assignment operator is an expression, we can use it in any context where an expression is allowed. For example:

int x;
printf("%d\n", x = 5);  // prints 5

In this example, the expression x = 5 is evaluated and returns the value 5. Then, the value 5 is passed to the printf function, which prints it to the screen.

We can take advantage of this feature by chaining multiple assignments, for example:

int x, y, z;

x = y = z = 0;          // all values are initialized to 0

Given that the assignment operator is right-associative, we can rewrite this expression as:

int x, y, z;

x = (y = (z = 0));      // all values are initialized to 0

In other words, the value 0 is first assigned to variable z, then the result (which is 0) is assigned to variable y, and finally the result (still 0) is assigned to variable x.

Note

Beware of Chained Assignments

When using chained assignments, be careful of unintended side effects.

For example:

double x;
int y;

x = y = 3.14;

In this example, the value 3.14 is first converted to an integer, becoming 3. It is then assigned to the integer variable y. Afterwards, the value 3 is converted to double and assigned to the double variable x.

So the final result is that x has the value 3.0, not 3.14 as one might expect.

Since assignment is an expression, it can be used anywhere another expression of the same type is expected.

For example:

int x, y, z;

x = 5;
z = 2 + 3 * (y = x);

However, it is good practice to avoid mixing expressions and assignments in a single expression. This is because such programs become harder to read and understand.

Introduction to Side Effects

In general, an operator performs an operation between operands and returns a result. In mathematics, for example, the addition + and subtraction operators combine two operands and produce a result.

In programming languages, including C, operators can, in addition to performing their associated operations, modify the operands themselves. When this happens, we say that the operator has side effects, since the operation affects more than just the result.

We’ve seen that the simple assignment operator, besides returning a result, also modifies the value of the destination variable. Therefore, the simple assignment operator has side effects.

int x, y;

y = 3 * (x = 5);

In this case, the assignment operator returns the value 5 and modifies the operand x.

Definition

Side Effect of an Operator

A side effect is the modification an operator makes to one or more operands in addition to returning a result.

In reality, the concept of side effect is broader than described above. Side effects are not limited to modifying operands but can also involve modifying the state of the program. We will delve into this concept when we study functions and variable scope.

L-value and R-value

In most cases, in the C language, operators act on operands that may be constants, literals, variables, or other expressions.

The assignment operator, however, requires that one of the operands be something that a value can be assigned to. This kind of entity is technically called an l-value.

The name l-value comes from the fact that these are entities that can appear on the left-hand side of the assignment operator; the name stands for left-value.

Definition

L-value

An l-value is an entity associated with a memory location from which data can be read and into which data can be written.

So far, we’ve only encountered one type of l-value: variables. Therefore, the left operand of the assignment operator must be a variable.

int x;

x = 5;

It is not possible to assign a value to an expression:

/* ERROR */
5 * x = 7;

Expressions or constants are not associated with any memory location, so no value can be stored in them. For this reason, they are called r-values, since they can appear on the right-hand side of the assignment operator. The name stands for right-value.

Definition

R-value

An r-value is an entity associated with a result, a value, but not necessarily a memory location.

An l-value is also an r-value, but the opposite is not always true.

Based on this definition, a constant or an expression are both r-values but not l-values.

Conversely, a variable can be both an l-value and an r-value. In fact, a variable can be used as an l-value to assign a value to it, but also as an r-value to retrieve the value it holds.

int x;

x = 5;      // x is an l-value
x = x + 1;  // x is an r-value

Compound Assignment

When writing programs—particularly in C—it’s common to need to modify the value of a variable by calculating a new value based on its current one.

For example, there is often a need to increment an integer variable by a given value:

int x;

x = 5;

x = x + 1;      // Increments the variable by 1
x = x + 2;      // Increments the variable by 2

Since these types of operations occur frequently in practice, the C language provides special operators that simplify them.

For instance, there is a compound addition and assignment operator with the following syntax:

x += e;

The compound addition and assignment operator += performs the addition of operand x and expression e, and assigns the new result to variable x.

These types of operators that combine an operation with assignment are called compound assignment operators. Below is the complete list:

Operator Meaning
v += e Adds v and e and stores the result in v
v -= e Subtracts e from v and stores the result in v
v *= e Multiplies v and e and stores the result in v
v /= e Divides v by e and stores the result in v
v %= e Calculates the remainder of v divided by e and stores the result in v
Table 1: Compound Assignment Operators in C

When using compound assignment operators, be careful with their precedence. In fact, the compound assignment operator has lower precedence than other arithmetic operators.

For example:

x *= y + 3;

Does not mean:

(x = x * y) + 3;

But instead means:

x = x * (y + 3);

Also, compound assignment operators are right-associative, so the following expression:

x *= y *= z;

Is equivalent to:

x *= (y *= z);

Which is the same as the sequence:

y = y * z;
x = x * y;
Note

Be Careful Not to Reverse the Symbols in Compound Assignment Operators

When using compound assignment operators, it’s easy to get confused and reverse the operator symbols. For example, it’s easy to write:

x =+ 3;

This is a completely legal expression and the compiler won’t throw an error. However, the result is that x will be assigned the value +3, i.e., 3.

In Summary

In this lesson we learned some very important concepts:

  • The assignment operator = assigns the value of an expression to a variable;
  • Assignment is an expression whose result is the assigned value;
  • Compound assignment operators perform an operation and assign the result to the variable;

These concepts are fundamental to learning the C language, and we will use them throughout all the upcoming lessons.