CS140 -- Lab 7

Brad Vander Zanden

This lab will give you practice:

  1. using doubly linked lists,
  2. using lists of lists,
  3. writing programs to test library code,
  4. figuring out potential error conditions, and
  5. writing a design document. Before you start this lab, you will need to create and submit a design document to the TA. The last section of this lab write-up describes what your design document should contain.


You will need the following files:

Part 1 -- Completing the Dllist Library

As described in the class notes and in lecture, you need to write the following four functions to complete dllist.c:

  1. dll_insert_after
  2. dll_prepend
  3. dll_append
  4. dll_delete
If you forget what these functions do or want some hints on how to implement them, consult the dllist notes.

Part 2 -- Testing Your Dllist Library

When you write a library, like dllist, that will be used in multiple applications, you should try to thoroughly test it before you release it. One way to test your library is to write a driver application that tests all the different functions in your library. You are going to write a driver program named photo_sorter.c to test your dllist library.

photo_sorter is going to mimic an imaginary photo album in which you are arranging the photos. Each photo is going to be identified by a single word, and your driver program is going to accept a number of commands for arranging the photos:

  1. append photo_name: appends the named photo to the end of the list.
  2. prepend photo_name: prepends the named photo to the beginning of the list.
  3. after photo1 photo2: inserts photo2 after photo1 in the list.
  4. before photo1 photo2: inserts photo2 before photo1 in the list.
  5. delete photo_name: delete the named photo from the list.
An example set of commands might be:
append brad
append smiley
append fred
prepend joe
prepend yifan
after yifan ebber
before brad huck
before yifan bounce
delete joe
delete fred
after yifan wolf
Do not worry about duplicate photo names. If a duplicate occurs, you should find the first photo with that name in the list and have the command act on that photo.


valid command: After each valid command your program should print a list header and then the contents of the list, one photo per line. The list header should consist of:

  1. the command number
  2. a ":"
  3. a space
  4. the header "Photo List"
For example, after the first six commands above (ending with "after yifan ebber"), your output would be:
6: Photo List
invalid command: After an invalid command you should print an appropriate error message, prefixed with the command number. If you experiment with my executable, you can see the error messages that I used.

line spacing: There should be a single blank line after each list or error message.


Your program should:

  1. create a dllist and an inputstruct to read from stdin,
  2. read commands from stdin until EOF is received. Your program should perform the appropriate action for each command. If the command is a valid one, it should then iterate through the list and print the names of the photos one per line. Remember to print the list header before you print the list. You can use the inputstruct's line field as the command number, since there is one command per line, and therefore the line number is the same as the command number. If the command is invalid, you should print an error message and continue.

You will need to include your dllist.o object file in the list of files you use to build your photo_sorter executable.

When I was designing my solution to this problem, my strategy for incremental development was to initially assume that the commands were always correct, and to add error checking only after I had the commands working properly. I then divided the commands into ones which were easy to implement, namely prepend and append, and the ones which would be more difficult to implement, namely after, before, and delete. I implemented the easier ones first, then the more difficult ones. The reason prepend and append are easy is that you can simply call dll_prepend and dll_append to implement them. In contrast, the remaining three commands require that you traverse the list to find a target node, and then do something with that target node (insert before it, insert after it, or delete it). Here is the rough set of steps I used to solve the problem. These are the steps that I would put in a design document.

  1. create a dllist and an inputstruct to read from stdin.
  2. create the code to implement the prepend command.
  3. create the code to traverse the list and print its contents. I could now call this print function after executing each of my commands, and specifically I could now check to see that prepend was working properly.
  4. create the code to implement the append command. Check it first using only append commands, then mix in prepend commands.
  5. create the code to test the delete command. This is the next easiest command because it requires the least work. I traverse the list to try to find the indicated photo and call dll_delete when I find the node that contains it. I put the code for finding the target node in a function called find_node, because I knew I would use it again with the before and after commands. To test my code I did a few prepends, then a few deletes, and then I mixed in prepends, appends, and deletes.
  6. create the code to test the after command. I called the find_node function that I wrote to support the delete command, and then used dll_insert_after to insert after the target node. First I tested the code with a single append, followed by a bunch of after commands, then mixed in the previously implemented commands.
  7. create the code to test the before command. I basically cut and pasted the after code, but called dll_insert_before. I tested the code with a single append, followed by a bunch of before commands, then mixed in the previously implemented commands.
  8. I now figured out the possible error conditions and implemented code to implement each one. I typically tested immediately after each new error condition to make sure it worked, before going on to the next one.

Notice that I did a great deal of incremental development and testing. If I tried to write the whole program at once, it would have been much more difficult to track down errors when they occurred.

Part 3 -- linenum

In the last lab you wrote a program called linenum that takes a filename and an arbitrary number of words from the command line and then prints the line numbers from the file on which each of these words appears. In this lab you will modify linenum so that for each unique word in the file, it prints the line numbers on which that word appears. You will need to print out the words in alphabetical order, and so you will want to use dllists for this lab, rather than the sllists you used in the previous lab.

Here are the program requirements:

  1. You must use the fields library to read each line of input.
  2. Each line of output should consist of a word and then the line numbers on which it appears.
  3. Line numbers should not be duplicated.
  4. The words should be printed in ascending alphabetical order. For example, if the file ice_cream contains the lines:
    ice cream is nice
    but chocolate ice
    cream is dandy
    then the output of the command
    <UNIX> linenum ice_cream
    will be
    but           2
    chocolate     2
    cream         1    3
    dandy         3
    ice           1    2
    is            1    3
    nice          1

Format of the Output

Your output should be formatted as follows:

Implementation Advice

Like the previous lab, you can still use lists to store the line numbers on which a word appears. If you want, you can continue to use sllists for storing line numbers, or you can convert them to dllists if you wish. You can use the same trick of malloc'ing space for an integer, storing the integer in that space, and passing a pointer to that integer to the list's append function. Unlike the previous lab you can no longer use an array to store the words because 1) you do not know how many words are in the file, and 2) you will need to insert new words in alphabetical order, which means that you will need to insert into the middle of your set of words. Hence you will need to use a dllist to keep track of your words. For each word you will need a struct that has two fields, one to store a pointer to the word and one to store a pointer to the line number dllist for that word. For each word in the file you should search the word list to see if the word is already on the word list. If it is, then you will need to add the line number to the end of the word's line number list, unless that line number is already on the word's line number list. If the word is not on the word list, then you will need to traverse the word list to find where the word should appear in alphabetical order, and then insert the word into the word list list. You should then add its line number as the first element of the word's line number list.

Design Document

Starting with this lab, we will be asking you to identify the error and boundary conditions for which you should test in your design document. Once the design documents have been collected, we will tell you the list of errors and boundar conditions we wish you to check for. You can use my executables to determine the error messages that get printed for each type of error.

Your design document for this lab will consist of two parts, one for photo_sorter and one for line_num.

Part 1 -- photo_sorter

For photo_sorter your design document should enumerate the list of potential error and boundary conditions for which you should test.

Part 2 -- linenum

For line_num you should:

  1. draw a picture of what your data structures might look like for the file ice_cream. It is okay to embed data like words or line numbers in your nodes.
  2. enumerate the list of potential error conditions and boundary conditions for which you should test.
  3. write down pseudo-code or a list of the high-level steps that your solution will entail. The design document that Thomas Hooper gave you for lab 4 is one version of a high-level list of steps to perform.

What to Submit

You will submit your design document in the lab when the TA calls for it. Submit the following source files:

  1. dllist.c
  2. photo_sorter.c
  3. linenum.c