Chapter 11 - Looping with FOR
Back in the '80s, I used to work as a programmer for a company that
made weighing machines. One project I had was to design a program to
load weights onto a series of scales and take readings. The test
station was to test four scales in turn. A colleague had tried the task
and failed because he developed the code for one machine and then tried
to copy it four times. A BBC Model B had 32k of memory: his program
wouldn't fit. He was completely unaware of the computer's ability to
run the same code repeatedly using a FOR loop. Effectively, I rewrote
the program so it did this:
REM Scale
test |
FOR Scale%=1 TO 4 |
REM load some weights |
REM get some readings |
REM print the results |
NEXT Scale% |
END |
Line 2 is the start of the loop. It tells the computer to use a
variable (Scale% in this case) to keep count of how many times a loop
has run and stop it when it gets past a limit, in this instance 4. When
the line is first encountered, Scale% is created and set to 1. Lines
3-5 are then run. When line 6 is executed, the program jumps back to
line 2, increases Scale% by 1, compares it with the final value, sees
that it is less and runs lines 3-5 again. On the last repeat, when
Scale% is 4, the program increases Scale% by 1,
sees it has exceeded the final value and jumps to line 7 where it
carries on with the rest of the program.
That's quite a lot of functionality for 2 lines of code, but as you've
probably guessed, it doesn't stop there. For a start, the counter
variable can be used in the loop itself so the code knows where it's up
to:
REM Scale
test |
FOR Scale%=1 TO 4 |
PRINT
"Currently testing
scale: ";Scale% |
REM load some weights |
REM get some readings |
REM print the results |
NEXT Scale% |
END |
...
or to make decisions:
REM Scale
test |
FOR Scale%=1 TO 4 |
CASE
Scale% OF |
WHEN
1 : PRINT
"Testing first
scale" |
WHEN 2 : PRINT
"Testing second
scale" |
WHEN
3 : PRINT
"Testing third
scale" |
WHEN 4 : PRINT
"Testing fourth
scale" |
ENDCASE |
REM load some weights |
REM get some readings |
REM print the results |
NEXT Scale% |
END |
... or anything else you may need it for. Obviously, the counter has no
validity outside the loop, so don't use it there.
The start and finish values can take any logical value:
FOR Count%=-10 TO
10 |
PRINT
Count% |
NEXT Count% |
or they can be variables or expressions:
FOR Count%=MinValue% TO MaxValue%-10 |
PRINT
Count% |
NEXT Count% |
Each counter will start at the first value and increase by one until it
passes the second value. You, as a programmer, must be careful here. If
the final value is less than the start value, BB4W won't complain but
you might be puzzled as to why your loop isn't behaving. Different
dialects of BASIC react differently to this situation. BBC BASIC will
run the loop at least once whatever values you give it.
There may be times when you want the program to repeat loops in
increments other than one. Here, a new keyword can be used to force
this. The following code will print all the odd numbers up to 20.
REM
STEP demo |
FOR Count%=1 TO 20 STEP 2 |
PRINT
Count% |
NEXT Count% |
END |
The keyword STEP forces the increment to the value specified. Again, it
can be any logical value or expression for the type of variable you are
using.
FOR I=1 TO 5 STEP 0.5 |
REM ... |
It can also be negative:
FOR I%=10 TO 1 STEP -1 |
REM ... |
In this case, BASIC works out that it's going in reverse and instead of
stopping when I% is greater than 1, which it would do instantly, it
stops when I% is less than 1 - makes sense really.
As with any other construct, it is possible to nest one inside another:
FOR I%=1 TO 5 |
FOR
J%=1 TO
5 |
PRINT
I%,J% |
NEXT J% |
NEXT I% |
Here, the inner loop is executed 5 times for each time the outer loop
runs. The inner loop has to be fully contained in the outer loop. Try
swapping NEXT J% and NEXT I% and you will produce an error.
After all these variations on FOR, the other end of loop is not very
exciting. NEXT is used as a placeholder to denote the end of the loop.
The name of the count variable is not really needed as BASIC is clever
enough to work out which NEXT ties up with which FOR. I prefer to put
them in as it makes the code easier to read, especially if the loop
covers more lines than can fit on the screen at one time.
In our nested example above, line 4 could have been replaced with:
Try it, remove or REM line 5 first. The program will run as before
doing 5 inner loops for each outer loop. BASIC will even accept:
Personally, I don't particularly like this method as it is not obvious
where loops end and it messes up the indentation that the editor so
neatly provides. That's just my preference though and you will see this
used in other code.
Tip: Warnings with FOR loops
|
To end, I would like to mention several common errors
that experience has taught:
a) Don't jump out of a loop using GOTO; if it's necessary, force the
counter to a number above the final value and let it end naturally.
b) Please, please, please don't use conditional NEXTs. People condemn
GOTO for encouraging bad programming practices, but it is possible to
do bad things with any command. What I'm talking about is this sort of
thing:
REM ...
program |
FOR I%=1 TO MaxNumber |
PRINT I%^2 |
IF I% MOD J%=0 THEN NEXT |
IF I%-1=J% NEXT ELSE
J%=I%+1 : NEXT |
REM
Rest of program ... |
|
There are so many NEXTs here that the editor gets confused, and so will
you. Always have only one NEXT for each FOR and give it a line to
itself so the indentation allows you to clearly see where the loop
starts and ends. You can always use block IFs to run code conditionally
if required.
c) It's common amongst programmers of many languages to use I% and J%
as counters. So much so that it is easy to forget and reuse the same
counter deep within the code of another loop:
FOR I%=1 TO 10 |
REM ... several pages of code ... |
FOR J%=1 TO 10 |
FOR
I%=1 TO
99 |
REM Problem here using I% as we've |
REM just reset the first loop |
|
You'll see what I mean one day because everyone does it, even though
they've been warned!
|
Exercises
1) Write a program with a FOR loop to print the 5 times table. Each
line should be in the format:
1 * 5 = 5 |
2 * 5 = 10 |
... |
12 * 5 = 60
|
2) Use two nested FOR loops to draw a rectangle on the screen by using
a line like PRINT TAB(X,Y);"*"
© Peter Nairn 2006