This exercise is to supplement your reading on loops. It also
introduces you to the BGI collection of graphics functions that we'll use
to draw objects from within a C++ program.
Getting the Demonstration Programs
Start this exercise by opening a cs1300 command-line window.
Create a directory to work in (I would suggest moving over to the D:
drive and moving down to your own directory, as you did last week), then copy these files
to your working directory:
You can
right click on the names above to download them.
The Purpose of loops.cxx
The purpose of loops.cxx is to let you step through a couple different
kinds of loops. Apart from that, the program doesn’t really do anything
useful. Anyway, go ahead and start emacs with the
loops.cxx file. You can look through the code to get an idea of what the
program is doing. Compile the program. Then run the program once and give the W response, and run it a
second time with the F response. Running the program in this way won’t be
particularly enlightening, but using the debugger you can get more out of
the program.
Putting some breakpoints in the program
The loops program will be most useful if you use the debugger to run the
program with two breakpoints. Remember from Exercise 2 that
a breakpoint is a statement in your program
where you want the program to stop so you can examine the state of affairs
more closely. To set the first breakpoint, move down through the file until
the cursor reaches
the line in the main program which calls a function named savings_time.
It looks like this in the main program:
case 'W': case 'w': // Call savings_time
many_years = savings_time(50, 100, 0.10);
Put the cursor on the "many_years..."
line shown above, which is the line that calls the
savings_time function. We will put a breakpoint at this line, so that when
the program executes, it will stop here to let you examine matters.
To set the breakpoint, open a second window, start gdb in that window,
move the cursor back to the line where you want a breakpoint,
and press Ctrl-x Spacebar.
Next, move down to the line that calls the second function, called
future_balance. The line looks like this:
case 'F': case 'f': // Call future_balance
final_balance = future_balance(50, 0.10, 5);
Set a second breakpoint on this "final_balance..." line.
Running the Program up to the Breakpoint
With the two breakpoints in place, you can run the program in the usual way. When you are asked which kind of loop to see, respond with W.
The program will then run until it reaches the breakpoint at the statement
"many_years = savings_time(50, 100, 0.10);".
This line calls the savings_time function to determine how many years are
required to increase a balance of $50 to a goal of $100 with an annual
interest rate of 10%. We want to step into this function and watch the
lines execute one at a time to see how a while-loop works.
When you are executing a program, the command to
step into a function and
see the lines execute one at a time is the s key followed by the
return key.
Give the s command now, and
the program Steps to the start of the savings_time function.
(Note that s is slightly different that the n command. The n command executes
an entire line without stepping through any functions line-by-line.)
Setting Watches
In a moment you will step through the savings_time function, one line at a
time. But first, let’s set things up to watch the values of a few
variables.
Put watches on the local variables balance, goal and years.
You should now continue executing the savings_time function.
In order to execute the lines of the function one at a time, give the
n command. The function’s first statement, years=0, is now highlighted and
ready to execute. Press n and the statement will execute, setting the value
of years to zero in the Watch window. The highlighted line moves down to the
first line of the while-loop:
while (balance < goal)
Seeing the While-loop in Action
The loop that we are about the execute will calculate how many years are
required to increase the balance ($50.00) to the goal ($100.00) at the
stated interest rate (10%). At the start of the loop’s execution, the
highlighted line is the while-statement:
while (balance < goal)
This is the statement that controls the while-loop. The statement indicates
that the loop should continue as long as balance is less than goal.
At the moment, balance ($50) is less than goal ($100), so the loop will
continue executing. To continue this execution, press n again
(or just press the return key, which repeats the previous command).
The
highlight moves to the first assignment statement in the body of the loop
(balance = ...). At this point, you should execute the two lines of the
loop’s body by giving two n commands. These statements will increase balance to
$55, and increase years to 1. The highlight will once again be at the first
line of the while-loop:
while (balance < goal)
The balance ($55) is still less than the goal ($100), so the loop continues.
Execute three more lines, and once more you are back at the top of the loop.
This is what a while-loop does: It goes around and around, always controlled
by the expression at the top of the loop. The current balance ($60.5) is
still less than the goal ($100), so the loop continues. again. Keep
executing,
keeping an eye on the value of the balance. Stop when you notice that
the balance is greater than or equal to 100. At this point, the balance should be
107.1794, and years is 7.
The program is still executing inside the loop. The highlighted statement:
years = years + 1;
is about to be executed. Now, at this point, balance is bigger than goal--so
you might be thinking that the loop should stop. But it won’t--not
quite yet. The loop must always continue until it reaches the controlling statement at the top. At that point, the loop uses the control statement to determine whether to continue.
For our example, execute one more line. The value of years increases
to 8, and we are back at the top of the loop. Now, balance is no
longer less
than goal, so the loop will end. To see this, execute
one more line and the highlighted statement moves after
the loop to: return years; This is the function’s return statement, which returns 8 (the current value of years). In other words, it took 8 years to increase $50 to at least $100 at a 10% interest rate.
You can continue pressing return to complete the execution of the
program. When the execution completes, the arrow will be on the last
closing bracket of the main program.
Running to the Second Breakpoint
You can now run the program a second time. This time you should answer F when you are asked what kind of loop you want to see. The program will run to line that calls the future_balance function:
final_balance = future_balance(50, 0.10, 5);
Stepping into the future_balance Function
This function call computes how much money will be in an account that starts
with a balance of $50 and earns 10% annual interest for 5 years. To step
into this function, give the s command once. The compiler jumps to the first
line of future_balance, displaying the values of the arguments and
local variables.
Seeing the For-loop in Action
We haven't talked about for-loops yet, but you can get an idea for
this kind of loop by seeing the statements of the function’s for loop executed
one at a time. Give the n command once, and the highlighted line jumps into the function’s body. Here’s what you see on the screen:
for (i=0;
i<years;
i++
)
These four lines combined are actually the control statement of a
for-loop. Normally the control statement would be written on a single line,
like this: for (i=0; i<years; i++)—but we have broken it into separate lines so that the debugger can show precisely how the different parts of the control statement are executed. In order to see this execution more clearly, put a watch on the local variable i, and then move to the next step of this exercise.
The Initialization Clause of the For-Loop
The control statement of every for-loop has three parts, separated by
semi-colons. The first part is the initialization clause. For our example,
the initialization clause is the highlighted statement i=0;
The initialization clause is always executed once when the for-loop
begins. For our example, execute one line now; the assignment i=0
will be executed, and i changes to zero in the watch window. The
highlight moves to the second clause in the for-loop’s control
statement. (Note: This doesn't seem to work for all versions of
gdb. It might go straight into the body of the loop.)
The Repetition Test Condition
The second part of a for-loop’s control statement is the
repetition test condition. This is a test, such as our test
i<years. The test is executed each time before the body of the loop
is about to begin. If the test is true, then the loop continues.
If the test fails, then the loop stops. In our example, the test i<years
is true. So, press n to execute this test, and the debugger will move the highlighted statement to the inside of the loop’s body.
Executing the Body of the For Loop, and the Update Clause
The body of our for-loop is now ready to be executed. This body consists of
two assignment statements, so you should press n twice to execute these
statements. After the second assignment statement, the debugger will move
the highlight to the third clause in the for-loop’s control statement.
This clause, which is written i++ in our example, is the update clause.
The update clause is executed each time the body of the loop finishes.
In our example, the update clause i++ adds one to the value of
i. Press n to execute the update clause, and the highlight moves back to the repetition test condition. You have now seen the complete cycle of a for-loop, which looks like this in a diagram:
Execute the For-loop to Completion
At this point you can use the n key to execute our for-loop to completion. As you are executing the loop, pause for a moment whenever the repetition test condition is highlighted. This condition,
i<years, determines whether the loop should continue. When the condition becomes false, the loop will end. When the loop ends, you can continue executing the program to completion.
Introduction to BGI
There's one more brief task before the end of this exercise.
The task introduces you to the graphics library that we'll use
throughout the semester. From your working directory, compile
the program bgidemo0.cxx
bgi++ -Wall -g bgidemo0.cxx -o bgidemo0
The bgi++ command is a lot like g++, except that it allows you to use
certain graphical functions in your program. After running the command, you should end with an executable file called bgidemo0.exe.
Run the Demonstration Program
From the command line, run the demonstration program by typing
its name (bgidemo0).
Press any key to step through the program. Keep going until it ends. The last screen contains
the message
"That's all, folks!"
A Simpler Graphics Program for You To Modify
Whenever you run a BGI program, you'll have to compile and run it as you did with
the bgidemo program (using the bgi++ command).
Writing a BGI program also requires some techniques that
are more easily illustrated with the small graphics program,
bgismall.cxx.
Compile and run
this file now. Then bring up the source code in emacs and
notice these things:
In order to use any BGI graphics, you must always compile with bgi++
rather than g++.
To access the BGI library, the program includes the graphics.h header file with the
directive
#include <graphics.h>
When a program begins execution, it opens a graphics window where the
drawing will occur. Text input and output may still go through the
original text window (using cin or cout), or it may go to the graphics
window using other commands.
The program needs to call the initwindow(...) function to
initialize the graphics screen and begin graphics mode. In bgismall.cxx,
the main program calls initwindow(450, 300), which
creates a graphics window that is 450 pixels wide and 300 pixels high.
The graphics screen consists of a grid of pixels which can be thought of as points of light on the
screen. For smaller monitors, the grid usually has a maximum of
640 pixels in the horizontal direction ( numbered 0 to
639 from left to right ) and 480 pixels in the vertical direction ( numbered 0 to 479 from top to
bottom).
If we take x to be our name for the coordinate in the horizontal direction and y for the
vertical direction, then the origin ( x = 0, y = 0 ) of the numbered grid is in the upper left corner
of the screen. The x-coordinate increases as one moves to the right. The y-coordinate increases
as one moves down the screen. The direction for increasing y is opposite to our usual practice,
and will probably cause much hardship until everyone becomes used to it.
In general, the code that you write should not depend on a particular screen size. Instead,
you should call the BGI functions getmaxx() and getmaxy() to
get the maximum x and y pixel numbers.
Once the program in in graphics mode, there are nearly 100 different BGI functions that can
be used. The bgismall program uses these functions:
putpixel(x, y, color) -- draws a pixel in a particular color at a given x and y
location.
setcolor(color) -- determines the color for subsequent drawing functions such
as line and circle.
line(x1, y1, x2, y2) -- draws a line from (x1,y1) to (x2,y2).
circle(x, y, radius) -- draws a circle with center (x,y) and the specified radius.
These graphics functions may also be called from within other functions (such as within
the triangle function that is part of bgismall.cxx).
When the program is finished drawing it should call the function
getch().
This pauses for the user to press the return key (with the mouse focus
in the graphics window). Then call
closegraph() to close the graphics window.
More BGI Functions
Play around with the bgismall.cxx program a little bit, making it draw
some new lines or use new colors.
A complete list of the BGI functions is
available at
www.cs.colorado.edu/~main/cs1300/doc/bgi/index.html).
You may have noticed that any program that's compiled with g++ or
bgi++ will always open a DOS command window when the program is run.
If you want to stop this window from opening, then add the option
-mwindows to the compile line (just after g++ or bgi++).