SYSC2006 L03 Functions Recursion
SYSC2006 L03 Functions Recursion
● main.c and sput.h implement a test harness (functions that will test your code). main.c
contains five functions. Functions test_power1, test_power2, test_power3 and
test_power4 contain the code for four test suites, one for each of the four functions in
power.c. (These functions are explained in Step 6.) Function main controls the execution
of the test suites. Do not modify main.c or sput.h.
Step 4: Run the project. It should build without any compilation or linking errors, but you will see
that all tests fail.
Step 5: Read this step carefully.
Double-click the icons for main.c and power.c to open these files in editor windows. Locate
function test_power1. This is the function that checks if power1 correctly calculates 20, 21, 22
and 23. Here is the code for this function:
static void test_power1(void){
sput_fail_unless(power1(2, 0) == 1, "power1(2, 0)");
printf("Expected result: 1, actual result: %d\n", power1(2, 0));
1
SYSC 2006: Foundations of Imperative Programming
The four checks are performed by sput_fail_unless, which has two arguments. The first
argument is a condition that must be true in order for the test to pass. The second argument is a
descriptive string that is displayed when sput_fail_unless is executed.
For example, the first call to sput_fail_unless determines if power1 correctly calculates 20,
which is 1. The first argument is the expression power1(2, 0) == 1, which compares the value
that is returned by power1 (the calculated value of 20) to the expected result, 1. This test fails
unless the value returned by power1(2, 0) equals 1; in other words, the test passes only if the
value returned by power1 is correct.
After sput_fail_unless returns, printf is called to display the value that we expect a correct
implementation of power1 to return (that is, 1), followed by the actual value returned by the
function.
The next three pairs of sput_fail_unless/printf calls check if power1 correctly calculates
21, 22 and 23.
Execute the project. The test harness runs, and in the TERMINAL tab you will see the output
from the test harness. It will be similar to this:
Running test harness for SYSC 2006 Lab 3, Part 1
As we review the output, we see that all four checks in test_power1 failed; in other words, the
conditions in all four sput_fail_unless calls are false. Specifically,
Step 6: Trace the code in power1 (in file power.c) "by hand", step by step. Identify the incorrect
statement or statements that cause power1 to return 0 instead of the correct power of 2. Edit
power1 to correct the flaw. Do not add any additional local variables to the function; they are
not needed.
Build and execute the project. The test harness will run.
After you have corrected power1, the output displayed by the test harness should look like this:
If any of the checks in suite #1 fail, repeat this step until all checks pass. When all checks in suite
#1 pass, the harness will also run test suite #2, which tests power2. Some of the checks in suite
#2 will fail.
Step 7: Review the console output from suite #2. Use this output to help you determine the flaw
in power2. Correct the flaw. Do not add any additional local variables to the function; they
are not needed.
Build and execute the project. Review the console output and determine if your function passes all
the tests in test suite #2. If any of the checks fail, repeat this step until all checks pass. When all
checks in suite #2 pass, the harness will also run test suite #3, which tests power3. Some of the
checks in suite #3 will fail.
3
SYSC 2006: Foundations of Imperative Programming
Step 8: Use the output from test suite #3 to help you determine the flaw in power3. Correct the
flaw. Do not add any additional local variables to the function; they are not needed.
Build and execute the project. When all checks in suite #3 pass, the harness will also run test suite
#4, which tests power4. Some of the checks in suite #4 will fail.
Step 9: Use the output from test suite #4 to help you determine the flaw in power4. Correct the
flaw. Do not add any additional local variables to the function; they are not needed.
Build and execute the project. When all checks in suite #4 pass, the summary output by the test
harness will look like this:
==> 16 check(s) in 4 suite(s) finished after 0.00 second(s),
16 succeeded, 0 failed (0.00%)
[SUCCESS]
Notice that we did not assign the value computed by this expression:
acos(-1.0) * r * r
to a local variable and return that variable. The function is more concise if the return statement
contains the expression.
Here is a function that calculates the distance between two points (x1, y1) and (x2, y2):
/* Return the distance between points (x1, y1) and (x2, y2). */
double distance(int x1, int y1, int x2, int y2)
{
int dx = x2 - x1;
int dy = y2 - y1;
return sqrt(dx * dx + dy * dy);
}
The function body could be written as a single return statement, but by using local variables dx
and dy, we do not have to compute the differences x2 - x1 and y2 - y1 twice.
4
SYSC 2006: Foundations of Imperative Programming
Now suppose you are asked to write a function that takes two points, the center of a disk and a
point on the perimeter, and returns the area of the disk:
/* Return the area of a disk with center point (xc, yc) and
* a point on the perimeter (xp, yp).
*/
double area_of_disk(int xc, int yc, int xp, int yp)
First, we calculate the radius of the disk, which is the distance between the two points. To do this,
we call function distance:
Next, we calculate the area of a circle with that radius. To do that, we will call area_of_circle:
Recall that a function call that returns a value, such as distance(xc, yc, xp, yp) or
area_of_circle(radius), is an expression. The arguments of a function call are expressions,
so arguments can be function calls. While local variables like radius and area may be useful
when debugging, we can revise area_of_disk, making it more concise, by eliminating the local
variables and composing the function calls:
/* Return the area of a disk with center point (xc, yc) and
* a point on the perimeter (xp, yp).
*/
double area_of_disk(int xc, int yc, int xp, int yp)
{
return area_of_circle(distance(xc, yc, xp, yp));
}
5
SYSC 2006: Foundations of Imperative Programming
You must format your C code so that it adheres to one of two commonly-used conventions for
indenting blocks of code and placing braces (K&R style or BSD/Allman style). VS Code makes it
easy to do this. (Instructions for formatting the code are in VS Code installation instructions.)
Finish each exercise (i.e., write the function and verify that it passes all of its tests) before you
move on to the next one. Do not leave testing until after you have written all the functions.
Getting Started
Finish the definition of this function. Your function should assume that n is 0 or positive; i.e., it
should not verify that n is ≥ 0 before calculating n!.
Aside: for C compilers that use 32-bit integers, the largest value of type int is 231 - 1. Because the
return type of factorial is int and n! grows rapidly as n increases, this function will be unable
to calculate factorials greater than 15!
Run the project. Use the console output to help you identify and correct any flaws. Verify that your
function passes all the tests in test suite #1 before you start Exercise 2.
Exercise 2
Your function should not be recursive. Repeated actions must be implemented using C's while,
for, or do-while loop structures.
Suppose we have a set of n distinct objects. There are n! ways of ordering or arranging n objects,
so we say that there are n! permutations of a set of n objects. For example, there are 2! = 2
permutations of {1, 2}: {1, 2} and {2, 1}.
If we have a set of n objects, there are n! ⁄ (n − k)! different ways to select an ordered subset
containing k of the objects. That is, the number of different ordered subsets, each containing k
objects taken from a set of n objects, is given by:
n! ⁄ (n − k)!
For example, suppose we have the set {1, 2, 3, 4} and want an ordered subset containing 2 integers
selected from this set. There are 4! / (4 - 2)! = 12 ways to do this: {1, 2}, {1, 3}, {1, 4}, {2, 1}, {2,
3}, {2, 4}, {3, 1}, {3, 2}, {3, 4}, {4, 1}, {4, 2} and {4, 3}.
An incomplete implementation of a function named ordered_subsets is provided in
composition.c. This function has two integer parameters, n and k, and has return type int. This
function returns the number of ways an ordered subset containing k objects can be obtained from
a set of n objects.
Finish the definition of this function. Your function should assume that n and k are positive and
that n >= k; i.e., the function should not check if n and k are negative values, or compare n and
k.
For each factorial calculation that’s required, your ordered_subsets function must call the
factorial function you wrote in Exercise 1. In other words, do not copy/paste code from
factorial into ordered_subsets. Do not declare any local variables in your
ordered_subsets function. There is no need to store the values returned by factorial in
local variables.
Run the project. Use the console output to help you identify and correct any flaws. Verify that your
function passes all the tests in test suite #2 before you start Exercise 3.
7
SYSC 2006: Foundations of Imperative Programming
Exercise 3
Your function should not be recursive. Repeated actions must be implemented using C's while,
for, or do-while loop structures.
Combinations are not concerned with order. Given a set of n distinct objects, there is only one
combination containing all n objects.
If we have a set of n objects, there are n! ⁄ ((k!)(n − k)!) different ways to select k unordered
objects from the set. That is, the number of combinations of k objects that can be chosen from a
set of n objects is:
n! ⁄ ((k!)(n − k)!)
Finish the definition of this function. Your function should assume that n and k are positive and
that n >= k; i.e., the function should not check if n and k are negative, or compare n and k.
Your binomial function must call your ordered_subsets and factorial functions. Do not
declare any local variables in your binomial function. There is no need to store the values
returned by factorial and ordered_subsets in local variables.
Run the project. Use the console output to help you identify and correct any flaws. Verify that your
function passes all the tests in test suite #3.
Exercise 4
If n < 10, it has one digit, which is n. Otherwise, it has one more digit than the integer n / 10. For
example, 7 has one digit. 63 has two digits, which is one more digit than 63 / 10 (which is 6). 492
has three digits, which is one more digit than 492 / 10, which is 49.
Define a recursive formulation for num_digits. You'll need a formula for the recursive case and
a formula for the stopping (base) case. Using this formulation, implement num_digits as a
recursive function. (Recall that, in C, if a and b are values of type int, a / b yields an int, and
8
SYSC 2006: Foundations of Imperative Programming
a % b yields the integer remainder when a is divided by b.) For full marks, your num_digits
function must not have any loops.
Run the project. Use the console output to help you identify and correct any flaws. Verify that your
function passes all the tests in test suite #4.
The TAs will verify that your function is recursive.
Exercise 5
x0 = 1
Implement power2 as a recursive function, using the recursive formulation provided above. For
full marks, your power2 function must not have any loops, and it must not call the pow function
in the C standard library or the power function you wrote for Exercise 1.
Run the project. If you translated the recursive formulation into C correctly, you will find that your
power2 function performs recursive calls "forever". Add the following statement at the start of
your function, to print the values of its parameters each time it is called:
printf("x = %.1f, n = %d\n", x, n);
The information displayed on the console should help you figure out what is going on. Hint: What
happens when parameter n equals 2; i.e., when you call power2 to square a value? Drawing some
memory diagrams may help!
x0 = 1
Change your power2 function to use the revised formulation. Are there any other changes you can
9
SYSC 2006: Foundations of Imperative Programming
make that will reduce the number of times that power2 is called recursively?
Use the console output to help you identify and correct any flaws. Verify that your function passes
all the tests in test suite #5.
The TAs will verify that your function is recursive.
Some exercises were adapted from problems by Frank Carrano, Paul Helman and Robert Veroff,
and Cay Horstmann
Wrap-up
Submit power.c, composition.c and recursion.c to Brightspace. Make sure they have been
formatted to use K&R style or BSD/Allman style, as explained in Part 2, General Requirements.
Ensure that you submit the version of the file containing your solutions and not the unmodified
file you downloaded from Brightspace!
Make sure that the code you submit can be opened, compiled, and run in the VS Code IDE.
Ensure that your code does not use any non-standard C extensions or libraries. If your code does
not compile and run, you will receive 0 for that submission.
We recommend that, after submitting source code files, you download the files from Brightspace
and verify that:
● the downloaded files have the correct filenames;
● the files can be opened and viewed in the IDE's editor;
● no syntax errors are reported when the code is compiled.
Once you have submitted your files, you must demo your work to the TAs for grades before
leaving your lab session.
Remember that your mark will be 0 if the TA did not check your work in the lab or your
submission was not on the system when the TA checked your work. No exceptions!
Note (applicable for all labs): It is your responsibility to keep track of the TA who graded
your work and to check that your grade is on Brightspace. If the grade is not on Brightspace
one day after you demo the work to the TA, contact the TA who graded your lab. Requests made
after the end of your next lab session (i.e., lab 4 session in this case) will not be considered
Solutions that are emailed to your instructor or a TA will not be graded, even if they are emailed
before the deadline.
10