Edits / Updates:

Goals for this homework

  • Practice the C development cycle
  • Write a small C program to get used to the syntax.
  • Write programs that exercise functions and printing.

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.).

Also, this assignment is shorter than most assignments because it is due so early, not allowing us to cover material that would lead to a more substantive assignment. In addition, some subset of the class will have trouble with logistics. If your logistics went smoothly, don't take the time required for this assignment as the normal weekly time investment for the quarter.

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 11:59pm prior to your next lab session.

You should submit two files for this assignment (hw1.c and Makefile), in addition to ones from your warm-up, in your subversion repository as directed below. Your subversion repository is named CNET-cs152-win-20, and you can check it out with the following command:

  $ svn checkout https://phoenixforge.cs.uchicago.edu/svn/CNET-cs152-win-20 
(where CNET is your cnetid). 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.

printf

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);

For this assignment, you'll also need to control the spacing of your printing. Here is a website that provides a reference in how to format with printf.

Error Handling

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.

Types

The homework exercises follow. We use the type int for integers (except, in certain cases made explicit below, unsigned int), double for floating-point numbers (i.e., non-integers), and int for Booleans (noting that C has no Boolean type).

Makefile

Because you are adding a second file to your directory, you need to add a second target to your Makefile. In your makefile, add another two lines (with a space between these and the ones already there).
hw1: hw1.c 
	clang -Wall -o hw1 hw1.c 
To compile, type:
$ make hw1 

To run, type:
$ ./hw1 

Set Up - Skeleton project

The first thing to do is to create a skeleton project that will minimally execute. This week, I provided it for you. In the future, you will be expected to create it for yourself. Let's imagine that this homework only required a single function, surface_area_cylinder. Then your skeleton would be the following:
  • Step 1: Create hw1.c. For each function, it must do a few things.
    1. Have the right signature - return type, name, inputs
    2. Print to stderr the fact that it is not yet implemented
    3. Return somethingwith the right type.

    For example:
    
    {
    	fprintf(stderr,"surface_area_cylinder not yet implemented\n");
    	return 0.0;
    }
    
  • Step 2: Create a main function. For each function, put in a single function call. For example:
    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.

Exercise 1: Calculations

This exercise asks you to write functions that calculate results and return them (do not print anything out in the function). Be especially careful about the type of the variables and the order of operations.

double convert_length(double centimeters)

Write a function that takes in a number of centimeters and converts that to a number of inches.

Use 0.3937 as the conversion multiplier

This function does not print out the result. It returns the result. If you do not understand the distinction, please ask.

All non-negative values are valid. Make sure you check for validity and print out an appropriate error message is you find one, as described previously. Do not exit. Return the value -1 for any negative input.

double trapezoid_area(unsigned int height, unsigned int base1, unsigned int base2)

Write a function that calculates the area (not surface area, but internal area) of a 2-d trapezoid. Two lines are parallel and of length base1 and base2. These two lines are height apart.

Any non-zero values are valid. If the user enters a 0 for any of the three values, print out an error message as previously described. Make sure you do not exit the program in the event of an error. Return 0 if the user enters a 0 for any of the inputs.

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!

Exercise 2: Printing

This exercise pertains to printing. You are going to print out a triangle of numbers, created the way Pascal's Triangle is created. You need to print out only 5 rows, which is necessary to be able to implement this with only the information you have learned in this class so far. See this example for clarification.

void print_number_triangle(unsigned int start_num);

Some details:
  • Input number is always first row
  • Numbers are right-justified (ones places are all lined up vertically if they are in the same column)
  • The input is always positive - you do not need to check for this.
  • Spacing for where to begin is determined by tabs. Each layer of the triangle is tabbed in one more than the one below it.
  • There is a carriage return immediately following the last number in each row
  • No loops are necessary for this, but if you already know them, you may use them. We will not provide help with loops (since it will be covered after the assignment is due).
  • You need to support printing up to 3 digits. Anything larger is an error. Do not print out the triangle. Instead, print out:
    ERROR (print_number_triangle): Numbers larger than 3 digits not supported
    Remember, as described above, to use fprintf rather than printf and send the output to stderr. Do not exit


Don't forget to complete this portion, test it, and commit it before moving on!

Submit

At this point, for hw1, you should have done the following:
  • Created one new file and filled in the proper information: hw1.c.
  • Added the new executable hw1 to your Makefile.
  • $ svn add hw1.c 
    
  • Implemented all of your functions.
  • Compiled your executable manually and with the Makefile
  • Implemented your test cases
  • Executed your code
  • Debugged your code
  • Submitted your code:
    $ svn commit -m "hw1 complete"