OS X games from the ground up: loops

You can see an index of all the posts in this series: go to index.

If you are starting from this point, or need a fresh set of files, here are the starter files from the end of the previous post: more on decisions and functions

In the previous post you made improvements to the code that reads and validates the command line. Now that we have the number of phrases the learner wants to see, it’s time to do something with it.

Change your code so it looks like this:

The changed code is between lines 46 and 55.

You’ve seen how we can control whether a block of code gets executed by using if and else commands. Sometimes we need to execute a block of code multiple times. This is exactly the situation we have here. We want to execute line 53 as many times as it takes to display the number of phrases requested by the user. One way to do that is with a while command. While works in a similar way to if, in that it has a condition in parentheses followed by a body between braces. However, whereas if will execute the statements in its body once if the condition is true, while will execute the code in its body repeatedly while the condition is true.

Let’s assume that the user has requested two phrases and follow the code through step by step to see what happens. In line 50 we declare and initialise a counter called i. The counter will keep track of the number of phrases we’ve displayed. In line 52 the while command checks to see if i is less than numberOfPhrases. It is, because i is currently 0 and numberOfPhrases is 2. So the body (lines 53 and 54) is executed.

The first line of this code displays a randomly generated phrase – you’re already familiar with this line from previous posts. The second line introduces a new operator, the increment operator ++. The statement i++ is equivalent to i = i + 1. The reason we have a special operator for it is that adding 1 to a variable is something you end up doing a lot in code. There’s also an equivalent decrement operator, --, which subtracts 1 from a variable. So what this second line is doing, is adding 1 to our counter because we’ve just displayed a phrase.

One important thing to note about the increment and decrement operators is that they can work in two different ways, with the operator placed either before the variable, e.g. ++i, or after the variable, e.g. i++. These both do the same thing if they are used on their own in a statement, the difference comes when they are used in an expression and/or an assignment. When the prefix form is used, ++i, the value of i used in the expression or assignment will be its value after it has been incremented. In other words, this code:

would display “result is 4 and i is 2”.

If you use the postfix form, i++, the value of i used in the expression or assignment will be its value before it is incremented. So, this code:

would display “result is 3 and i is 2”.

OK, back to our Buzzword code. Now we reach the end of the body, marked by the closing brace on line 55. Instead of continuing with the next bit of code outside the braces, as we would do with an if command, control is passed back to the while command on line 52, which once again checks to see if i < numberOfPhrases.  It is, because i is now 1 and numberOfPhrases is 2.

So the body is executed once more. A second phrase is printed and i is incremented, so it now equals 2.

Once again we reach the end of the body and go back to the while command on line 52. This time, when the condition is checked, i is not less than numberOfPhrases, because they both now equal 2. So now the body is not executed and control passes to the statement following the closing brace, which in our case is the return statement on line 57.

Edit the scheme and change the argument to a single digit number, say 5. Now build and run the code. You should get something like this:

Buzzword loop five times

Count the phrases and satisfy yourself that you have exactly five, no more, no less.

Here’s another example of a while loop:

Take a close look at this loop and see if you can work out what number will get displayed by the printf command in line 11.

If you said 5, then well done, you’re starting to get the hang of loops, but you missed something that would prevent this from happening. If you said the number will never get displayed, then my hat off to you for your powers of observation and deduction.

You’ll remember from a previous post that a common programming error is to use the assignment operator, =, when you meant to use the equality operator, ==. You’ll also recall that when you use the assignment operator in a condition, it always evaluates as the value of the assignment. If you look closely at line 4 you’ll see that’s exactly the mistake that’s been made here. Each time the condition on line 4 is evaluated, rather than being compared to 1, keepGoing will be set to 1. Since an assignment always evaluates as the value of the assignment, the condition will always evaluate as 1. You’ll recall that C interprets any non-zero number as true, so this loop will never end and the printf command will never be reached. If you ever have a programme seem to hang on you and sit there doing nothing, one of the first things to check is that you haven’t made this sort of error in your loops.

Let’s review the parts of our loop in Buzzword. We have:

  • A counter called i, which we declare and initialise on line 50.
  • A condition, on line 52, that is evaluated at the start of each loop to determine if the loop should continue
  • A statement on line 54 that updates the counter.

Now, it so happens that the need for a loop that includes these three things occurs so often in C programmes that there’s another command, called a for loop, which is dedicated to constructing loops of this nature. Let’s update our code to use a for loop instead of a while loop:

The changed code is on lines 50 to 52.

You can see that the for loop is a lot more compact than the equivalent while loop. That’s because all three of the components we identified are included within the parentheses following for, and separated with semicolons:

Note that, like a while loop, the for loop executes the first of these statements, the initialisation statement, once before the start of the loop. The second statement, the condition, is executed each time through the loop before the body is executed. The final statement is executed after the body has been executed. You should also note that there is no semicolon after this third statement.

Try building and running the programme again and you should get exactly the same number of phrases as you did with the while loop.

Notice that with both forms of loop our counter started at zero and we incremented it at the end of the loop. What that means is that once the counter is equivalent to numberOfPhrases we have already displayed enough phrases. That’s why we’re checking that the counter is less than numberOfPhrases(i < numberOfPhrases), not less than or equal to numberOfPhrases: (i <= numberOfPhrases). For that to work, we’d have had to change the declaration and initialisation of i to int i = 1. It’s easy to use the wrong condition for the starting value of your counter, which will mean your loop will execute either one time more than it should or one time fewer. This is known as an off by one error. It’s another thing to check for if your code isn’t behaving as you expect.

At this point I want to address something that might have been bothering you. In a previous post I stressed the importance of giving meaningful names to variables, and yet here I am calling a variable i. Well in this case it’s a valid exception. It’s traditional to use i for counters in loops. These types of variable are sometimes referred to as index variables, which is where the i comes in. You can safely use i as a variable name in this way as experienced programmers will understand, from the context, what it means.

This is all great, and we’ve had fun extracting information from the command line, but so far we are not living up to the promise of the original programme. In the original, the user could decide after each phrase if they wanted another phrase or not. We’ll fix that in the next post.

In the meantime, here’s a challenge for you. There’s yet another type of loop in C, called the do … while loop. It looks like this:

do {
       .
       .
       .
} while (condition);

Here’s how it works. Everything in the braces is executed at least once. At the end of each execution, the condition is tested and, if it’s true, the loop is repeated. One thing to note about this type of loop is that, because the condition comes at the end, not the beginning, it’s terminated with a semi-colon.

Your challenge is to rewrite the programme to use a do … while loop. The solution will be shown in the next post.

 

This entry was posted in Games, Programming Tutorials and tagged , , , , , . Bookmark the permalink.

Leave a reply