Handy References:
Lab 2 Goals:
- Use git to clone a repository and share code with your partner.
- Practice with C programming basics: declaring variables, types, arrays, and
functions.
- Writing C code and functions that uses statically declared arrays.
- Practice writing and using C functions. Pass by value: basic types and
array parameters.
- C I/O: scanf, printf, and using a simplified file reading library.
- More practice with top-down design.
- Using a Makefile.
Partner Etiquette
For lab assignments when you are working with a partner you should
follow these guidelines:
- The expectation is that you and your partner are working together side by
side in the lab for most, if not all, of the time you work on partnered lab
assignments.
- You and your partner should work on all aspects of the project together:
initial top-down design, incremental testing and debugging, and final testing
and code review.
- If you are pair programming, where one of you types and one of you
watches and assists, then you should swap roles periodically, taking turns
doing each part.
- There may be short periods of time where you each go off and implement
some small part independently. However, you should frequently come back
together, talk through your changes, push and pull each other's code from the
git repository, and test your merged code together.
- You should not delete or significantly alter code written by your partner
when he or she is not present. If there is a problem in the code, then meet
together to resolve it.
- If there is any issue with the partnership, contact the professor.
Taking time to design a plan for your solution together and doing
incremental implementation and testing together may seem inefficient, but in
the long run it will save you time. By working together it is less
likely that you have design or logic errors in your solution, and you will more
easily be able to track down and correct bugs.
Partnerships where partners work mostly independently rarely work out well
and rarely result in complete, correct and robust solutions. Partnerships where
partners work side-by-side for all or most of the time tend to work out very
well. You and your partner are both equally responsible for initiating
scheduling times when you can meet to work together, and for making time
available in your schedule for working together.
Lab Outline
You will implement program that sorts floating point numbers using a sorting
algorithm of your choice in C. Your program will read a collection of unsorted
floats from a file, store those floats in an array, provide some information
about the floats to the user, sort them from smallest magnitude to largest
magnitude (i.e., ascending order), and print them out in sorted form to the
user.
Lab 2 Starting Point Code
If you haven't already done so, follow the one-time
configuration instructions on the weekly lab page.
Next, you'll follow our course
git guide to make a local clone of the git repository that you
share with your partner. Our organization's name is CS31-F18, and the
repository you want to use is named Lab2-user1-user2, where user1 and
user2 are the user names of you and your partner.
Cloning the repository will give you the starting point code, which
includes:
- Makefile: A Makefile simplifies the process of compiling your
program. We'll look at these in more detail later in the course. You're
welcome to look over this one, but you shouldn't need to edit it for lab
2.
- readfile.h and readfile.c:These files contain a library for
reading from files. You should make calls to functions in this library in your
program to simplify file I/O. The instructions for using this library are
explained below.
You should not modify any code in these two files.
- sorter.c: the file into which you will add your C solution and
comments. The starting point code includes a helper function for you:
- get_filename_from_commandline: takes the storage space for a
string and the command line arguments and initializes the string storage
space with the filename from the command line argument. You should not
change this function, but feel free to change where it gets called.
- floats.txt, floats2.txt, and floats3.txt: example
input files to your program. These are provided for your convenience to help
you test your program. You will ultimately want to create new test files to
more extensively test your program before you consider it finished.
To compile your program, run make, which will use the Makefile to
build your program (and link in the provided readfile library).
Running make will show you the compiler output, which you should examine for
errors and warnings.
$ make
gcc -g -Wall -c readfile.c
gcc -g -Wall -o sorter sorter.c readfile.o
sorter.c: In function 'main':
sorter.c:23:9: warning: unused variable 'values' [-Wunused-variable]
float values[ARRAYSIZE];
Program Start-up
Your program will take one command line argument: the name of the input file
containing floating point values to sort, one on each line. You should read
these values (using the provided library), sort them, and print out the sorted
result back to the user. Here is an example of how you invoke the program:
$ ./sorter floats.txt
File Format
The input file format consists of several lines of an ASCII text file. A
properly formatted file will contain a short header, consisting of a single
line with one integer and two floats on it. These numbers represent the total
number of floats in the file (i.e., the number of subsequent lines), as well as
the minimum and maximum to-be-sorted float value in the file. These numbers
will be written like this:
For example, here is the header of a valid input file:
4 0.0 9.0
This header indicates that the file contains a total of 4 floats that need
to be sorted. The smallest float value in the file will be 0.0,
and the largest will be 9.0. You may not need to know the minimum and maximum
values to successfully sort the values, but you will need to inform the user
about the range of values being sorted.
Included with the starting point code are a few sample test files you can
use to test your code. Every line after the first line in the file will
contain a single floating point number. These are the float values that must
be sorted. For example, a file containing the header we just saw might look
like this (after the first line):
0.0
2.1
9.0
5.3
File I/O
For this assignment we'll use functions from the provided readfile library
(in the files readfile.c and readfile.h). You should not
change any code in these files. The readfile.h file contains function
prototypes for the readfile library. There are function comments in this file
that describe each function and a high-level comment describes how to use the
library.
Here are the general rules for how to use these functions:
- Open a file by calling: open_file(), passing in the name of the
file to open as a string. The return value of open_file() tells you
whether or not the file was opened successfully. It returns 0 if the file is
successfully opened, and -1 if the file cannot be opened. You should always
check the return value of this function and respond appropriately!
- Call the read_int(), read_string(), read_float()
functions to read values from the file into your program's variables, where
the name of the function you call determines the resulting type of the value
that gets filled in. Like open_file(), these functions return 0 on
success, and you should always check their return value. If you've reached
the end of the file, they will return -1.
These functions take arguments much like scanf does: they need to know
the memory location of where to put the value read in.
For example:
int x;
float f;
char s[20];
...
/* These functions return 0 on success or -1 if read fails or
* if there is nothing left to read (end-of-file has been reached). */
ret = read_float(&f);
ret = read_int(&x)
ret = read_string(s)
- Close the file when you're done with it: close_file().
If you are curious, the implementation of these functions is in
readfile.c. You can take a look and see how it uses the C FILE *
interface and fscanf functions for reading. We will use this interface
directly later in the semester. For now, we're hiding it under a layer of
abstraction!
Requirements
Your output should look like this output
from an example run of a working program. It doesn't show every possible
run or error handling, but should give you some idea of what a correct program
will look like. To make my job of grading easier, please make your output
match the example as closely as possible.
For full credit, your solution should meet the following requirements:
- As in the example above, you program should print the following four items
in a human-readable way:
- The name of the file.
- The header contents of the file (number of values, max/min values).
- The values in their original, unsorted order.
- The values in sorted order, from smallest to largest.
- You should store the set of floating point values only once (e.g., keep
only one array, don't copy all the values to a second array.) You may assume
that there will never be more than 100 values to sort, and you can use any
sorting algorithm you like, it doesn't need to be fancy. You should not
attempt to use merge sort, as we haven't yet discussed all the C functionality
that you'll need to implement it.
- Your program should exit gracefully if you detect an error that's not your
code's fault (for example, if it was given the name of an invalid input file).
Be sure to check those return values!
- It should be evident that you applied top-down design when constructing
your submission. In addition to main(), you should have at least
two non-trivial functions, each with a specific role. (See the
Implementation Recommendations section below for suggestions.)
- Your code should be commented, modular, robust, and use meaningful variable
and function names. Each function should include a brief description of its behavior.
- Your program should not use global variables. If a function needs a value
from its caller, then that value should be passed in as a parameter. If a
function needs to store variables, then those should be declared as local
variables inside the function. If you don't know what a global variable is, no
problem, you won't make the mistake of using one!
- Your code should compile cleanly with no errors or warnings and should not
crash unexpectedly during execution.
Implementation Recommendations
The following is the suggested way to implement the lab and fulfill the
requirements. If you intend to significantly deviate from this design, please
let me know so that I can do a basic sanity check of your proposed changes.
- Store the floating point values in an array of C float types.
- Write a function that knows how to print the contents of an array of
floating point values. You'll use this twice: once to print the original
unsorted values, and later, to print the sorted values.
- Write a sort function that takes in an array of floating point values (and
the size of the array), sorting the array values such that the original array
is in sorted order after the call completes.
Tips
- Before even starting to write code, use top-down design to break your
program into manageable functionality.
- Test your code in small increments. It's much easier to localize a bug
when you've only changed a few lines.
- Many of the functions that you'll write to deal with arrays will need to
know the size (length) of the array. Unlike Python, C does NOT keep that
information around (there is no len() function). If a function needs
to know the array length, you should probably make that a parameter to the
function.
- When printing floating point values, you can make the output more readable
by limiting the number of digits that get printed after the decimal point. For
example, using %.2f in the format string for printf() will
limit the printed float to two digits after the decimal.
- For values that will never change in your program, you can compile in
constants using #defines.
- Use CNTRL-C to kill a running program stuck in an infinite
loop.
- Post on Piazza, attend ninja sessions, and/or come to office hours if you
have questions!
Submitting
Please remove any debugging output prior to submitting.
To submit your code, simply commit your changes locally using git
add and git commit. Then run git push while in your lab
directory. Only one partner needs to run the final push, but make sure both
partners have pulled and merged each others changes. See the section on Using a shared repo on the git help
page.