• Articles
  • Conditionals - The true or false story
Published by
Aug 11, 2008 (last update: Aug 14, 2008)

Conditionals - The true or false story

Score: 2.4/5 (11 votes)
*****
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