I have yet again seen a piece of code similar to the following very common mistake
1 2 3 4 5 6
|
if (chr == 'Y' || 'y') // this will always return true
do_something; // and this will always be called
else if (chr == 'N' || 'n') // this makes same mistake as above
do_something_else; // but, this will never be called because of above
else
do_some_other_thing; // This will never be called
| |
Before I get into why that first if will always return true, let's look at a few details about how conditionals work.
What is a conditional?
A conditional is a statement that evaluates to
true or
false. All of your control structures rely on conditionals. This includes..
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
if ( conditional )
else if ( conditional )
while ( conditional )
do { ... }
while ( conditional )
// even
for ( initialization; conditional; incremental)
// for loops can have an empty conditional which evaluates to true. But this only works for For loops.
// and there is the conditional operator
int a = conditional ? ... : ...;
| |
And since conditionals evaluate to
true or
false then the above can also be writen as such..
1 2 3 4 5 6 7 8 9 10 11
|
if (true)
else if (true)
while (true)
do { ... }
while (true)
for ( ...; true; ...)
int a = true ? ... : ...;
| |
Naturally,
if (true) would defeat the purpose of the
if statement, but
while (true) is very commonly used.
So how do we define True or False?
A lot of people would tell you that
false is
zero, and
true is any number larger than
zero. This is not entirely accurate. To be more percise,
false is
zero and
true is any
non-zero. This includes negative numbers. (
I have tested to confirm this with DevC++)
False can also be
null which is distinctly different from
zero. There are many functions that return
null, so this can also be used as a conditional.
So what qualifies as a conditional?
Anything that evaluates to
true or
false. All of your comparisons, such as
greater than '>',
less than or equal to '<=', and
is equal to '==' evaluate to
true or
false.
1 2 3 4 5 6 7 8 9 10 11 12
|
int i = 5; // integer i is equal to five.
if (i == 5) // this evaluates to
if (true)
else if (i < 5) // this evaluates to
else if (false)
while (i >= 5) // this evaluates to
while (true)
// and so forth
| |
All of your assignments also evaluate to
true or
false. This is because assignments also return a value.
a = 5; stores the number
5 into the variable
a. But it also returns the value
5. This is why
b = a = 5; works. It first stores
5 into
a, then returns
5 which is stored into
b.
The
b = 5; also returns
5, but since we don't store it into anything else, it gets lost into time and space, never to be seen again. This is ok, since someday someone will invent a hyperspace engine that gets its power from all of these lost values floating around.
1 2 3 4 5 6 7 8
|
// notice one '=' sign makes it an assignment, not a comparison
if (a = 5) // this evaluates into
if (5) // which since 5 is a non-zero, it evaluates into
if (true)
if (a = 0) // this evaluates to
if (0) // which as we know from above evaluates to
if (false)
| |
Then finally, there are many functions that you can call that return values. Any function that does not return a
void (or by definition of
void does not return anything) can be used as or in conditionals.
Logical Operators
There are two logical operators that can be used to concatenate conditionals. These are the
And '&&', and the
Or '||' operators. both of these take two conditionals, one on either side, and evaluate each conditional seperately.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
if ( condition_1 || condition_2 ) // or
if ( condition_1 && condition_2 ) // and
int i = 5, j = 1;
if ( i == 3 || j == 1 ) // evaluates to
if ( false || true ) // evaluates to
if ( true )
if ( i == 5 && j == 3 ) // evaluates to
if ( true && false ) // evaluates to
if ( false )
// You can even use multiple concatenations.
int h = 3;
if ( i == 2 || ( j == 1 && h == 3 ) ) // evaluates to
if ( false || ( true && true ) ) // evaluates to
if ( false || true ) // evaluates to
if ( true )
| |
And this brings us back to the code at the beginning, and why it will always return true. That code reads...
1 2 3 4
|
if (chr == 'Y' || 'y') // which if chr = anything other than 'Y' would evaluate to
if ( false || 'y' ) // and since 'y' is a non-zero this would evaluate to
if ( false || true ) // which will evaluate to
if ( true )
| |
Special Note
You can also use assignments and function calls with the logical operators. However, special care should be given here, as doing so may have unexpected results. This is due to the way the program handles these logical operators.
For example,
Or returns true if either conditional is true. It checks the first conditional, and if it returns false, it will check the second conditional. If, however, the first conditional returns true, it does not need to check the second conditional. It already has enough information to return true. Let's take the following code for example..
1 2 3 4 5 6 7 8 9 10 11 12
|
int i = 0, j = 0;
while (true)
{
if (++i >= 5 || ++j >= 5) // OR
cout << i << " " << j << " true" << endl;
else
cout << i << " " << j << " false" << endl;
if (i >= 10)
break;
}
| |
One would think from looking at this code that both
i and
j would reach 10. However, once
i reaches 5, it returns true and thus the second conditional no longer needs to be tested. The result is the following output.
1 1 false
2 2 false
3 3 false
4 4 false
5 4 true
6 4 true
7 4 true
8 4 true
9 4 true
10 4 true |
And, however, requires both conditionals to be true. So it checks the first conditional, and if it returns true, it will check the second conditional. If, however, the first conditional returns false, there is no reason to check the second conditional. It already has enough information to return false. Thus the following code..
1 2 3 4 5 6 7 8 9 10 11 12
|
int i = 0, j = 0;
while (true)
{
if (++i >= 5 && ++j >= 5) // AND
cout << i << " " << j << " true" << endl;
else
cout << i << " " << j << " false" << endl;
if (i >= 10)
break;
}
| |
.. produces the following output..
1 0 false
2 0 false
3 0 false
4 0 false
5 1 false
6 2 false
7 3 false
8 4 false
9 5 true
10 6 true |
The Not Operator
And there is of course, one more logical operator to consider. the
Not '!' operator which when put in front of the conditional, simply reverses it. It turns
true into
false and
false into
true.
1 2 3 4 5 6 7
|
if (!true) // evaluates to
if (false)
// and
if (!false) // evaluates to
if (true)
| |
Side Note: XOR
I originally had
Xor as a logical operator, but it is not. It is a bitwise operator. It is possible, however, to emulate the
Xor functionality in a logical sence.
Xor is simply '
Or And Not And'. However, using assignments in part or all of this is much more difficult to predict the possible outcomes.
1 2 3 4 5 6 7 8 9 10 11 12
|
int i = 0, j = 0;
while (true)
{
if ((++i >= 5 || ++j >= 5) && !(++i >= 5 && ++j >= 5))
cout << i << " " << j << " true" << endl;
else
cout << i << " " << j << " false" << endl;
if (i >= 10)
break;
}
| |
..produces this output..
1 1 false
2 2 false
3 3 false
4 4 false
6 5 false
8 6 false
10 7 false |