Conditionals

It is a very rare program that solves a problem with the exact same sequence of operations every time it is executed. What is more common is a program that does some operations if the data or user inputs look a certain way, and a different set of operations if the data look a different way.

The way we can do this in C++ is with "conditionals." The word "conditional" means that some operations will only occur if a certain "condition" is true.

For example, consider the program that gives the user three attempts to guess a number between 1 and 10. Here is what the program should do (in pseudo-code):

How to do it in code

In C++, we have a command called if. This is what it looks like:

if(...something...)
{
    // do stuff...
}

Of course, we need to change the phrase ...something... to a "conditional." The if command expects something that results in a bool value. So we can use bool values like true and false:

if(true)
{
    // do stuff...
}
if(false)
{
    // do stuff...
}

But these conditionals (true and false) are not very interesting because in the first case, the stuff inside the if block will always be executed (a "block" is the stuff between { and }). In the second case, the stuff in the block will never be executed.

More interesting conditionals may involve the following boolean operators (assuming p and q are bool variables and x is an int variable):

So we can write our guessing program like this:

#include <iostream>
using namespace std;
int main()
{
    int answer = 8;
    int guess;
    
    cout << "Enter first guess: ";
    cin >> guess;

    if(answer == guess)
    {
        cout << "Success!";
        return 0;
    }
  
    cout << "Nope. Try another guess." << endl;
    cout << "Enter second guess: ";
    cin >> guess;
    
    if(answer == guess)
    {
        cout << "Success!";
        return 0;
    }
    
    cout << "Nope. Try another guess." << endl;
    cout << "Enter third guess: ";
    cin >> guess;

    if(answer == guess)
    {
        cout << "Success!";
        return 0;
    }
    
    cout << "Nope. You are not allowed any more guesses, sorry!"
         << endl;
    cout << "The number you failed to guess was " << answer
         << endl;
    
    return -1;
}

if/else

Besides if we can also use else to specify some operations that should be executed if the conditional is not satisfied. Example:

if(x == 5)
{
    cout << "x equals 5!" << endl;
}
else
{
    cout << "x does not equal 5!" << endl;
}

Nested if's

if commands can be inside other if (or else) blocks:

if(x < 5)
{
    if(x < 0)
    {
        cout << "x is less than 0!" << endl;
    }
    else
    {
        cout << "x is less than 5 but not less than 0!" << endl;
    }
}
else
{
    cout << "x is not less than 5!" << endl;
}

Series of if/else's

It is common practice to check a series of conditions, where you only expect one of them to be true:

if(x == 0)
{
    // do stuff...
}
else if(x == 1)
{
    // do stuff...
}
else if(x == 2)
{
    // do stuff...
}
else
{
    // fallback...
}

An example of nested if's and an if/else-if chain

Task: Write a program that asks for three decimal numbers (a, b, c) and prints a message indicating whether the quadratic equation ax^2 + bx + c = 0 has no solutions, one solution, two solutions, or no real solutions (i.e., only imaginary solutions). Your program will need to make use of several if statements. Nest the if statements appropriately so that you do not test for a condition twice (e.g., you must check if a equals 0 only once, not five times). Here is the algorithm:

Examples:

Enter value 'a': 0
Enter value 'b': 0
Enter value 'c': 7
No solution.

Enter value 'a': 0
Enter value 'b': 0.5
Enter value 'c': 2
x = -4

Enter value 'a': 1
Enter value 'b': -6
Enter value 'c': 9
x = 3

Enter value 'a': 1
Enter value 'b': -3
Enter value 'c': 2
x = 1 OR x = 2

Enter value 'a': 1
Enter value 'b': 0
Enter value 'c': 1
No real solution.

The code:

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    double a, b, c, d;
    cout << "Enter value 'a': ";
    cin >> a;
    cout << "Enter value 'b': ";
    cin >> b;
    cout << "Enter value 'c': ";
    cin >> c;
    
    if(fabs(a) < 0.00001)
    {
        if(fabs(b) < 0.00001)
        {
            cout << "No solution." << endl;
        }
        else
        {
            cout << "x = " << (-c/b) << endl;
        }
    }
    else
    {
        d = pow(b, 2.0) - 4 * a * c;
        if(fabs(d) < 0.00001)
        {
            cout << "x = " << (-b/(2*a)) << endl;
        }
        else if(d >= 0.00001)
        {
            cout << "x = " << ((-b - sqrt(d))/(2*a)) << " OR "
                 << "x = " << ((-b + sqrt(d))/(2*a)) << endl;
        }
        else // i.e., d < 0.00001
        {
            cout << "No real solution." << endl;
        }
    }

    return 0;
}

"switch" statements

An alternative series of if/else's is the switch statement. The switch statement is the same as a series of if/else's because only one of the conditions should turn out to be true. The switch statement can only handle simple conditions, however; actually, it can only handle conditions of the form "is some integer equal to some value?" This means that a switch statement can only be used for integers.

Here is an example.

#include <iostream>
using namespace std;
int main()
{
    int number;
    cout << "Enter a number 1-4: ";
    cin >> number;
    
    switch(number)
    {
    case 1:
        cout << "You entered the number 1." << endl;
        break;
    case 2:
        cout << "You entered the number 2." << endl;
        break;
    case 3:
        cout << "You entered the number 3." << endl;
        break;
    case 4:
        cout << "You entered the number 4." << endl;
        break;
    default:
        cout << "You must have entered some other number."
             << endl;
    }
    
    return 0;
}

The switch statement above can be rewritten with a series of if/else's:

// the following is the same as the "switch" statement above
if(number == 1)
{
    cout << "You entered the number 1." << endl;
}
else if(number == 2)
{
    cout << "You entered the number 2." << endl;
}
else if(number == 3)
{
    cout << "You entered the number 3." << endl;
}
else if(number == 4)
{
    cout << "You entered the number 4." << endl;
}
else
{
    cout << "You must have entered some other number."
         << endl;
}

Notice that an if is much more powerful: you can use very complicated conditionals. On the other hand, a switch is very simple: for each "case", you provide a value that is compared to the variable used in the switch (in this case, the variable used in the switch is "number"). Each case basically asks, "does the value in the variable equal this number?"

Each "case" in a switch needs a "break" at the end so that the next case is not entered. It's good practice to always include a "break" at the end of each case in a switch.

The "default" case is the case that is used if all the other cases fail.

You can also use a switch to determine which character a user typed, since characters are themselves just integers. Here is an example:

#include <iostream>
using namespace std;
int main()
{
    char letter;
    cout << "Enter a letter: ";
    cin >> letter;
    
    switch(letter)
    {
    case 'a':
        cout << "You entered the letter 'a'." << endl;
        break;
    case 'b':
        cout << "You entered the letter 'b'." << endl;
        break;
    default:
        cout << "You must have entered some other letter."
             << endl;
    }
    
    return 0;
}

Another view of the "if" construct

It turns out that, in C and C++, any integer that's not zero is considered a "true" value, and zero is considered the singular "false" value. Thus, these are equivalent:

int x = 5;
if(x != 0)
{
    cout << "x is not equal to zero." << endl;
}
if(x)
{
    cout << "x is not equal to zero." << endl;
}

Actually, the details are more gruesome than this. So it's best to avoid such trickery.

if conj. 1 (Poetic) Kiplingian milestones on the road to mandelayhood and gambler's ruin. 2 (CS) One of many conditional control-flow obstacles faced by a process linearly anxious to complete the next instruction without tiresome, trivial, testing diversions.

Some programmers see if as the soul of machine intelligence. Thus,

if(CurBankBal <= 0) errmsg("Spendthrift scoundrel!");
else exit(0);

forms the core of many a smart, ethical money manager. The home-exit loving, non-judgmental process, however, reluctantly forced to test transient bits of registers, is tempted to rule in favor of else. Baudelaire predicts these nuances in Les Hiboux: "Sous les ifs noirs qui les abritent..." The if's in procedural computer languages are followed by boolean expressions that reduce at runtime to TRUE or FALSE. Logical implication is replaced by material implication: TRUE implies that the then clause (possibly empty) is obeyed, while FALSE triggers the else clause (also possibly empty). Note that we lose the asymmetry of logical implication (true implies true, but false implies anything), and you are free to interchange FALSE and TRUE: they are essentially arbitrary attributes with no semantic significance. You are equally free to switch your then and else clauses.

C is rather different. The interesting quirk with C, in the absence of a dedicated Boolean type, is that zero is Boolean FALSE, while nonzero is TRUE. An expression such as (1 != 1), which most would regard as patently false, does indeed evaluate to zero; (2 == 2) evaluates to the integer 1, which is abundantly nonzero and eminently true.

The interesting point is that FALSE is single-valued (I exclude the metaphysics of null pointers, huge, near, and far) while TRUE is legion. There may be a Zarathustrian strand here: the diabolical equivalence of all dark lies constrasting with a billion points of light? However, when you want a function to return TRUE for success and FALSE for failure, a perfectly natural, dare I say, intuitive ploy, you hit a snag. Success is a one-of-a-kind-blessing, failure comes in whole battalions. To have the function return an instructive error code, it is necessary to rephrase the question pessimistically: Did the function fail? Yes, TRUE! Why did it fail? Test the nonzero return value:

if(e = f()) { // did f() fail?
  switch(e) { // why?
    case 1: // one reason for failure
      ...
    case 2: // and another
      ...
    case n: // no end?
      ...
    break;
  }
}
// success

Some see life itself as a huge case statement. -- The computer contradictionary

CSE 230 material by Pawas Ranjan is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. Source code for this website available at GitHub.