Aside from computing simple things like an average, programs aren’t very useful if they just follow a fixed set of steps. By using conditionals the operations performed by a program can be determined at runtime instead of when the program is compiled. For example, here we receive a signed long from the user and print a different statement depending on its value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

int main()
{
    signed long userInput = 0;

    std::cin >> userInput;

    if(userInput > 0)
    {
        std::cout << "That's positive!\n";
    }
    else if(userInput < 0)
    {
        std::cout << "That's negative!\n";
    }
    else
    {
        std::cout << "That's zero!\n";
    }

    return 0;
}

The if statement in the example first evaluates the expression within (), and then runs the code between {} if and only if that expression evaluated (i.e was equal) to true. If it didn’t, it checks the expression in the else if—of which there can be any number, including none at all—before finally resorting to the optional else code if that wasn’t true either. Note that only the first true if/else if/else statement will run, even if one after it is also true.

The expressions inside the () must be any expression that evaluates to a bool (true/false) value, which includes any mathematical comparison using <, >, <=, >=, ==, and != for less than, greater than, less than or equal to, greater than or equal to, equal to, and not equal to, respectively. Make sure you don’t use = instead of ==, the first is an assignment and not a comparison!

If the body of your conditional (the part between {}) is only a single statement (there’s only one ;) then you can omit the {} entirely. Hence the example is equivalent to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

int main()
{
    signed long userInput = 0;

    std::cin >> userInput;

    if(userInput > 0)       std::cout << "That's positive!\n";
    else if(userInput < 0)  std::cout << "That's negative!\n";
    else                    std::cout << "That's zero!\n";

    return 0;
}

The condition and body don’t have to be on the same line.

Logical Operators

Just like how numbers can be combined using arithmetic operators such as + and -, comparisons can be combined using the logical and and or operators && and ||. (These do not have compound assignment operators.)

int foo = 10;
int bar = 7;

// a will be true because both foo > 5 and bar < 10 are true
bool a = (foo > 5 && bar < 10);

// b will be true because whilst foo != 10 is false, bar <= 7 is true
bool b = (foo != 10 || bar <= 7);

When combining muliple logical operators together it’s important to insert () in the correct places as the order of evaluation may not be what you expect. For example, is 10 < 11 && 3 > 5 || 6 > 10 true or false? Try it out!

There’s also a unary negation operator ! which turns true to false and false to true. This is evaluated before other logical operators so make sure to insert parentheses around the expression you’re negating.

int foo = 7;
// This is true regardless of the value of foo because
// !(x == y) is the same as (x != y)
bool a = (!(foo == 10) == (foo != 10));

The bool Type

To be consistent with C, where the bool type doesn’t exist as a built in type (although it’s available in stdbool.h from C99, if you were curious), 0 is treated as false and any other value is treated as true. (In the opposite direction true is treated as 1 and false as 0.) This is achieved via type conversion and promotion respectively.

int foo = 9;

// This is equivalent to foo != 10
if(foo-10) std::cout << "Foo is not equal to 10\n";

Try not to abuse this as it complicates code, but it’s useful in general for checking for non-zero values which often occur when something hasn’t occured correctly. (Remember that we return a value of 0 at the end of the program to tell the operating system that everything went OK?)

Switch Statement

The switch statement is a useful replacement for a long if-else construct when you are checking for different outcomes of a single expression. Consider for example this simple conditional

int foo = 0;
std::cin >> userInput;

if(userInput == 0)
{
    std::cout << "0\n";
}
else if(userInput == 1 || userInput == 2)
{
    std::cout << "1 or 2\n"
}
else if(userInput == 4)
{
    std::cout << "4\n";
}
else
{
    std::cout << "Something else\n";
}

This can be equivalently written using a switch statement as

int foo = 0;
std::cin >> userInput;

switch(foo)
{
case 0:
    std::cout << "0\n";
    break;
case 1:
case 2:
    std::cout << "1 or 2\n";
    break;
case 4:
    std::cout << "4\n";
    break;
default:
    std::cout << "Something else\n";
    break;
}

Inside the () is the expression whose value we want to check; it needn’t be a variable—any expression such as (foo+10) / 2 will do—although it must evaluate to an int or something easily convertable to one (which includes all the types we’ve covered so far).

Each case x: is then a check for the given value (x must be an int or char), and the code after the relevant case is run by the program. Unlike an if statement there are (usually) no {} and instead the code is run line by line until a break statement is found, in which case everything else is ignored and the program continues. We use this in the example to run the same piece of code if foo is either 1 or 2.

Finally there’s the default statement, which is run if none of the case values are met, a lot like the else part of a conditional. Unlike else however, default does not need to come last.

switch(foo)
{
default:
case 0:
    std::cout << "Hello ";
case 1:
case 3:
    std::cout << "World!";
    break;
case 2:
    std::cout << "Bye";
}

Here a value of 1 or 3 will print "World!", a value of 2 will print "Bye", and a value of 0 or anything else will print "Hello World!". Note that the last break statement is omitted as it isn’t necessary; there are no other case statements after it.

Exercise

Write a program that accepts a two integers less than 10 from standard input and then outputs whether the largest is prime or not. (A prime number has no factors other than itself and 1.)

In the next section we’ll see a much easier way to do this, but you can use if statements here because the input is so small.

Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>

int main()
{
    short p = 0, q = 0;

    std::cin >> p >> q;

    // Set p to be the greatest of the two
    if(q > p) p = q;

    // Only need to check that p is less than 10
    if(p < 10)
    {
        // Check for primality
        // Note that if conditions can span multiple lines
        if((p % 2 == 0 && p != 2) || (p % 3 == 0 && p != 3) ||
            (p % 5 == 0 && p != 5) || (p % 7 == 0 && p != 7))
        {
            std::cout << "Not prime\n";
        }
        else
        {
            std::cout << "Prime\n";
        }
    }
    else
    {
        std::cout << "Numbers must be less than 10\n";
    }    
    return 0;
}