You are expected to complete this assignment individually. If you need help, you are invited to come to office hours and/or ask questions on piazza. Clarification questions about the assignments may be asked publicly. Once you have specific bugs related to your code, make the posts private.
Another note about Piazza. Piazza is your community resource - please use those as discussions amongst yourselves. We are not monitoring it all day, rather we each have check-in times once a day. Therefore, you need to start early enough to wait for feedback and/or build a vibrant, supportive community that helps each other while we are completing other necessary tasks (research, developing assignments, preparing for lecture, performing advising tasks, etc.).
Make sure you filled out the Student Information Form
This homework has several exercises. We are also providing you with some resources on printf and error handling for this assignment.Homework 1, which includes warmup 1, will be collected from your subversion repository at 5:00pm on Wednesday, just prior to your next lab session.
You should submit four files for this assignment (hw1.h, hw1.c, hw1_main.c, and Makefile), in addition to ones from your warm-up (functions.c, main.c, functions.h, errors.txt), in your subversion repository as directed below. Your subversion repository is named CNET-cs152-win-18 and you can check it out with the following command:
$ svn checkout https://phoenixforge.cs.uchicago.edu/svn/CNET-cs152-win-18(where CNET is your cnet). Do not commit any executable, a.out or any other, to your repository; we will (in fact, must) recompile your code on our own machines on our end.
The printf() function takes a string as its first argument. The contents of this string are printed to the screen as-is, but with the same kinds of escape conventions as we saw in Racket (e.g., \n is the newline character). The function can be used with a string and no other parameters:
printf("Hello, world!\n");
If you want to include a representation of the value of one or more expression in the string printed by printf, you need to include one or more format codes in printf's string argument, and you need to pass correspondingly many expressions as additional arguments to printf, separated by commas. Some examples follow.
Format codes begin with the character % and the next character(s) specify the type of the value to be printed. For now, it suffices to know that d specifies an int, and lf specifies a double. To be clear, put together, we write %d as a placeholder when we want to write an int, %ld for a long int, and %lf for a double.
For example,
printf("The number is %d.\n", 42);
prints this:
The number is 42.
If we want more than one expression included in the same string, we use multiple format codes and pass arguments in lockstep with those codes:
int ndigits = 6;
double approx_pi = 3.14159;
printf("Pi to %d digits is %lf, and pi squared is %lf\n",
ndigits, approx_pi, approx_pi * approx_pi);
Error handling capabilities vary by language, and what you want to do in an error varies by the situation. When an error occurs in a function, the question becomes, what should you do, and how do you notify the caller that an error occurred?
In C, there is no good way to distinguish error conditions from normal execution. This is unfortunate because if you write a function, and it's used in a variety of different circumstances, it is bad programming practice to determine within the function what will be done. For example, one program might want to exit, whereas another might want to notify the user that there was bad input and to try again.
In this course, we will print the error message in a special way (see below). If there is an opportunity, we will designate a specific return value for an error condition. If there is no available return value, then we will exit from within the function.
When we print error messages, it is helpful and appropriate for them to be routed through a special error mechanism. This gives them priority, increases their likelihood of being printed in the case of a program crash, and allows them to be separated from other output. To accomplish this, we use a variant of printf called fprintf. This function works the same as printf, but takes in an extra argument at the beginning: the "file" to which to write the message. Passing in stderr as that argument will send the output to the screen, but using the special error mechanism:
fprintf(stderr, "error: too many widgets for the number of grommets\n"); fprintf(stderr, "error: need ten boondoggles, but only have %d\n", num_bds);
Sometimes, these lines will be followed by exit(1); This immediately exits the program and returns a code. If you were writing a large program, you might assign a different code to each type of error that would result in an exit.
hw1: hw1.h hw1.c hw1_main.c clang -Wall -o hw1 hw1.c hw1_main.cTo compile, type:
$ make hw1
double surface_area_cylinder(double height, double radius);
double surface_area_cylinder(double height, double radius)
{
fprintf(stderr,"surface_area_cylinder not yet implemented\n");
return 0.0;
}
int main()
{
double dval;
dval = surface_area_cylinder(2,1.5);
}
First get this compiling and running. It won't print out anything, but this will mean that your code will compile and execute with our infrastructure. This must work in order to get any points in this course. Do this first, not last.
This exercise pertains to geometric shapes. You are going to write two functions, in increasing difficulty (from a programming perspective). You may use the math library to calculate square root. To use the math library, you must both add #include <math.h> to your program and place -lm on the compile line (with clang).
double surface_area_pyramid(double edge_length);
Write a function that calculates the surface area of a pyramid. Each side is length edge_length. Once you have written the calculation in code, make sure you also identify what values of edge_length would not be valid.
double sides_to_surface_area(int num_sides, double side_length);
Write a function that calculates the surface area of a 3-d shape with all equal-length sides and faces. Support pyramid, cube, and regular dodecahedron.
For both functions, if the user enters an invalid input, print out an error with the format "error (function_name): [description of error]". Remember, as described above, to use fprintf rather than printf and send the output to stderr. Return -1.0 to indicate that an invalid input was received. Do not exit.
Don't forget to complete this portion, test it, and commit it before moving on! This means you need to write a test function and develop a suite of test cases!In this exercise, you will implement an exponent function two different ways. First, you will implement the naive implementation - to raise the number a to the nth power, simply perform n multiplications. Next, you will use a method that reduces the number of multiplications you need to perform. That technique is described below.
For both of these functions, you must solve them recursively. Do not use a loop. You may not use the math library.
Write a function expt to compute through simple multiplications of a. Its header should be
long int expt(int a, unsigned int n)
b = a*a (a^2)
c = b*a (a^3)
d = c*a (a^4)
With successive squaring, two multiplications suffice:
b = a*a (a^2)
c = b*b (a^2)
To raise a number to the eighth power, with successive squaring, three multiplications suffice:
b=a*a (a^2)
c=b*b (a^4)
d=c*c (a^8)
Let's consider a power that is not one of the powers of 2. To compute a^9, four multiplications suffice, as follows:
b=a*a (a^2)
c=b*b (a^4)
d=c*c (a^8)
e=d*a (a^9)
In general, for integer a and natural number n, we compute a^n with successive squaring according to the following recursive algorithm:
if n is 0, a^n = 1
if n>0 and n is even, a^n = (a^(n/2))^2
if n>0 and n is odd, a^n = a*(a^(n-1))
Implement exponentiation by successive squaring as a function with the following header:
long int ss(int a, unsigned int n)
Note that == is the testing operator for integer equality. % is the "mod" operator and gives the remainder when the first operand is divided by the second. For example, 5%2 is 1 and 6%2 is 0.
Also, take care that recursive calls within ss are calls to ss itself, not to any other function.
$ svn add hw1.h hw1.c hw1_main.c
$ svn commit -m "hw1 complete"