Simple recursion
The goals of this lab are to get you accustomed to recursion in C++ and
to expose you to the concept of stack frames. You'll learn
to explore stack frames in gdb.
- The following file contains a program which does
exponentiation as described in exercise 5.22. Please read the
exercise. (There's one typo in the exercise; the fraction
1/xn should be
1/x-n.) Copy the lab files to a called, say,
recursion, using the following command:
cp -r ~mc38/labs/recursion/files recursion
- cd to this directory, and type make -k.
You'll get one warning. Try running ./power in the shell;
you should notice that there is a bug. You'll explore this bug in the
first portion of the lab; please don't try to fix the bug until
instructed to do so below.
Stack frames
Open the file power.cc and use gdb to inspect
the run of your program as follows. As you complete this portion of
the lab, do not delete your gdb buffer. We'll take a
look at it when we check you off. You'll want to follow these
instructions to the letter.
As you work through this problem, please ask if you have any
questions. Be sure you grasp all the concepts.
- Set a breakpoint at the top of the int_power. (As
always, you can either type C-x SPC in the code buffer, or
by typing b int_power to gdb.)
- Run your program to compute 214. Gdb should stop
at your breakpoint, and report the arguments to
int_power (2 and 14).
- Hit n or next until int_power is
called recursively. Observe that the breakpoint was hit again, and
the arguments are now 2 and 7.
- Hit c or cont several more times until the
arguments are 2 and 0. (If you hit c once too many, the
program will output the wrong answer. In this case, I
recommend you kill the gdb buffer and start over.)
- Type where or bt or backtrace.
This shows you the execution stack with 8 stack frames
numbered 0 through 7. Notice that main called
int_power, which called int_power, and so forth.
- Type up and down to go up and down the stack
frames. You can go all the way back up to main. Each stack
frame has its own copy of all the local variables in your program.
Note that you aren't executing your program as you do this, you are
merely looking at what procedure calls are currently active.
- Try inspecting the local variables in some of the stack
frames with the gdb command info locals. See if the
values of the variables makes sense. Notice that uninitialized
variables have arbitrary values. Notice also how static
variables are the same in all stack frames.
- Go back down to the next-to-lowest stack frame (frame 1 with
arguments 2 and 1). Hit bt or where once more to
remind yourself what the stack looks like.
- Type fin or finish. This asks the program to
continue execution until it returns from the stack frame you are
currently in. It also reports the return value from the procedure
call. Now, if you do a bt or backtrace or
where, you'll see that there are two fewer stack frames
active. Make sense? (If not, stop and ask.)
- Type fin one more time. You should notice the
incorrect return value of 0. This is our bug!
- We'd like to rerun the program, and quickly get to the place
where the program stopped. Type cond 1 exp == 2.
This says, "Break at breakpoint number 1 only if the value of
variable exp is 2."
- Type the command info break lists all your
breakpoints.
- By the way, you can also type dis 1 or disable
1 to disable a breakpoint and ena 1 or enable 1
to cause it to start working again. You might want to try these, and
type info break to see what happens. In any event, leave the
breakpoint in the enable state before going on.
- Now, type run to run the program from the top. Again,
enter the arguments 2 and 14.
- Use n or next to single step through the
program and see if you can figure out what went wrong. Inspect each
local variable at each step.
- Check-off Report the bug and explain how to fix it.
Be sure to have your gdb buffer on the screen for our
perusal.
- For your reference, power-better.cc contains a
reasonable version of the program.
Although the program addresses exercise 5.22, it still has a flaw.
You may wish to think about what this flaw is.
Draw a ruler
- Complete the code in ruler.cc
to draw a ruler. You can run the sample solution in
~mc38/labs/recursion/ruler
- Check-off Don't forget to get checked off. Be sure
the code is well documented and clear.