1Assignment 3: Employee Database
IMPORTANT: Please read the assignment rules on the web page at
http://www.ee.surrey.ac.uk/Teaching/Courses/C/rules.html
and the submission procedure at
http://www.ee.surrey.ac.uk/Teaching/Courses/C/submission.html
BEFORE starting the assignments.
The submission deadline is:
4pm, Tuesday 8th May 2012 for all lab classes.
When submitting the les, you MUST follow the name specication as described in the end of each part of
the assignment. Failing to follow the name specication will result in a penalty of 10 percent reduction
from your nal mark.
This assignment will be to implement a program to maintain an employee database, with each employee
represented by his/her name, sex, age and job description. This is a fairly large program, and you will
only have to implement part of it. You will be provided with the source code for some basic functions, the
structure you can use to represent the information for each employee, and also the code for the top-level
keyboard interface to the program. Your task will be to build the lower level functions that build and
manipulate the database.
You will represent the employee database as a list of structures, one per employee, each containing the
relevant name, sex, age and job description for the employee. The struct Employee structure you will be
provided with contains this information, as follows:
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
/* Employee structure
*/
struct Employee
{
/* Employee details */
char name[MAX_NAME_LENGTH+1]; /* name string */
char sex; /* sex identifier, either 'M' or 'F' */
int age; /* age */
char job[MAX_JOB_LENGTH+1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
So the name is represented by a string of maximum length MAX NAME LENGTH (+1 to include the string
termination character), the sex by a single character, either 'M' or 'F', the age as an integer (which should
be greater than zero), and the job description as another string of maximum length MAX JOB LENGTH. If
either the name or job description is longer than the specied maximum length, it should be truncated.
2Representing a Database with an Array
In your program you will manipulate struct Employee structures to build and modify the database. The
simplest way to represent several structures at once is as an array of structures. Let us set the maximum
number of employees in our database to a dened constant MAX EMPLOYEES:
/* maximum number of employees that can be stored at once (relevant only
to storage using an array) */
#define MAX_EMPLOYEES 200
Then we can dene an array of MAX EMPLOYEES structures, and use an integer to represent the number of
employees currently represented in the program, which of course is initialized to zero:
/* array of employees */
static struct Employee employee_array[MAX_EMPLOYEES];
/* number of employees stored */
static int no_employees = 0;
This array/integer representation may be used to represent our database. However there are some problems
with using an array to represent a database:
An array has a xed size. The array employee array of struct Employee structures declared above
can obviously not hold details for more than MAX EMPLOYEES employees. This is only OK if you know
beforehand the maximum number of employees you are likely ever to have, which is not likely.
An array is inecient in storing the information, again because of its xed size. If you guess the
maximum number MAX EMPLOYEES of employees, and declare an array of that size, but in fact the
program actually only creates a much smaller database, most of the memory block used for the array
is wasted.
An array is inecient in implementing important operations, especially if the elements of the array are
maintained in a specic order. Let us assume that our array is stored in alphabetical order of name,
and we wish to insert a new employee \Carmen Miranda" into the array shown in gure 1. As you can
see, insertion into an ordered array is a very inecient operation, because every array element (in this
case struct Employee structure) beyond the insertion point must shift up one place to make room.
This involves lots of copying data. The same applies to deleting an employee, when all the employee
structures beyond the deletion point would have to shift back one place.
The linked list data structure gets around all these problems. It is a dynamic data structure, which expands
and contracts as the database size goes up and down. Implementing linked lists involves the use of an
advanced C feature called dynamic memory allocation. We shall rst introduce the concept of dynamic
memory allocation and provide a simple example, before discussing how we can use it to eciently build a
linked list. Once you are comfortable with the concepts and examples, it will be easier to write the programs
for this assignment using linked lists than using arrays. However if you really do not want to use linked
lists, you may if you like use the array representation, but in this case you will be marked out of 90% for
this assignment (i.e. you will lose 10% of your marks, for this assignment only). An alternative would be to
convert to the linked list representation when you have successfully implemented the array representation. If
you do not want to know about linked lists right now, you may turn immediately to part 1 of the assignment
description on page 9.
3Delia Harrigan
F
35
Marketing
Colin Winthrop
M
21
Computer support
Hristo Stoichkov
M
34
Security officer
Hilary Nair
F
23
Computer support
Peter Morris
M
53
Managing Director
Carmen Miranda
F
47
Sales director
(b) Modified database array after insertion
Hristo Stoichkov
M
34
Security officer
Colin Winthrop
M
21
Computer support
Peter Morris
M
53
Managing Director
Hilary Nair
F
23
Computer support
Delia Harrigan
F
35
Marketing
Carmen Miranda
F
47
Sales director
(a) Database before insertion of new employee "Carmen Miranda"
New employee
to be inserted in array
Employees after insert position must move up to make room
Figure 1: Illustration of the ineciency of the array representation of an ordered database. Here the database
of employees is ordered alphabetically by surname, and a new employee \Carmen Miranda" is to be inserted
in the existing array (a) of ve employees. To insert the new employee, all the employees with surnames
alphabetically \greater" than \Miranda" have to shift up one place in the array to make room for her. (b)
Modied database after insertion of new employee.
4Dynamic memory allocation
We must rst introduce the mechanism provided in C to create temporary blocks of memory within a
program. The two most important functions that implement dynamic memory allocation in C are malloc()
and free(). malloc() is used to allocate a block of unused computer memory which can then subsequently
be used in the program. It is declared as:{
void *malloc(size_t size);
The size argument species how many bytes you want in your block of memory. The memory block is
returned as a generic pointer (void *) type, and can be cast (converted) to whatever C pointer type you
wish. When the program has nished with the memory block, the free() function is used to discard it so
that it may be used again:-
void free(void *ptr);
The (void *) memory block returned by malloc() should be passed to free() when it is not needed any
more. Here is a simple program using dynamic memory allocation.
#include
#include
#include
int main ( int argc, char *argv[] )
{
char *string;
int length = 200;
string = (char *) malloc(length);
strcpy ( string, "This is a string that fits easily into 200 bytes" );
printf ( "String: %s\n", string );
free ( string );
return 0;
}
Firstly the character pointer string is declared. As you should know by now, a pointer can be used to point
to a single object, or it may specify the start of an array. In this case we dynamically create an array of
characters by calling malloc(), and set string to point to the start of it. string can then be used exactly
as if it had been declared as an array of characters, and we show an example, copying another string into it
and printing the copied string. The code for the alternative array version of the program would be
#include
#include
int main ( int argc, char *argv[] )
{
char string[200];
strcpy ( string, "This is a string that fits easily into 200 bytes" );
printf ( "String: %s\n", string );
return 0;
}
5Comparing the two versions of the program, we note that
1. The version using dynamic memory allocation version is more
exible, in that the size of the string
allocated need not be a constant (200 in this case) but can be any integer value, for instance (as here)
the value of an integer variable. The size of the allocated block of memory is determined when the
program is run. In the second version, the array size is xed.
2. On the other hand, the array version is shorter and simpler. If malloc() is called, you must remember
to add a free() statement at the point where the program has nished using the memory block,
because otherwise the memory will be wasted. The memory taken up by arrays (allocated from the
\stack") is returned automatically when the program block in which it was declared terminates, in this
simple case the end of the program. Predened arrays are in this sense easier to use than dynamically
allocated arrays.
Another use of dynamic memory allocation is to create an instance of a structure. So for instance the
program segment
{
struct Employee *new;
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Philip McLauchlan" );
new->sex = 'M';
new->age = 34;
strcpy ( new->job, "Lecturer" );
free ( new );
}
creates a memory block the right size to hold a struct Employee structure, sets new to point to it, and then
lls the elds of the structure with some personal details (in this case mine). Note the -> operator, which
allows you to access elds of a structure via a pointer to it. In fact new->name is equivalent to (*new).name,
but a little simpler and more concise.
Without dynamic memory allocation one could write this program segment as
{
struct Employee employee, *new;
new = &employee;
strcpy ( new->name, "Philip McLauchlan" );
new->sex = 'M';
new->age = 34;
strcpy ( new->job, "Lecturer" );
}
Again this program segment is exactly equivalent. The employee structure is here allocated from the \stack",
and returned to the stack automatically at the end of the program segment.
NOTE: To use malloc() and free() in your program you must rst #include the header le stdlib.h.
Linked Lists
So far the only benet we have mentioned of dynamic memory allocation is the extra
exibility of being able
to create blocks of memory with size specied as the program runs rather than being xed beforehand. The
6other major benet becomes clear if we extend the above program segment as follows:{
static struct Employee *employee_list = NULL;
{
struct Employee *new;
/* create the first employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Philip McLauchlan" );
new->sex = 'M';
new->age = 34;
strcpy ( new->job, "Lecturer" );
/* add first employee to singly-linked list */
new->next = employee_list;
employee_list = new;
/* create the second employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Monica Lewinsky" );
new->sex = 'F';
new->age = 28;
strcpy ( new->job, "Intern" );
/* add second employee to singly-linked list */
new->next = employee_list;
employee_list = new;
/* create the third employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Carol Vorderman" );
new->sex = 'F';
new->age = 38;
strcpy ( new->job, "TV Brainbox" );
/* add third employee to singly-linked list */
new->next = employee_list;
employee_list = new;
}
Here we have created three employees, and built a simple linked list employee list to hold them, using
the next elds of the struct Employee structure to hold the links between the employee structures. Here
we have built a singly-linked list, so-called because there is only one link between each pair of employee
structures (the prev eld is not used). The singly-linked list generated by this simple example is illustrated
in gure 2. Note that free() is not called. This means that the employee data stored in the linked list is
maintained outside the program segment in which it is created, which is not possible with locally declared
arrays.
Note also that in this simple example new employees are always inserted at the start of the list. This is the
most ecient method of insertion. If the list were ordered, for instance by surname (family name), then
the program would have to rst locate the correct position for insertion. To insert Carol Vorderman at the
7Philip McLauchlan
M
34
Lecturer
next
Monica Lewinsky
F
28
Intern
next
Philip McLauchlan
M
34
Lecturer
next
Carol Vorderman
F
38
TV Brainbox
next
Monica Lewinsky
F
28
Intern
next
Philip McLauchlan
M
34
Lecturer
next
employee_list
NULL
(b) Modified linked list after insertion of first
employee_list
employee "Philip McLauchlan"
NULL
(c) Modified linked list after insertion of second employee
employee_list
NULL
(d) Modified linked list after insertion of third employee "Carol Vorderman"
"Monica Lewinsky"
employee_list NULL
(a) Initial empty linked list
Figure 2: A simple linked list. (a) Initial empty list pointing to NULL. (b) After the rst employee is added.
(c) After the second employee is added. (d) After the third employee is added. Note that employees are
inserted at the start of the list (see program segment).
correct position at the end of the list, one would have to replace the last part of the code segment with
{
...
/* add third employee to singly-linked list */
employee_list->next->next = new;
new->next = NULL;
}
Clearly one can use such constructions to place new list elements anywhere we desire in the list.
If an employee is to be deleted from the database, one can achieve this with code such as
{
struct Employee *second_employee;
/* delete second employee in linked list */
second_employee = employee_list->next;
/* make first employee point to third employee */
employee_list->next = second_employee->next;
/* free second employee */
free ( (void *) second_employee );
}
8which deletes the second employee in the employee list, and xes the pointers in the linked list to avoid
the deleted employee structure. So free() is applied to the employee structures as they become redundant.
This linked-list method of holding employee information gets around the previously mentioned problems
with arrays, because
1. The linked list can grow and shrink as required. It is only limited by the computer's memory.
2. It is usually more ecient in terms of using memory, because only the data required at any time is
stored. This usually compensates for the extra pointer elds(s) in the structure used to represent the
links, which are not required in the array representation.
3. Insertion, deletion and other operations can be implemented eciently as above. The dierence be-
tween linked lists and arrays here is that with a linked list the operation can often be implemented as
a \local" operation, with only two or three elements of the list involved, whereas with ordered arrays
sometimes the whole of the array must be modied to implement a single operation.
Doubly-Linked Lists
Operations such as sorting and deletion may be simplied if there are links between adjacent elements of a
linked list in both directions. This is a doubly-linked list. To implement this we use the prev eld of the
struct Employee structure, and the doubly-linked list version of the previous code segment is:{
static struct Employee *employee_list = NULL;
{
struct Employee *new;
/* create the first employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Philip McLauchlan" );
new->sex = 'M';
new->age = 34;
strcpy ( new->job, "Lecturer" );
/* add first employee to doubly-linked list */
new->prev = NULL;
new->next = employee_list;
employee_list = new;
/* create the second employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Monica Lewinsky" );
new->sex = 'F';
new->age = 28;
strcpy ( new->job, "Intern" );
/* add second employee to doubly-linked list */
new->prev = NULL;
new->next = employee_list;
employee_list->prev = new;
employee_list = new;
9employee_list Carol Vorderman
F
38
TV Brainbox
Monica Lewinsky
F
28
Intern
Philip McLauchlan
M
34
Lecturer
next next next
prevprevprev
NULL
NULL
Figure 3: Illustration of doubly-linked list with three elements (employees).
/* create the third employee */
new = (struct Employee *) malloc ( sizeof(struct Employee) );
strcpy ( new->name, "Carol Vorderman" );
new->sex = 'F';
new->age = 38;
strcpy ( new->job, "TV Brainbox" );
/* add third employee to doubly-linked list */
new->prev = NULL;
new->next = employee_list;
employee_list->prev = new;
employee_list = new;
}
This code segment produces the linked list shown in gure 3 The doubly-linked list is a useful construction
because it is possible to traverse the whole list backwards or forwards from any element of it, whereas with a
singly-linked list you can only go \forwards". You are recommended to use a doubly-linked list to represent
the employee database in this assignment.
Part 1: Add employees to the database (40 marks)
Now you should have decided whether to use arrays or (as recommended) linked lists for the assignment, and
we can now describe the details of the assignment. Firstly, cd to your eeclabs directory. Then download
the input les for part 1 into this directory from the following website:
http://info.ee.surrey.ac.uk/Teaching/Courses/C/rules.html
This should include the template C source le employee.c and input le \emp1". employee.c is a \template"
program with some empty functions, which you shall ll in with code as the assignment proceeds. Compile
the program with the command
gcc -ansi -Wall employee.c -o employee
It should compile successfully (although it may give a warning that the read string() function is \dened
but not used", which you can ignore). Run it using the command:
./employee
10
You will nd that none of the menu options do anything, except 3 (Exit), which should work! When a menu
option is selected, the relevant function (menu add employee(), menu delete employee() or menu print database())
is called, but these functions are empty. Your assignment is to build this program into a useful database
program by lling in these empty functions.
Copy the employee.c le into a new le employee1.c, and work with this le in this part of the assignment.
Please note that, as with the other assignments, the testing that will be applied to your program involves
comparing what your program prints to standard output (stdout) with the correct output specied in
the assignment sheet and produced by our reference program. Your program must conform to the specied
output format to be classied as a working program. Therefore please take note of any instructions regarding
output. The use of the standard error (stderr) is however unrestricted, so any debugging messages, prompts
etc. should be fprintf'd to stderr.
In the rst part of the assignment, you are to ll in the functions menu add employee() and menu print database()
by modifying employee1.c. These functions are called when menu options 0 (add new employee) and 2 (print
entire contents of employer database to screen) respectively are selected by the user.
menu add employee() should prompt the user to enter the name, sex, age and job description of the new
employee, in that order, and add the new employee to the array/linked list database. The prompt messages
(which you can pick for yourself) should be printed to standard error (use fprintf to stderr), NOT
standard output (i.e. DO NOT use printf). The name and job should be entered as strings, truncated to
MAX NAME LENGTH and MAX JOB LENGTH characters respectively. The sex is a single character, and the age
is an integer. If any part of the description is entered incorrectly (i.e. empty name/job strings are typed,
sex character not one of 'M' or 'F' or age 0), the program should continue to prompt for the relevant
personal detail until a legal version is provided, before going on to the next part of the employee description.
The name should be entered in the form , to make sorting by surname easier.
Duplicate names are to be allowed, and if multiple people with the same name exist, their order is arbitrary.
To help you implement menu add employee(), the function read line() is provided, which reads a line of
input and stores it in a string (the read string() function also provided will be useful in part 3).
The function menu print database() should print the employee description for each employee to standard
output (i.e. DO use printf() here), with each part being printed on a line by itself and prexed by the
strings "Name:", "Sex:", "Age:" and "Job:" respectively, and also a space separating the prex from the
relevant following string/character/integer. There should be a blank line between each employee. Do not
print any extra invisible spaces at the end of lines. The employees should be printed in alphabetical order
of their surname. Because the surname is always the rst name in the name string, you can use strcmp()
to decide on the ordering. It is up to you whether you enforce the ordering by inserting new employees in
the correct position to maintain ordering of the database, or add employees in arbitrary order and sort them
before printing them.
Compile the program with the command
gcc -ansi -Wall employee1.c -o employee1
To test your program, the le emp1 can be used as input to the employee program, to simulate keyboard
input. Once you have adapted your program as above, and compiled it, run the command
./employee1 < emp1 > tmp
The contents of the standard output are sent to the le tmp, which should then contain
Name: Cham, Sandra
Sex: F
Age: 34
11
Job: Software engineer
Name: MacPherson, Ian
Sex: M
Age: 62
Job: Cleaner
Name: Saunders, Leslie
Sex: F
Age: 42
Job: Sales rep
You should generate other test les in the same way, to make sure your program is working, particularly to
test its behaviour with illegal inputs.
HINT 1: The database data structure, whether array of structures or linked list, will be accessed by dierent
functions, so it must be declared as a global variable.
HINT 2: Use read line() to read a line of input, and then, if necessary, sscanf() to read the contents of
the string.
NOTE 1: You should not change the main() function or the values of the menu codes (ADD CODE etc.). Apart
from that you are free to implement the program as you wish, so long as it produces the correct output to
stdout for a given keyboard input (from stdin). So you can if you like dene your own employee structure,
and you also do not have to use the read line() function; these are only intended as helpful suggestions.
This note applies to all parts of this assignment.
NOTE 2: Most of the marks will be for correct operation of the program given legal input. The tests
described above for illegal inputs in menu add employee() will gain you a few extra bonus marks.
Note 3: Once you are sure the menu add employee() and menu print database() functions are working,
and have written comment blocks into the source code for any extra internal functions you have added to
the employee1.c program (as described in the rules for assignments on the Web page), re-name your le
according to the following specication and then submit the program to both ULearn and Turnitin web
sites.
NOTE 4: The name of the submitted le MUST be proceeded with your surname and initial followed by
the name of the program. For example, if your surname is \Brown", and your rst name is \Peter", you
need to name the le as follows:
BROWNP-employee1.c
The rst part is your surname and initial followed by a hyphen, and then followed by the original lename.
If you also have middle names, ignore them in the le name. If your files do not follow this name
specification, as a penalty, 10 percent will be deducted from your final mark.
NOTE 5: Submit your program (named according to NOTE 4) to ULearn, which can be accessed via the
following web site:
http://ulearn.surrey.ac.uk/
Please use your university username and password (the same username and password that you use to access
your university email and computers in the campus) to login to ULearn. Once you login to ULearn, you
will be able to see the links to Programming - Spring Semester 2011-12 on your My ULearn Homepage.
Click this link, and submit your assignment to the folder employee.
12
NOTE 6: Also submit your program (named according to NOTE 4) to Turnitin, which can be accessed via
the following web site:
http://submit.ac.uk
Use the password sent to you by turnitin to login to the system.
Part 2: Delete employees from the database (30 marks)
Download the input le \emp2" for part 2 into your directory from the following website:
http://info.ee.surrey.ac.uk/Teaching/Courses/C/rules.html
In the second part of the assignment, which follows on from the program employee1.c you wrote in part 1,
you are to ll in the function menu delete employee(). This function is called when menu option 1 (delete
employee) is selected by the user.
Firstly copy the employee1.c le from part 1 into a new le employee2.c, and work with this le in this
part of the assignment.
menu delete employee() should prompt the user to enter the full name of the employee to be deleted (as it
appears in the database), and delete the named employee from the employee database. If the name does not
match anyone in the database, the function should fprintf an error message to stderr (e.g. \Employee
not found") and return with no change to the database.
Compile the program with the command
gcc -ansi -Wall employee2.c -o employee2
To test your program, the le emp2 can be used as input to the employee2 program, to simulate keyboard
input. Once you have adapted your program as above, and compiled it, run the command
./employee2 < emp2 > tmp
The contents of the standard output are sent to the le tmp, which should then contain
Name: MacPherson, Ian
Sex: M
Age: 62
Job: Cleaner
Name: Saunders, Leslie
Sex: F
Age: 42
Job: Sales rep
Sandra Cham has been removed from the database. You should generate other test les in the same way, to
make sure your program is working, particularly to test its behaviour with illegal inputs.
Note 1: Once you are sure the menu delete employee() function is working, and have written comment
blocks into the source code for any extra internal functions you have added to the employee2.c program
13
(as described in the rules for assignments on the Web page), re-name your le according to the following
specication and then submit the program to both ULearn and Turnitin web sites.
NOTE 2: The name of the submitted le MUST be proceeded with your surname and initial followed by
the name of the program. For example, if your surname is \Brown", and your rst name is \Peter", you
need to name the le as follows:
BROWNP-employee2.c
The rst part is your surname and initial followed by a hyphen, and then followed by the original lename.
If you also have middle names, ignore them in the le name. If your files do not follow this name
specification, as a penalty, 10 percent will be deducted from your final mark.
NOTE 3: Submit your program (named according to NOTE 2) to ULearn, which can be accessed via the
following web site:
http://ulearn.surrey.ac.uk/
Please use your university username and password (the same username and password that you use to access
your university email and computers in the campus) to login to ULearn. Once you login to ULearn, you
will be able to see the links to Programming - Spring Semester 2011-12 on your My ULearn Homepage.
Click this link, and submit your assignment to the folder employee.
NOTE 4: Also submit your program (named according to NOTE 2) to Turnitin, which can be accessed via
the following web site:
http://submit.ac.uk
Use the password sent to you by turnitin to login to the system.
Part 3: Read initial employee database from le (30 marks)
Download the input le \emp3" for part 3 into your directory from the following website:
http://info.ee.surrey.ac.uk/Teaching/Courses/C/rules.html
In the third part of the assignment, which follows on from the program employee2.c you wrote in part 2,
you are to ll in the function read employee database(). This function is called when the program is run
with an argument, which species a le of employees with which to initialize the databse. You should check
the value of argc to see whether a databse le has been specied.
Firstly copy the employee2.c le from part 2 into a new le employee3.c, and work with this le in this
part of the assignment.
read employee database() should read the database in the same format that menu print database()
prints them, except that it should be able to accept employee lists not in alphabetical order. If any illegal
name/job string, sex character or age appears in the le, the program should exit (use the exit() function)
with an exmplanatory error message printed to stderr. Otherwise, the le is read, the database is built,
and the menu interface starts as normal, with the pre-loaded employee database.
You will need to use the function fopen() to open the database le. Then you can use the provided function
read string() to read lines from the le. Finally use fclose() to close the le when you have nished.
Compile the modied program with the command
14
gcc -ansi -Wall employee3.c -o employee3
To test your program, the le emp3 can be used as input to the employee3 program, to simulate keyboard
input. Once you have adapted your program as above, and compiled it, run the command
./employee3 emp3 > tmp
and then select option \2" in turn to print the database read from the le emp3 to standard output, and
then \3" to exit. The standard output is here redirected to the le tmp, which should then contain
Name: Conker, Richard
Sex: M
Age: 19
Job: Trainee marketing
Name: Goulermas, Isabel
Sex: F
Age: 52
Job: Managing Director
Name: Graham, Billy
Sex: M
Age: 63
Job: Evangelist
Name: Karula, Roger
Sex: M
Age: 23
Job: Engineer
Name: Kumar, Sanjay
Sex: M
Age: 47
Job: Marketing manager
Name: Leavers, Karen
Sex: F
Age: 35
Job: Systems analyst
Name: McLeod, Jonathan
Sex: M
Age: 27
Job: Computing support
Name: Ranganathan, Aris
Sex: M
Age: 33
Job: Marketing
Name: Smart, Lisa
Sex: F
15
Age: 18
Job: Trainee engineer
Name: Yip, Susan
Sex: F
Age: 22
Job: Secretary
You should generate other test les in the same way, to make sure your program is working, particularly to
test its behaviour with illegal inputs.
Note 1: Once you are sure the read employee database() function is working, and have written comment
blocks into the source code for any extra internal functions you have added to the employee3.c program
(as described in the rules for assignments on the Web page), re-name your le according to the following
specication and then submit the program to both ULearn and Turnitin web sites.
NOTE 2: The name of the submitted le MUST be proceeded with your surname and initial followed by
the name of the program. For example, if your surname is \Brown", and your rst name is \Peter", you
need to name the le as follows:
BROWNP-employee3.c
The rst part is your surname and initial followed by a hyphen, and then followed by the original lename.
If you also have middle names, ignore them in the le name. If your files do not follow this name
specification, as a penalty, 10 percent will be deducted from your final mark.
NOTE 3: Submit your program (named according to NOTE 2) to ULearn, which can be accessed via the
following web site:
http://ulearn.surrey.ac.uk/
Please use your university username and password (the same username and password that you use to access
your university email and computers in the campus) to login to ULearn. Once you login to ULearn, you
will be able to see the links to Programming - Spring Semester 2011-12 on your My ULearn Homepage.
Click this link, and submit your assignment to the folder employee.
NOTE 4: Also submit your program (named according to NOTE 2) to Turnitin, which can be accessed via
the following web site:
http://submit.ac.uk
Use the password sent to you by turnitin to login to the system.
If you have implemented all the functions correctly, you will have built a database program that can read
an existing database and modify it under interactive keyboard control.
Printout of employee.c
#include
#include
#include
16
/* maximum number of employees that can be stored at once (relevant only
to storage using an array) */
#define MAX_EMPLOYEES 200
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
/* Employee structure
*/
struct Employee
{
/* Employee details */
char name[MAX_NAME_LENGTH+1]; /* name string */
char sex; /* sex identifier, either 'M' or 'F' */
int age; /* age */
char job[MAX_JOB_LENGTH+1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
/* read_line():
*
* Read line of characters from file pointer "fp", copying the characters
* into the "line" string, up to a maximum of "max_length" characters, plus
* one for the string termination character '\0'. Reading stops upon
* encountering the end-of-line character '\n', for which '\0' is substituted
* in the string. If the end of file character EOF is reached before the end
* of the line, the failure condition (-1) is returned. If the line is longer
* than the maximum length "max_length" of the string, the extra characters
* are read but ignored. Success is returned (0) on successfully reading
* a line.
*/
static int read_line ( FILE *fp, char *line, int max_length )
{
int i;
char ch;
/* initialize index to string character */
i = 0;
/* read to end of line, filling in characters in string up to its
maximum length, and ignoring the rest, if any */
for(;;)
{
/* read next character */
ch = fgetc(fp);
/* check for end of file error */
if ( ch == EOF )
17
return -1;
/* check for end of line */
if ( ch == '\n' )
{
/* terminate string and return */
line[i] = '\0';
return 0;
}
/* fill character in string if it is not already full*/
if ( i < max_length )
line[i++] = ch;
}
/* the program should never reach here */
return -1;
}
/* read_string():
*
* Reads a line from the input file pointer "fp", starting with the "prefix"
* string, and filling the string "string" with the remainder of the contents
* of the line. If the start of the line does not match the "prefix" string,
* the error condition (-1) is returned. Having read the prefix string,
* read_string() calls read_line() to read the remainder of the line into
* "string", up to a maximum length "max_length", and returns the result.
*/
static int read_string ( FILE *fp,
char *prefix, char *string, int max_length )
{
int i;
/* read prefix string */
for ( i = 0; i < strlen(prefix); i++ )
if ( fgetc(fp) != prefix[i] )
/* file input doesn't match prefix */
return -1;
/* read remaining part of line of input into string */
return ( read_line ( fp, string, max_length ) );
}
/* menu_add_employee():
*
* Add new employee to database
*/
static void menu_add_employee(void)
{
/* fill in the code here in part 1, and add any extra functions you need */
}
18
/* menu_print_database():
*
* Print database of employees to standard output.
*/
static void menu_print_database(void)
{
/* fill in the code here in part 1, and add any extra functions you need */
}
/* menu_delete_employee():
*
* Delete new employee from database.
*/
static void menu_delete_employee(void)
{
/* fill in the code here in part 2, and add any extra functions you need */
}
/* read file containing database of employees */
static void read_employee_database ( char *file_name )
{
/* fill in the code here in part 3, and add any extra functions you need */
}
/* codes for menu */
#define ADD_CODE 0
#define DELETE_CODE 1
#define PRINT_CODE 2
#define EXIT_CODE 3
int main ( int argc, char *argv[] )
{
/* check arguments */
if ( argc != 1 && argc != 2 )
{
fprintf ( stderr, "Usage: %s []\n", argv[0] );
exit(-1);
}
/* read database file if provided, or start with empty database */
if ( argc == 2 )
read_employee_database ( argv[1] );
for(;;)
{
int choice, result;
char line[301];
/* print menu to standard error */
fprintf ( stderr, "\nOptions:\n" );
fprintf ( stderr, "%d: Add new employee to database\n", ADD_CODE );
fprintf ( stderr, "%d: Delete employee from database\n", DELETE_CODE );
19
fprintf ( stderr, "%d: Print database to screen\n", PRINT_CODE );
fprintf ( stderr, "%d: Exit database program\n", EXIT_CODE );
fprintf ( stderr, "\nEnter option: " );
if ( read_line ( stdin, line, 300 ) != 0 ) continue;
result = sscanf ( line, "%d", &choice );
if ( result != 1 )
{
fprintf ( stderr, "corrupted menu choice\n" );
continue;
}
switch ( choice )
{
case ADD_CODE: /* add employee to database */
menu_add_employee();
break;
case DELETE_CODE: /* delete employee from database */
menu_delete_employee();
break;
case PRINT_CODE: /* print database contents to screen
(standard output) */
menu_print_database();
break;
/* exit */
case EXIT_CODE:
break;
default:
fprintf ( stderr, "illegal choice %d\n", choice );
break;
}
/* check for exit menu choice */
if ( choice == EXIT_CODE )
break;
}
return 0;
}