|
Logical and Assignment Operators |
This page covers the following topics:
Booleans: True and False |
Before talking about operators, we'll take a quick aside into booleans, since we'll need to know what a boolean is before discussing operators. A boolean value is one that can be either true or false. No other values are allowed. Booleans and boolean operations are at the heart of programming. Many times in a program, you'll want to do one thing if a certain condition is true, and a different thing if the condition is false.
Most programming languages have a
type for booleans, usually called "boolean" or "bool". Some C++ compilers
recognize the type bool,
others do not.
In order to use boolean logic to your advantage, you need to learn about the three basic boolean operations. They are called and, or, and not. Each operation takes either one or two boolean inputs, and returns a boolean output. They are often represented by symbols known as "gates", shown below.
|
|
The "and" operation takes two inputs and produces one output. If both inputs are true, the output is true; in all other cases, the output is false. It can be interpreted as follows: "I will return true if input 1 and input 2 are true." |
|
|
The "or" operation takes two inputs and produces one output. If either of the inputs are true, the output is true; otherwise (i.e., if neither input is true), the output is false. It can be interpreted as follows: "I will return true if either input 1 or input 2 is true." |
|
|
The "not" operation takes one input and produces one output. If the input is true, the output is false. If the input is false, the output is true. In other words, the "not" operation takes the input and returns its opposite. |
Boolean operators in C++ |
There are operators in C++ which behave just as the boolean gates shown above! We'll show you an example of how to use each one.
The "and" operator is used by
placing the "and" symbol, &&,
in between two boolean values.
//suppose that Hussam is tired boolean HussamTired = true; //but Hussam doesn't have to wake up early boolean HussamMustWakeUpEarly = false; //will Hussam go to sleep now? boolean bedTime = HussamIsTired && HussamMustWakeUpEarly;
What does this chunk of code do? It
initializes two variables,
HussamIsTired
and HussamMustWakeUpEarly,
to true and
false,
respectively. Then, in the third line of code (not including comments!), we
determine that Hussam will go to sleep if and only if the "and" operation
is true -- that is, if both inputs to the "and" operation are true. In this
case, the first input is true and the second input is false. Since "and"
requires both inputs to be true in order for the output to be true, but one of
the inputs is false, the output will be false. So, the variable
bedTime will store the value
false.
Also, take note that the variable names used here are lengthy. How you decide to program is up to you, but often times it's better to have lengthier variable names that are readable, rather than short, obfuscated variable names like "i" or "zz". (The names in this example may have gone overboard, though.)
The "or" operator is used by
placing the "or" symbol, ||,
in between two boolean values.
//suppose that Jaber is tired boolean jaberIsTired = true; //but Jaber doesn't have to wake up early boolean jaberMustWakeUpEarly = false; //will Jaber go to sleep now? boolean bedTime = jaberIsTired || jaberMustWakeUpEarly;
This example is very similar to the
example involving Hussam , except notice the key difference: whether or not
Jaber
goes to sleep is determined differently. Jaber will go to sleep if he is tired
or if he needs to wake up early. Whereas Hussam would go to sleep only if both
conditions were true, Jaber will go to sleep if either condition (or both) is
true. Therefore, the value of bedTime
is true.
The "not" operator is used by
placing the "not" symbol, !,
before a boolean value.
//suppose that Haytham stayed up late boolean haythamStayedUpLate = true; //will Haytham Awake up early boolean haythamWakeUpEarly = !haythamStayedUpLate;
This example illustrates the "not"
operator. At the end of this block of code, the variable
haythamWakeUpEarly
will take on
the opposite value of
haythamStayedUpLate
.
If haythamStayedUpLate
were false,
then
haythamWakeUpEarly
would be true.
In this case, the opposite is true, so
haythamWakeUpEarly
gets a value of
false.
It is perfectly legal in C++ to use boolean operators on variables which are not booleans. In C++, "0" is false and any non-zero value is true. Let's look at a contrived example.
int hours = 4; int minutes = 21; int seconds = 0; bool timeIsTrue = hours && minutes && seconds;
Since
hours evaluates to
true, and since
minutes evaluates to
true, and since
seconds
evaluates to false,
the entire expression
hours && minutes &&
seconds evaluates to
false.
Equality operators in C++ |
You are undoubtedly familiar with equality operators, even if you don't know it. An equality operator is one that tests a condition such as "is less than", "is greater than", and "is equal to". You will find it useful to be able to compare two numbers using expressions like "x is less than y".
Let's say you are writing software for a bank ATM (automated teller machine). A customer makes a request for a certain amount of cash, and your responsibility is to determine if they should be allowed to withdraw that amount. You could decide to use the following algorithm: "if the amount requested is less than the account balance, that amount should be withdrawn; otherwise, the customer should be notified and no money should be withdrawn." Makes sense, right? So, the next step is coming up with some pseudo-code. Once you have pseudo-code, writing the C++ code will be easy.
Pseudo-code for the ATM problem might look like this:
if the amount requested < account balance then
withdraw the amount requested
otherwise
withdraw nothing and notify the customer
Now that we have pseudo-code, writing the C++ code is as simple as "translating" your pseudo-code into C++. In this case, it's easy:
if (amountRequested < accountBalance) {
withdraw(amountRequested);
}
else {
withdraw(0);
notifyCustomer();
}
You'll notice some new syntax in
this example, but don't worry about it too much. Pay close attention to the very
first line, which checks to make sure that the amount requested is less than the
account balance. The way it works is, if the expression
between parentheses (())
evaluates to true,
then the first block
of code will be read. That is, the code inside the first set of curly braces ({})
will be executed. If the expression in parentheses evaluates to
false, on the other hand,
then the second block of code (the code following the word
else) will be read. In this
case, the first block of code withdraws the amount requested by the customer,
while the second block of code withdraws nothing, and notifies the customer.
That wasn't so hard! All we did was take the original English description of how we would solve the problem, write some pseudo-code for the English description, and translate the pseudo-code into C++.
Once you know how to use one
equality operator, you know how to use all of them. They all work the same way:
they take the expressions on either side of them, and either return
true or
false. Here they are:
|
Equality operators |
|||
|---|---|---|---|
|
name |
symbol |
sample usage |
|
|
is less than |
|
|
|
|
is greater than |
|
|
|
|
is equal to |
|
|
|
|
is less than or equal to |
|
|
|
|
is greater than or equal to |
|
|
|
|
is not equal to |
|
|
|
to test whether the variable i lies between 1 and 10, you might use
if(1 < i && i < 10) ...
Here we're expressing the relation ``i is between 1 and 10'' as ``1 is less than i and i is less than 10.''
It's important to understand why the more obvious expression
if(1 < i < 10) /* WRONG
*/
would not work. The expression 1 < i < 10 is parsed by the compiler analogously to 1 + i + 10. The expression 1 + i + 10 is parsed as (1 + i) + 10 and means ``add 1 to i, and then add the result to 10.'' Similarly, the expression 1 < i < 10 is parsed as (1 < i) < 10 and means ``see if 1 is less than i, and then see if the result is less than 10.'' But in this case, ``the result'' is 1 or 0, depending on whether i is greater than 1. Since both 0 and 1 are less than 10, the expression 1 < i < 10 would always be true in C, regardless of the value of i!
Relational and Boolean expressions are usually used in contexts such as an if statement, where something is to be done or not done depending on some condition. In these cases what's actually checked is whether the expression representing the condition has a zero or nonzero value. As long as the expression is a relational or Boolean expression, the interpretation is just what we want. For example, when we wrote
if(x > max)
the > operator produced a 1 if x was greater than max, and a 0 otherwise. The if statement interprets 0 as false and 1 (or any nonzero value) as true.
But what if the expression is not a relational or Boolean expression? As far as C is concerned, the controlling expression (of conditional statements like if) can in fact be any expression: it doesn't have to ``look like'' a Boolean expression; it doesn't have to contain relational or logical operators. All C looks at (when it's evaluating an if statement, or anywhere else where it needs a true/false value) is whether the expression evaluates to 0 or nonzero. For example, if you have a variable x, and you want to do something if x is nonzero, it's possible to write
if(x)
statement
and the statement will be executed if x is nonzero (since nonzero means ``true'').
This possibility (that the controlling expression of an if statement doesn't have to ``look like'' a Boolean expression) is both useful and potentially confusing. It's useful when you have a variable or a function that is ``conceptually Boolean,'' that is, one that you consider to hold a true or false (actually nonzero or zero) value. For example, if you have a variable verbose which contains a nonzero value when your program should run in verbose mode and zero when it should be quiet, you can write things like
if(verbose)
printf("Starting first pass\n");
and this code is both legal and readable, besides which it does what you want. The standard library contains a function isupper() which tests whether a character is an upper-case letter, so if c is a character, you might write
if(isupper(c))
...
Both of these examples (verbose and isupper()) are useful and readable.
However, you will eventually come across code like
if(n)
average = sum / n;
where n is just a number. Here, the programmer wants to compute the average only if n is nonzero (otherwise, of course, the code would divide by 0), and the code works, because, in the context of the if statement, the trivial expression n is (as always) interpreted as ``true'' if it is nonzero, and ``false'' if it is zero.
``Coding shortcuts'' like these can seem cryptic, but they're also quite common, so you'll need to be able to recognize them even if you don't choose to write them in your own code. Whenever you see code like
if(x)
or
if(f())
where x or f() do not have obvious ``Boolean'' names, you can read them as ``if x is nonzero'' or ``if f() returns nonzero.''
Assignment operators in C++ |
Believe it or not, you've already
been using assignment operators! Probably the most common assignment operator is
the equals sign (=).
It is called "assignment" because you are "assigning" a variable to a value.
This operator takes the expression on its right-hand-side and places it into the
variable on its left-hand-side. So, when you write
x = 5, the operator takes
the expression on the right, 5,
and stores it in the variable on the left, x.
Remember how the equality
operators, like <
and !=,
returned a value that indicated the result? In that case, the return value was
either true or
false. In fact,
almost every expression in C++ returns something! You don't always have to use
the return value, though -- it's completely up to you. In the case of the
assignment operators, the return value is simply the value that it stored in the
variable on the left-hand-side.
Sometimes your code will use the return value to do something useful. In the ATM example, one line of code was executed if the condition was true (that is, if the equality operator returned true). Two different lines were executed if the condition was false.
Other times, you'll completely ignore the return value, because you're not interested in it. Take a look at the following code:
int x; int y; x = 5; y = 9; cout << "The value of x is " << x << endl; cout << "The value of y is " << y << endl; int sum; sum = x + y; cout << "The sum of x and y is " << sum << endl;
This chunk of code shows why you
might want to throw away the return value of an operator. Look at the third
line, x = 5.
We're using the assignment operator here to place the value
5 in the variable
x. Since the
expression x = 5
returns a value, and we're not using it, then you could say we are
ignoring the return value. However, note that a few of lines down, we are very
interested in the return value of an operator. The addition operator in the
expression x + y
returns the sum of its left-hand-side and right-hand-side. That's how we
are able to assign a value to sum.
You can think of it as sum = (x + y),
since that's what it's really doing.
The other assignment operators
are all based on the equals sign, so make sure you understand that before going
on. Here's another assignment operator: +=.
How does it work? You might guess that it has something to do with addition, and
something to do with assignment. You'd be absolutely right! The
+= operator takes the
variable on its left-hand-side and adds the expression on its right-hand-side.
Whenever you see a statement that looks like the following:
myVar += something;
it is identical to saying the following:
myVar = myVar + something;
That's exactly what it's doing! It's simply a shortcut.
The other common assignment
operators are -=,
*=,
/=, and
%=. They all function just
like the +=
operator, except instead of adding the value on the right-hand-side, they
subtract, or multiply, or divide, or "mod" it.
d -= 4
(d = d - 4)
e *= 5
(e = e * 5)
f /= 3
(f = f / 3)
g %= 9
(g = g % 9)
=
returns the value that it stored, all of the assignment operators return the
value stored in the variable on the left-hand-side. Here's an example of how you
might take advantage of this return value. It's not used terribly often, but it
can sometimes be useful.//these four variables represent the sides of a rectangle int left; int top; int right; int bottom; //make it a square whose sides are 4 left = top = right = bottom = 4;
All this code does is store the
value in each of the four variables left, top,
right, and
bottom. How does it work? It starts on the far
right-hand side. It sees bottom = 4.
So it places the value 4
in the variable bottom,
and returns the value it stored in bottom
(which is 4).
Since bottom = 4 evaluates to
4,
the variable right
will also get the value 4,
which means top
will also get 4,
which means left
will also get 4.
Phew! Of course, this code could have just as easily been written
//these four variables represent the sides of a rectangle int left; int top; int right; int bottom; //make it a square whose sides are 4 left = 4; top = 4; right = 4; bottom = 4;
and it would have done the exact same thing. The first way is more compact, and you're more likely to see it written the first way. But both ways are equally correct, so use whichever you prefer.
Confusing Equality (==) and Assignment (=) Operators |
if ( payCode == 4 )
printf( "You get a bonus!\n" );
if ( payCode = 4 )
printf( "You get a bonus!\n" );
Expressions that can appear on the left side of an equation ,their values can be changed, such as variable names:
x = 4;
Expressions that can only appear on the right side of an equation.
Constants, such as numbers .
Cannot write 4 = x; ( ERROR : Lvalue required ).
Must write x = 4;
lvalues can be used as rvalues, but not vice versa
y = x;