In this section you will find very few complete programs. Rather, I've used short code fragments to highlight a certain type of expression, or operator. It could be rather difficult to understand the use of the given expressions unless you write your own programs and see what happens. In the previous chapter, you learnt how to write loops with simple expressions. As you progress through this chapter, write programs using the new operators you learn. I encourage you to take your own time going through this chapter, because expressions are the of bread and butter almost any kind of programming.
An expression can be any combination of operators and operands. Operators perform operations like addition, subtraction, comparision etc. Operands are the variables or values on which the opertions are performed. For example, in a + b, a and b are operands and + is the operator. The whole thing together is an expression.
You can usually use an expression wherever you can use a variable. However, note that simply saying a + b does NOT change any value. For example:
printf ("%d\n", a + b);
In this example, both a and b retain the values they had before the printf statement was executed. But the sum of the two values is printed on the screen.
But what type is a + b? That depends on what type a and b are. If they're both ints, then their sum is an int. If they're floats their sum is also float. We'll discuss what happens when they're both of different types, later.
Unary operations are operators which require only one operand. For example, when you use - to negate a value, for example -a, - is a unary operator. It is only concerned with the value of a. On the other hand, something like, say, + (in the previous example) is a binary operators, because it uses two values or variables.
Now, consider this expression.
c = a + b;
You've already dealt with expressions like this in the last chapter. You know that is adds the two values together and assigns it to c. But can you use the assignment operator like the following?
printf ("%d", c = a + b);
Yes you can. It still has the same effect of assigning the sum of a and b to c. The whole expression is assigned this value. So printf prints the sum of a and b. The statement above is exactly equivalent to the following:
c = a + b;
printf ("%d", c);
In the chapter on Loops, you learnt about the comparision operator ==. Don't confuse this with the assignment operator =. Moreover, it is legal syntax in C. For example,
while (a == b)
will execute the loop while a is equal to b. Both a and b retain their original values. However,
while (a = b)
will make a equal to b and execute the loop while a is non-zero. Because of this potential for mistaken use of = instead of == many compilers will produce a warning if you use an assignment operator where a boolean expresion is expected. However, because it is legal, it won't produce an error, and the program will compile.
At first sight this might look like an annoying glitch in C syntax. However, it is rather convenient, and is frequently used, particularly in areas like Input/Output. We'll deal with these topics in a later chapter.
You used expressions like a == b to compare two values, in the last chapter. But what is the value of this expression? Logically it is be false or true. In computer terms it is zero for false, or non-zero for true. So if you did something like:
printf ("%d", a == b);
It will print 0 if a and b are not equal, or some non-zero number if they are equal. This non-zero value usually turns out to be 1, but you should not assume that 'true' will be 1 everywhere. Just call it non-zero. However, when you say, perform a boolean operation like, a == b it will probably be equal to 1 is a and b are equal.
On the other hand, any expression can be used where a boolean expression is expected. It will be considered true if it is non-zero, and false if it is zero. For example,
while (a + b)
{
printf ("%d, %d\n", a, b);
a++;
}
This loop will execute till the sum of a and b becomes zero. For example, if b is -5, the loop will execute till a becomed +5.
If you use something like:
while (1)
It will become an infinite loop, because 1 obviously is always non-zero.
In the last chapter you also used other comparision operators line <=, <, =>, > etc. The meaning of these operators should be fairly obvious.
The % operator is called the modulo operator. It returns the remainder after an integer divide. For example, 5 % 2 is 1. The modulo operator can't be used for floating point numbers.
Often it is not enough to check for one condition. For example, say, you want a loop to eexecute while a is less than 5 and b is greater than 10. How will you write the while statement? You use the logical and operator &&.
As you will see later in this chapter apart from the logical and, there also is a bitwise and. In fact there are bitwise versions of all logical operations. So it is important to explicitly mention which is meant, except when it is completely obvious from the context.
For example,
while (a < 5 && b > 10)
Reading out the statement completely explains its meaning: While a is less than 5 and b is less than 10. Sometimes, when you want to check more than one condition on a single variable, it might be tempting to do something like:
while (a > 0 && < 5)
When you mean: While a is greater than 0 and less than 5. However this expression is WRONG. It should be written as:
while (a > 0 && a < 5)
^ can't skip out this a
There are other logical operators:
Operator | Meaning |
---|---|
&& | Logical AND |
|| | Logical OR |
! | Logical NOT |
You can use the logical OR operator just like the logical AND operator. But what about the logical NOT operator? What happens when you use:
while (! a < 5)
Is it the same as
while (a >= 5)
Well, it is not. The second statement obviously eexecutes the loop while a is greater than or equal to 5. The first statement however is an infinite loop. What it does is to first negate a and then compare it with 5. Since !a will be zero or one depending on whether a is true or false (non-zero or zero), it will always be less than 5. There are comprehensive rules (called precedence) about which you'll learn in this chapter. For now, we'll use examples where the meaning of the expression is completely obvious, or I'll clearly explain what happens.
You know that numbers are encoded in binary as zeros and ones. So far you weren't particularly concerned about how the numbers are encoded. For example, when you multiply or divide or compare numbers, you can simply use their decimal value and be done with it. However, there are times when you need to manupulate binary numbers. That is when these bitwise operators are useful. If you're not familiar with how binary numbers are represented, you should go to the Binary/Hexadecimal Tutorial in the Beginners' Section.
You might be wondering why anyone would want to bother with binary numbers when you can simply use decimal. Well, in most ordinary programs you don't need to. But there are other times when you do. for example, when you access BIOS or DOS functions you often need to encode lots of information in various groups of bits of a byte. Or when you write directly to the video memory for fast graphics output, the color info for the pixels needs to be encoded into a single byte or word.
You learnt about the logical operators in the previous section. The bitwise operators do the same for each bit.
Operator | Meaning |
---|---|
& | Bitwise AND |
| | Bitwise OR |
~ | Bitwise NOT |
^ | Bitwise XOR |
<< | Shift Left |
>> | Shift Right |
AND, OR and NOT should be easy to underastand:
10 & 12 (in binary, 1010 & 1100) gives 8 (1000)
10 | 12 (1010 | 1100) gives 15 (1111)
~10 (1010) gives 5 (0101)
Note that, !10 is not the same as ~10. !10 gives 0.
For the shift operators, the second operand gives the number of bits to shift by. The left shift operator introduces zeros to the right, and the right shift operator introduces zeros to the left. Bits that 'fall off the edge' are lost. They don't return to the other side.
10 >> 1 (1010 >> 1) gives 5 (0101).
10 >> 2 (1010 >> 2) gives 2 (0010).
10 << 1 (1010 << 1) gives 4 (0100).
10 << 2 (1010 << 2) gives 8 (1000).
Now, XOR stands for eXclusive OR. Basically XOR means: OR but NOT AND. In other words, when you XOR two bits, the result is 1 if either one, but not both of the bits are 1.
10 ^ 12 (1010 ^ 1100) gives 5 (0110)
Very often you'll need to perform some operation on a variable, and assign the result to the same variable. For example,
a = a + b;
This adds the current value of a to b and then assigns the sum to a itself. For example, if a is 10 before the statement is executed, and b is 5, the new value of a is 15. Now, C offers a shorthand notation for expressions like this. The above statement is exactly same as this one:
a += b;
Other examples are:
a -= 10;
a *= b + c;
a |= 10;
a >>= 4;
a %= c;
In each case, the expression on the right hand side of the = is evaluated, then the relevant operation is preformed on the variable on the left side of the = and assigned to the same variable. Since an assignment is to be performed, you obviously can't have a constant or something like a + b on the left hand side.
Conditional statements have the form:
expr1 ? expr2 : expr3
First expr1 is evaluated. If It is true (non-zero) expr2 is evaluated, otherwise expr3 is evaluated. For example
a = b == c ? 5 : 10;
Here, if b == c, then a equals 5, otherwise, a equals 10. Although they're usually not necessary, it might make the conditional expression easier to understand if you include brackets:
a = (b == c) ? 5 : 10;
A comma, is used to separate two or more expressions. The value of the whole expression is taken to be that of the rightmost expression. For example,
a = b++, c--, 5;
Here, both b and c are incremented (i.e. b++ and c++ are both evaluated), but a is assigned the value 5.
Often you'll use more than one operand in an expression. The operations are not performed in a strict left to right order. For example, in
a + b * c
The multiplication is performed first followed be the addition. The multiplication operation is said to have a higher precedence. All operators in C are arranged in various precedence levels. The following table lists precedence levels for all operators you've encountered so far:
Operator | Comments |
---|---|
! ~ + - ++ -- | Unary operators |
* / % | Multiplication/Division |
+ - | Addition/Subtraction |
<< >> | Shift Operators |
< <= > >= | Comparision |
== != | Equal to/Not Equal to |
& | Bitwise AND |
| | Bitwise OR |
&& | Logical AND |
|| | Logical OR |
?: | Conditional |
= += -= *= /= %=
&= ^= |= <<= >>= |
Assignment Operators |
, | Comma |
All operators in the same row have the same precedence. Operators at the top of the table have the highest precedence. In an expression, operators with higher precedence are evaluated first, followed be the ones with next hoghest precedence etc. You can force evaluation in a particular order by using paranthesis (), just like the brackets in mathematics. For example,
a + b * c
Multiplies b and c and adds a, but if you use paranthesis around a + b the addition will be performed first.
(a + b) * c
In mathematics you could have omitted the multiplication sign. A value written outside a brached with no sign implies multiplication. But in C, the multiplication symbol * must be given explicitly.
In the following examples, I've used paranthesis to explain just how the expressions are evaluated, to help you understand precedence.
Expression | Meaning | Comments |
---|---|---|
b << 4 + a | b << (4 + a) | |
-a + b | (-a) + b | |
a & b + c | a & (b + c) | |
a && b & 2 | a && (b & 2) | True is both a and b & 2 are non-zero |
a = b == c | a = (b == c) | a equals 1 if b equals c, zero otherwise |
a << 10 >> 3 | Ambiguous * | Not illegal, but could produce a warning |
* Depending on whether the compiler evaluated the expression from left to right or right to left the result will vary. Most compilers will produce a warning message, but not an error.
Operators with same precedence are usually evaluated from left to right, but this may differ on different compilers. You should not use expressions that rely on order of evaluation of operators with equal precedence. The last example in the above table shows why.
In the chapter on loops you learnt about a few basic types of opeators. In this chapter we've expanded on that knowledge. You've learnt:
In this chapter you've learnt about lots of new operators, and gained more insight into C Expressions. Its almost time to move on the the next chapter. But before you do, let me repeat the piece of advice I give at the end of each chapter... don't move on to the next chapter unless you're sure you understand everything in this chapter. You've learnt about loops in the last chapter. Combine that knowledge with that gained in this one and write all kinds of programs you can think of.
Write expressions with loops and printf statements and make sure you get expected results. If you don't, review the chapter and see where you went wrong. And of course, if you still don't get it, you can mail me at: vinaypai@crosswinds.net .
If you're ready, click the link below to go to the next chapter.
C Tutorial Quicklist | Start Page
| Contents |
| Ch 1:Introduction
| Ch 2:Variables
| Ch 3:Loops
| Ch 4:Expresisons
| Ch 5:Control Flow |
| Ch 6:Basic I/O
| Ch 7:Arrays |
| Home Page
| Beginners
| Advanced
| Links
| Downloads
| Books |
| C Tutorial
| HYPERSearch
| Guestbook
| Feedback |