Operators
Operators are like verbs. They cause things to happen to your variables.
Arithmetic Operators
C has the usual binary operators +, -, *, and / for addition, subtraction, multiplication, and division, respectively.
Remainder Operator
The remainder or modulus operator (%) calculates the remainder from an integer division. The result of the following expression is 1:
int a = 7; int b = 3; int c = a%b; // c is now 1
Both operands of the remainder operator must be integer types.
Increment and Decrement Operators
C provides operators for incrementing and decrementing variables:
a++; ++a;
Both lines add 1 to the value of a. However, there is a difference between the two expressions when they are used as a part of a larger expression. The prefix version, ++a, increments the value of a before any other evaluation takes place. It is the incremented value that is used in the rest of the expression. The postfix version, a++, increments the value of a after other evaluations take place. The original value is used in the rest of the expression. This is illustrated by the following example:
int a = 9; int b; b = a++; // postfix increment int c = 9; int d; d = ++c; // prefix increment
The postfix version of the operator increments the variable after its initial value has been used in the rest of the expression. After the code has executed in this example, the value of b is 9 and the value of a is 10. The prefix version of the operator increments the variable’s value before it is used in the rest of the expression. In the example, the value of both c and d is 10.
The decrement operators a-- and --a behave in a similar manner.
Code that depends on the difference between the prefix and postfix versions of the operator is likely to be confusing to anyone but its creator.
Precedence
Is the following expression equal to 18 or 22?
2 * 7 + 4
The answer seems ambiguous because it depends on whether you do the addition first or the multiplication first. C resolves the ambiguity by making a rule that it does multiplication and division before it does addition and subtraction; so the value of the expression is 18. The technical way of saying this is that multiplication and division have higher precedence than addition and subtraction.
If you need to do the addition first, you can specify that by using parentheses:
2 * (7 + 4)
The compiler will respect your request and arrange to do the addition before the multiplication.
Negation
The unary minus sign (-) changes an arithmetic value to its negative:
int a = 9; int b; b = -a; // b is now -9
Comparisons
C also provides operators for comparisons. The value of a comparison is a truth value. The following expressions evaluate to 1 if they are true and 0 if they are false:
a > b // true, if a is greater than b a < b // true, if a is less than b a >= b // true, if a is greater than or equal to b a <= b // true, if a is less than or equal to b a == b // true, if a is equal to b a != b // true, if a is not equal to b
Logical Operators
The logical operators for AND and OR have the following form:
expression1 && expression2 // Logical AND operator expression1 || expression2 // Logical OR operator
C uses short circuit evaluation. Expressions are evaluated from left to right, and evaluation stops as soon as the truth value for the entire expression can be deduced. If expression1 in an AND expression evaluates to false, the value of the entire expression is false and expression2 is not evaluated. Similarly, if expression1 in an OR expression evaluates to true, the entire expression is true and expression2 is not evaluated. Short circuit evaluation has interesting consequences if the second expression has any side effects. In the following example, if b is greater than or equal to a, the function CheckSomething()is not called (if statements are covered later in this chapter):
if ( b < a && CheckSomething() ) { ... }
Logical Negation
The unary exclamation point (!) is the logical negation operator. After the following line of code is executed, a has the value 0 if expression is true (non-zero), and the value 1 if expression is false (zero):
a = ! expression;
Assignment Operators
C provides the basic assignment operator:
a = b;
a is assigned the value of b. Of course, a must be something that is capable of being assigned to. Entities that you can assign to are called lvalues (because they can appear on the left side of the assignment operators). Here are some examples of lvalues:
/* set up */ float a; float b[100] float *c; struct dailyTemperatures today; struct dailyTemperatures *todayPtr; c = &a; todayPtr = &today; /* legal lvalues */ a = 76; b[0] = 76; *c = 76; today.high = 76; todayPtr->high = 76;
Some things are not lvalues. You can’t assign to an array name, the return value of a function, or any expression that does not refer to a memory location:
float a[100]; int x; a = 76; // WRONG x*x = 76; // WRONG GetTodaysHigh() = 76; // WRONG
Conversion and Casting
If the two sides of an assignment are of different variable types, the type of the right side is converted to the type of the left side. Conversions from shorter types to longer types don’t present a problem. Going the other way, from a longer type to a shorter type, or converting between a floating-point type and an integer type, requires care. Such a conversion can cause loss of significant figures, truncation, or complete nonsense. For example:
int a = 14; float b; b = a; // OK, b is now 14.0 // A float can hold approximately 7 significant figures float c = 12.5; int d; d = c; // Truncation, d is now 12 char e = 99; int f; f = e; // OK, f is now 99 int g = 333; char h; h = g; // Nonsense, h is now 77 // The largest number a signed char can hold is 127 int h = 123456789; float i = h; // loss of precision // A float cannot keep 9 significant figures
You can force the compiler to convert the value of a variable to a different type by using a cast. In the last line of the following example, the (float) casts force the compiler to convert a and b to float and do a floating-point division:
int a = 6; int b = 4; float c, d; c = a / b; // c is equal to 1.0 because integer division truncates d = (float)a / (float)b; // Floating-point division, d is equal to 1.5
You can cast pointers from pointer to one type to pointer to another. Casting pointers can be a risky operation with the potential to trash your memory, but it is the only way to dereference a pointer passed to you typed as void*. Successfully casting a pointer requires that you understand what type of entity the pointer is “really” pointing to.
Other Assignment Operators
C also has shorthand operators that combine arithmetic and assignment:
a += b; a -= b; a *= b; a /= b;
These are equivalent to the following, respectively:
a = a + b; a = a - b; a = a * b; a = a / b;