Boolean things: Asking complex questions

Earlier, we looked at forming questions using C++ Logical Operators. We will be using these questions in places like our basic decision structure, the it-then-else statement. Let’s look at a simple example:

int x = 10;
int y = 20;

if(x < y) {
    cout << "yep, 10 is less than 20" << endl;
} else {
    cout << "Whoops - math seems broken here!" << endl;
}

Let’s ask a different kind of question. Is a number between 10 and 20?

A simple way to determining the answer is to ask it in two parts:

  • Is the number greater (or equal) to 10?
  • Is the number less than (or equal) to 20?

Let’s ask the question using two if-statements:

if (x >= 10) {
    if( x <= 20) {
        cout << "number is in the zone!" << endl;
    }
}

Now, if we had things to do if the number was less than 10, and other things to do if it was greater than 20, we could write it this way:

if (x >= 10) {
    if (x <= 20) {
        cout << "number is in the zone" << endl;
    } else {
        cout << "number is above the zone" << end;
    }
} else {
    cout << "number is below the zone" << endl;
}

See how we use indenting to organize a statement set like this? It really helps in figuring out what will happen when we process the code

Is this is clear?

I do not feel good about this code. It does not feel right, even though it will work right. The order of the output statements is wrong. I want them in the right order. How will I do that?

The answer involves asking the questions in a different way. Before we do that you need to be able to figure out what the opposite of a relational operator is. If the operator is less, what is the opposite? (If you came up with greater or equal you are on your way!)

Check this out. Is it the same as the previous code?

if (x < 10) cout << "below the zone" << endl;
else if(x <= 20) cout << "in the zone";
else cout "above the zone" << endl;

Wait a minute! Where did all the curly brackets go? The answer is easy - if all you want to do is one statement (even if it is a big one), you do not need the curly brackets! It does not hurt to include them, but they are not really needed - you get to choose how to write the code!

Look at the style as well. Any time we have a series of nested if statements, this style helps keep things from indenting off the right side of the page!

Boolean variables

C++ supports variables that can only hold boolean values (true or false). They are declared like this:

int     zone_lower_limit = 10;
int     zone_upper_limit = 20;

bool    below_zone;
bool    in_zone;
bool    above_zone;

Now, we can set these variables like this:

below_zone = (x < zone_lower_limit);
above_zone = (x > zone_upper_limit);
in_zone = (x >= zone_lower_limit && x <= zone_upper_limit);

In that last one, we are using the boolean operator and to combine the two logical expressions into a single, more complex questions.

Now, out code becomes:

if (below_zone) cout << "below the zone" << endl;
else if (in_zone) cout << "in the zone" << endl;
else cout << "above the zone" << endl;

We can even use the reserved words true and false in our code. What would this do?

while(true) {
    // do something a lot
}

There is a simple statement to get us out of this mess:

int count = 0;
while(true) {
    count = count + 1;
    if(count > 100) break;
}

In spite of looking like it will spin forever, the break statement aborts the immediately enclosing loop. Here is a complicated (and silly) example:

1
2
3
4
5
6
7
8
9
int count = 0;
while(true) {
    count = count - 5;
    while(true) {
        count = count + 5
        if(count > 5) break;
    }
    if(count<100) break;
}

ALthough this code is silly, it is legal! It is also a place where we can demonstrate something called desk checking.

Desk checking

Often, you will want to sit down with your code and thnk through how it will work before you plug it into the computer. WHat will the above code fragment do? we can find out by creating a table and processing each line of code by hand:

Line count next line
1 0 2
2 0 3
3 -5 4
4 -5 5
5 0 6
6 0 7
7 0 4
4 0 5
5 5 6
6 5 7
7 5 4
4 5 5
5 10 6
6 10 8
8 10 10

Phew! It is important that you learn this skill. You will be puzzling over why your code does things, and sometimes just thinking it through will help solve problems. Of course, you can always use a debugger to track your code! (This would be a good exercise for you!)

Comparing logical sequences

Look at this code:

if (below_zone) cout << "below_the zone" << endl;
if (in_zone) cout << "in the zone" << endl;
if (above_zone) cout << "above the zone" << endl;

Will this work the way our previous example worked?

Ready to try a simple function?

Many times, introducing a simple function can make your code easier to read (always a good thing to do!)

void zone_check(int x, int lower, int upper) {
    bool    below_zone;
    bool    in_zone;
    bool    above_zone;

    below_zone = (x < lower);
    above_zone = (x > upper);
    in_zone = (x >= lower && x <= upper);

    if (below_zone) cout << "below_the zone" << endl;
    if (in_zoxe) cout << "in the zone" << endl;
    if (above_zone) cout << "above the zone" << endl;
}

now all the code we had set up to do the work is reduced to a simple function call:

zone_check(x, 10, 20);

By itself, this is not that amazing. But what is we were looking at a bunch of values in a simple loop:

int position = 0;
while(position < 100) {
    zone_check(position, 20, 30);
    position = position + 5;
}

Now this looks pretty clean. Of course, I am not sure I have a good reason for doing this. Maybe I can come up with one:

Perhaps we have a zone of interest in a game. Before we get to the zone, the players are looking around for danger. In the zone - well, bad things happen!. After we clear the zone, we recover from the mess! With this setup, we can adjust the zone limits, and simple let the figure move across the screen.

Functions can help simplify the code so we focus on the action we want to happen. We use the function to hide the details, they are in another part of the program where we focus on just that part of the logic.

More on how functions work

If you look at the code above, I moved all the variables to a point inside the function. They were all associated wit the logic os doing zone work, and were not needed elsewhere in the program. In this position, they are called local variables. The names of the variables, and the values are unknown to any other part of the program. Pretend there is a wall around the function, and no other code can use the names inside. This is handy, since otherwise we have to watch for name collisions where a name being used for one thing is suddenly interfering with the same name being used for something else. Local variables come into life as the function wakes up, and disappear when the function ends. They are only needed while the function code is being processed.

The names used on the function parameter list act the same way, with a minor (but important) difference. The names defined with the function itself are also local variables and the exact names are not known to the code that calls the function. These variables are special in that they are given values when the caller decides what values they should have. Inside the function, we can do whatever we want with those variables. Unless the parameters are defined as reference parameters, the changes in these variables will not be felt by any other part of the program. We will get into this more later!