This assignment does not require the use of classes. Classes will be covered in project 3.
The original version of this assignment involved developing a program that edits a file of NCAA football teams. However, in order to make the assignment more interesting and personal, I am going to ask each of you to choose his/her own "topic" for the assignment.
You will be writing a menu-driven program that manipulates a file of data related to a given topic. You'll be able to add, delete and lookup items in that list, as well as read the list from a file, and write the list to a file.
In this part of the project, your job is to understand the big picture of what you are trying to accomplish, choose a topic, and post some general information about that topic on the web. I have put together sample scripts of a completed project involving the topic "NCAA teams." Your job is to review some sample output so that you know what you are aiming to accomplish.
The program provides the user with a menu of options for maniuplating the file. The menu allows the user to
You will develop the program as a menu driven program, and you are strongly encouraged to develop it in seven stages. (In fact, when I wrote the program, I wrote it in exactly the stages that I am recommending to you. It took me 3.5 hours to write it from start to finish, so I strongly encourage you not to wait until the day before to start, but rather, to start now, and try to do one stage per day until you are finished. If you keep pace with me, you can do each stage in about 30 minutes; more likely, it may take you a couple of hours for each stage.
So that you can get an idea of what the program is supposed to do, I have put an example script file for each stage in the following directory on strauss:
/www/htdocs/CIS/181/pconrad/06S/work/proj/proj2/sampleScriptswhich can be found on the following web link:
http://www.udel.edu/CIS/181/pconrad/06S/work/proj/proj2/sampleScripts
There is also some sample code in the directory:
/www/htdocs/CIS/181/pconrad/06S/work/proj/proj2/structExamplewhich can be found on the following web link:
http://www.udel.edu/CIS/181/pconrad/06S/work/proj/proj2/structExample
To finish part 0 of the project, you are going to describe a table of data related to the "topic" that you have chosen. Rather than give a detailed description of what I'm looking for, it is probably more effective to just show you several examples first.
Here are a few example tables for various topics. What you need in each case is at least two "fields" (i.e. two columns) that contain character array data, at least one with integer numberic data, and at least one with floating-point numeric data.
Pizzas with Side Salads (as in the inputExamples programs)
pizzaTopping | numPizzas | priceOfPizzaInDollars | saladDressing |
---|---|---|---|
cheese | 2 | 4.99 | ranch |
mushroom | 1 | 5.99 | italian |
green peppers | 3 | 5.99 | blue cheese |
onions | 1 | 4.99 | thousand island |
Hiking Trails
nameOfTrail | park | length | state | timesHiked |
---|---|---|---|---|
South Kaibab | Grand Canyon NP | 6.3 | AZ | 1 |
Hidden Pond | Brandywine Creek SP | 2 | DE | 4 |
Bright Angel | Grand Canyon NP | 9.3 | AZ | 1 |
Kelly's Run | Holtwood Recreation Area | 4 | PA | 1 |
Once you've come up with the "columns" for your table, and at least three sample "rows" for your table, you are ready to do the part that you are going to submit for credit.
The first thing you need to do is register your topic on WebCT. So log on to WebCT, go to the CISC 181 honors page, click on Discussions, and go to Project 2 topic registration. FIRST make sure no one else is doing your topic, and then submit a post where you briefly state what your topic is (e.g. "Pizza and Salad orders"). Now you have reserved your topic and are ready to begin the project
First, use the mkdir command to make a new subdirectory under your cisc181 homepage called
"proj2". The path of this directory will be something like ~/public_html/cisc181/proj2
.
Next, go to your cisc181 homepage html file and make a link to this new directory with something like <a href=proj2>Project 2 files</a>
Now make a new file in the proj2 directory called "proj2data.txt". Inside the file proj2data.txt, you want to document the columns in your table. Here are a couple of examples. The way I've formatted things here isn't the "only" way or the "right" way—this is a file written in English, not computer code, and it will be read by human beings, not a computer program. So format things however you like, as long as the way you write it is clear.
When you are finished writing up your proj2data.txt file, use a web browser and see if you can access your new file from your cisc181 homepage. If not, you might have to use the chmod command make it readable on the web, something like:
chmod a+x ~
chmod a+rx ~/public_html/proj2
chmod -R a+rx ~/public_html/cisc181
Your TA will grade this file based on what is there after you've submitted the other part of your project.
P. Conrad, cisc181 Section 22, proj2data.txt Topic: Hiking Trails column 1: hiking trail name type of data: character maximum length: 20 can contain blanks: yes column 2: location type of data: character maximum length: 30 can contain blanks: yes column 3: lengthOfTrail type of data: float minimum value: 0 maximum value: 9999.9 units: miles decimal places to show: 1 calculation: show length of trail in km as well. decision: if trail is < 5 miles print short, otherwise print long. column 4: state type of data: character maximum length: 2 can contain blanks: no comments: I'll either avoid trails that are in multiple states, or I'll divide up multi-state trails (such as the Appalachian Trail) into segments, one per state. column 5: timesHiked type of data: int minimum value: 0 maximum value: 9999 |
P. Conrad, cisc181 Section 22, proj2data.txt Topic: Supreme Court Justices column 1: justiceName type of data: character maximum length: 30 can contain blanks: yes column 2: appointedBy type of data: character maximum length: 30 can contain blanks: yes column 3: yearAppointed type of data: int minimum value: 1776 maximum value: 9999 units: years column 4: yearBorn type of data: int minimum value: 0 maximum value: 9999 units: years |
P. Conrad, cisc181 Section 22, proj2data.txt Topic: Digital Cameras column 1: brand type of data: character maximum length: 20 can contain blanks: yes column 2: model type of data: character maximum length: 20 can contain blanks: yes column 3: megapixels type of data: float minimum value: 0 maximum value: 99.9 units: megapixels decimal places to show: 1 column 4: price type of data: double minimum value: 0 maximum value: 9999.99 units: dollars notes: print dollars and cents separately, separated by . |
Consult the sample scripts for advice on what to test. You are encouraged to test each stage of the program as you develop, rather than trying to develop the whole thing at once.
At each stage, you should have a working complete program that you could script and turn in for partial credit. However, in the end you should only turn in one program.
It is best to read over the entire assignment before starting to code part 1, so you have some idea of where we are going. But don't let the size or complexity overwhelm you; working step by step, one step per day, you'll have no trouble finishing on time if you start NOW. With that said, let's begin.
For the remainder of the project, the term "record" will refer to
one line of data. For example, for the hiking trails, a record would be one
trail, with the name, the location, the length, the state, and the number of
times hiked. For generality, I will use function names like addRecordToList
.
But you should feel free to change these names to something specific to your
project, for instance addTrailToList
if you did the hiking trails
thing. In fact, changing the names in such a way would make your code easier to
read and understand, and thus would earn you style points. You should
definitely add such changes to any user input/output, e.g. in the menu system.
Main Menu: a: add record to list l: list records q: quit program s: summarize listThe main is therefore very short, and mainly consists of a loop that reads options from the user until the user selects the 'q' option. You can use a switch statement. The default case should print an error message indicating that the option is not supported. Print the menu of options each time through the loop.
Each of these options will call a function that will perform some task. (Even the 'q' option might perform some task before finally quitting.) For example, the 'a' option will call a function called something like:
void addRecordToList(Record **recordListHeadPtr, Record **recordListTailPtr);This function will
Each node in the linked list will be a struct
that you define
to represent a single record. For instance, struct Trail
or, for
this generalization, struct Record
. (Note:
C++ programmers generally capitalize user-defined types such as Trail or Record so that they
can be easily distinguished from variables and functions.)
The linked list will consist of struct Record
nodes.
All the fields of your data record (e.g. cost of pizza, topping, salad dressing)
will be in the stuct in addition to a pointer of type Record* to the next
node, called "next".
You should declare variables in your main program to point to the head and tail of a list of teams, such as the following:
Record *recordListHead; Record *recordListTail;These variables should be local variables to your main program not global variables (a serious deduction (at least 10%) will be made if you use global variables instead.)
You will pass these variables (the ones for head and tail of the record list) into the function readRecordFile
. You should pass these variables by pointer; that is, you will pass the address of these variables,
as follows:
... switch (menuOption) { case 'a': addRecordToList(&recordListHead, &recordListTail); break; ...Inside the function, you should dereference these pointers when assigning values to them. For example, when assigning a value to recordListHead, you should use code such as the following. Note that the name of the variables has "ptr" on the end of it to remind you that inside the function, these variables are not the head and tail of the list, but rather, they point to the head and tail of the list.
void addRecordToList (Record **recordListHeadPtr, Record **recordListTailPtr) { ... Record *p; p = new Record; // allocate a new node // set fields inside p based on values read from user // For example, if one of your fields is a character array called name: char userInput[100]; // To hold the user's input // read in userInput p->name = new char[ x ]; // Replace x with an appropriate value determined from the user input // Use the function strlen, and don't forget about the terminating null character. // set the rest of the fields similarly. You only have to use new to // allocate memory for character array fields. The rest of your fields // should just be simple data types (not arrays), so you can just set those // directly without calling new. if ((*recordListHeadPtr) == NULL) // if first node in list (*recordListHeadPtr) = p; // set the head of the list else (*recordListTailPtr)->next = p; // link new node to end of the list (*recordListTailPtr) = p; // update the tail pointer ... }
Note the use of the new
memory allocation operator above. We
use new to allocate memory that can't really be determined from the start of the
program, such as the number of nodes in the list or the size of the user-input
character arrays for a field. That is why the node above and the character
array field are allocated using new. This means we can essentially have as
many nodes as we want, etc.
However, using new
also means we have to deallocate that memory
manually. We do this with the deallocation operator delete
.
Delete takes a pointer (same thing returned by new) and deallocates the
associated memory chunk on the heap. For this step, you need to make a quit
function that deallocates all the memory that you created using new, prints a
message, and then quits. This function will be accessed with the "q" option
from the menu.
To do this, go through each node in the linked list (starting with the one pointed to by recordListHead), and do the following (in order):
delete currentRecord->nameField;
.delete currentRecord
).So after this step you have four menu options: a (add), q (quit), s (summary), and l (list).
Partial Credit: If this step is as far as you get, it is worth up to 40% partial credit (you start with a grade of 40%, and additional deductions may be taken from there). If you stop here, script this program. Be sure you test all the options that are present at this stage (see the script file p2s1.txt for ideas.
Your script file should also be called p2s1.txt if you stop at this stage.
If you are continuing on with the remaining parts, you do NOT need to submit a script or C++ program for this step.
Add one additional option to the program.
The "f" option "finds" a record in the list. You are required to have two
character array fields in your data type. The search will be on one of these
(e.g. for hiking, probably the name of the trail). Prompt the user for a search
string, then search the list for all teams that match that domain name. To
compare the user-entered c-string with the one in each record, you will have to
use the function strncmp
in the header file called "cstring". For help on how to use this function, type man strncmp
from
strauss, or look it up in your textbook.
Note that it is possible for the list to contain duplicate entries. See the script file p2s2.txt for example output.
Start by making a copy of your p2s1.cc or p2s1.cc program with, for example:
cp
p2s1.cc p2s2.cc
Then add the necessary code to implement the new option.
Partial Credit: If this step is as far as you get, it is worth up to 50% partial credit (you start with a grade of 50%, and additional deductions may be taken from there). If you stop here, script this program. Be sure you test all the options that are present at this stage (see the script file p2s2.txt for ideas.
Your script file should also be called p2s2.txt if you stop at this stage.
If you are continuing on with the remaining parts, you do NOT need to submit a script or C++ program for this step.
Add one additional option to the program:
The "d" option deletes a team from the list. It will prompt the user to enter a search string (should use the same character array field in the record that
you used for the "f" option). It will then search the list for the first node that matches that domain name, and delete that node from the list. Be sure
to use the delete
operator here to de-allocate everything for this node, as in step 1, and to update all pointers so
that the list is still in-tact after the delete.
From here on out the drill is the same for each additional step (except the last one)... for each step, you add one additional option to the program, and get a bit more credit. At each step, copy your file with a command such as:
cp p2s2.cc p2s3.cc
Then add the necessary code to implement the new options. (This is the last step where I'll spell out these specific instructions
Partial Credit: If this step is as far as you get, it is worth up to 60% partial credit (you start with a grade of 60%, and additional deductions may be taken from there). If you stop here, script this program. Be sure you test all the options that are present at this stage (see the script file p2s3.txt for ideas.)
(From here on out, you'll be expected to just follow the pattern; I'll just say "this step is worth x% partial credit, and the script file should be called p2sn.txt, where n is the step number.
If you are continuing on with the remaining parts, you do NOT need to submit a script or C++ program for this step. Only submit the script for the step at which you finish.
Suggestion: You should read the values into a character array (using
cin.getline()) and before assigning the new value, check if the string
entered is blank (using strlen()). If the length of the string is 0, that means
the string is empty. Ask your TA if you are not sure how to do this.
If a character array field is updated, you have to delete
the
old array and use new
to create the new one.
See previous stages 1-3 for guidance on how to name your program, script file, etc. and what to turn in if you stop at this step.
In this step, you will add an option to allow the user to read records into the linked list from a file.
The file will have the same format as the files in the directory proj2, which contains several files teams1.txt, teams2.txt, etc., all of which contain fields separated by ":". For your project, you may use comma separated data, or : separated data; it is your choice.
For hints on how to use strtok to read colon or comma separated data, follow the example code from the strtokExample subdirectory, which reads a file separated by commas. To use colons insetad, simply change "," in the second parameter of strtok to ":"
~pconrad/public_html/cisc181/05F/work/proj/proj2/strtokExample
http://copland.udel.edu/~pconrad/cisc181/05F/work/proj/proj2/strtokExample
After you've figured out how to handle the strtok part, add the "r" option to your program. This option prompts the user to enter a file name.
It then opens that file as an ifstream; if the file can't be opened, just print an error message and return from the function to the main menu (don't exit the program.)
If the file is opened successfully, read all records from the file
(which contains colon separated values, similar to the files teams.txt,
and udel.txt; these can be found in the proj/proj2 directory cited above).
For each line you read from the file, allocate a new node.
Read each line from the file into a single character array, then use
strtok() to break up the fields and store each one in its proper place
in the new node. Then, add that new node into the linked list. Remember to
use new
to allocate each node and to allocate each character
array field in each node.
You'll need to create a data file or two. I suggest you create at least three data files:
Name your data files after your theme, e.g.
Some sample data files for the NCAA team project (in colon separated format) are in:
http://copland.udel.edu/~pconrad/cisc181/05F/work/proj/proj2/sampleData/
See previous stages 1-3 for guidance on how to name your program, script file, etc. and what to turn in if you stop at this step.
It then opens that file as an ofstream; if the file can't be opened, just print an error message and return from the function to the main menu (don't exit the program.)
If the file is opened successfully, write all the records from the linked list into an output file, separated by colons or commas, in the same format as the input files teams.txt, and udel.txt; these can be found in the proj/proj2 directory cited above).
The idea is that the output file you create should be able to be read back into the program as an input file with the r option on the same run, or a later run. You should test this in your script.
See previous stages 1-3 for guidance on how to name your program, script file, etc. and what to turn in if you stop at this step.
When the user types quit, print a message warning the user if there are any unsaved changes. If there are NOT unsaved changes, the message should not be printed. If there are unsaved changes, ask the user if they really want to quit without saving. If the answer is yes, go ahead and quit. If the answer is no, return to the main menu.
Hint: Add a variable in your main program that keeps track of whether or not the list has been modified since the last time it was written to a file. Start the variable as false. Every time the user invokes an option that modifies the list, set the variable to true. Every time the user writes the file out to the disk, set the variable to false. Then pass this variable into the quit option.
See previous stages 1-3 for guidance on how to name your program, script file, etc. and what to turn in if you stop at this step.
For this step, you will need to make sure that your list remains sorted in
alphabetical order according to the "key" value (the same character array field
that you search for in steps 2, 3, etc.). For this, you will want to either
use strcmp()
or strcasecmp()
from the cstring library.
These are the same except that strcasecmp
ignores upper/lower case.
You decide for your choice of data which function is more appropriate
The primary function here that will need changing is "a" (add). This will need to insert each new node into the list at the proper place. Also, update will need to call remove and then add if the "key" field is changed. Additionally, you can not assume that input files are pre-sorted; therefore, your function that reads from a file may have to be modified, depending on how you chose to implement it. Finally, there is some minor improvement that can be made to the find function.
For information on how to use strcmp, type man strcmp
from
Strauss, or look on page 376 in Savitch. Or, ask your TA for help.
For this stage, be sure your script tests all the options involved in the program. Also, if you reach this stage, name your program and your script file proj2.cc and proj2.txt.
You do not need to create a Makefile or a tar file to submit this assignment; all your code will be in one C++ source file.
cat
any data files you read or create, and to do an ls
command before and after you create. Step | Filename | Menu options | comments | points | cumulative |
---|---|---|---|---|---|
0 | proj2data.txt | N/A | available on website, at least two char fields, at least two numeric (one int, one double), doesn't duplicate another's topic) |
9 | 9 |
final script |
p2sn.txt | N/A | scripting per instructions | 18 | 36 |
all | N/A | N/A | following directions | ||
1 | p1s1.cc | a(dd), l(ist), q(uit), s(ummarize) | style and correctness | 9 | |
2 | p2s2.cc | f(ind) | style and correctness | 9 | 45 |
3 | p2s3.cc | d(elete) | style and correctness | 9 | 54 |
4 | p2s4.cc | u(pdate) | style and correctness | 9 | 63 |
5 | p2s5.cc | r(ead from file) | style and correctness | 9 | 73 |
6 | p2s6.cc | w(rite to file) | style and correctness | 9 | 81 |
7 | p2s7.cc | smarter quit | style and correctness | 9 | 90 |
8 | proj2.cc | sorted list | style and correctness | 10 | 100 |