You are to write a program that reads in "Cards" that contain name and email information. After dynamically creating an array of Card objects, your program looks up a name and displays the corresponding email address (if present in the list of cards). You have been given the driver program; your job is to implement the two functions that do the actual work.
In the given header file you can see the struct that has been defined to hold the name and email information.
struct Card {
char * name;
char * email;
};
In other words, a Card object just has 2 pointers. Keep in mind that when you create a new Card object, you only get the 2 pointers; you will have to create space for the actual strings themselves (using malloc()).
This structure is defined in the given header file; you should not have to define it anywhere else.
Data for this program is stored in a simple text file with one Card per line. Specifically, each line contains first the name and then the email address associated with that name. For convenience it is assumed that neither the name nor the email address contain any spaces; therefore a single call to fscanf() can read the data for each Card:
conversions = fscanf(f, "%s %s", tmp_name, tmp_email);
Note that you don't know in advance how many characters the name and email address will each take; you are allowed to assume that neither will take more than 50 characters, so it is reasonable to create two temporary char arrays statically, each with 51 elements (don't forget the final null character!), and use these arrays in your fscanf() call.
You must implement 2 functions that work with an array of Card objects.
getCards() - this function takes the name of a data file as a parameter, and returns a pointer to an array of Card objects. As with the last lab, there is also an output parameter that you have to fill with the number of elements in the array.
The basic steps for this function are:
#3 above is the main step. In particular, the difficulty is in dealing with the strings, since they will need space allocated for them manually.
You don't want to store 50 characters in the actual Card objects, though, as most of the time there will be a lot of bytes left over, creating a lot of wasted space. Once you read in the strings using fscanf() as above, you can allocate exactly the right number of bytes for them using the string.h file's "strlen()" function, and "malloc()". That is, you use strlen() to find out how many characters were actually in the temporary string used in fscanf(); you then use malloc() to allocate that many chars, plus one for the null terminator.
After you use malloc(), you have the right number of bytes available for the permanent string, but you still need to copy the characters over from the temporary string. Use the "strcpy()" function (again from string.h) to perform this copy. Note that strcpy() copies all the characters and the null terminator from the source string, so you don't have to worry about that final null character.
Both strcpy() and strlen() are described briefly in the Appendix to the text; they also have entries in Wikipedia.
lookup() - this function takes an array of Card objects (as a pointer to the first item), a name to look up, and the size of the array. It goes through the array one item at a time. If the name is found (exact match is OK, case included), then the associated email is returned (as a char pointer). If you get through the whole array without finding the name, NULL is returned.
To test if two strings are equal (i.e. the input name and the name of the current Card object), use the strcmp() function from string.h. This function is listed in the Appendix to the textbook, and also has a Wikipedia entry. If you try to test them using "==", you are only testing the addresses of the first characters (which should always be different -- they won't be stored at the same spot in RAM). strcmp() goes through the strings character by character and compares actual ASCII codes rather than just comparing addresses.
This is a very small function! You just need to set up a loop to go through the Card array; inside the loop you have a single "if" statement that tests the current Card's "name" field with the "name" parameter (using strcmp()), and immediately returns the "email" field if there is a match (i.e. if strcmp() returns zero). If the loop finishes, then no match was found and you just return NULL. There should just be 5 lines of code:
1. declare loop counter. 2. set up for loop. 3. if statement 4. return email pointer (when "if" test succeeds) 5. return NULL (when loop finishes).
Don't make it harder than it needs to be! (Of course, getting at the "current" Card's name and email fields requires some careful syntax, but don't lose sight of the big picture, which is fairly straight-forward.)
The driver is set up to take two command-line parameters: the name of the file that contains the cards, and the name you want to lookup. In the card file I have supplied I have several entries for my various email addresses. Here are some sample outputs:
./a cards.txt Rob Rob -> rt@bridge.camosun.bc.ca ./a cards.txt Bob Bob -> rthorndy@gmail.com ./a cards.txt Jack Sorry, that name was not in the list of cards.
Note that name entries are always just one word ... the fscanf() gets too tricky if one item has spaces in it!
You are send just the lab9utils.c file as an email attachment to rthorndy@gmail.com with the subject header: Comp 166 Lab 9 Submission. Do not submit any other files.
This lab will be marked out of 10 points:
4 points: getCard() function correctly allocates and populates Card array.
2 points: parameters and return values used properly in functions.
2 points: lookup() returns correct results (i.e. email pointer if name is found, NULL if not).
2 points: correct indentation and naming conventions.