$29
1 Introduction and purpose
In this project you will write some functions using structures to store simple information about elephants, because they are the most fascinating animals, so we should naturally want to be able to represent them in programs. The purpose of the project is to use basic structures as well as pointers to structures.
This project is shorter and much simpler than Project #3, and your code will not be graded for style. (However, if your style is poor and you need to visit office hours for help and the TAs look at your code but cannot understand it, they will just tell you that you have to clean it up before they can do anything, and come back when you have improved it.) Because of its relative ease, the project is being assigned with a short time to be done in. This is to give more time for the other projects that are more difficult. But because of the short time you need to start (and finish) the project right away.
Due to the size of the course it is not feasible for us to be able to provide project information or help via email/ELMS messages, so we will be unable to answer such questions. You are welcome to ask any questions verbally during the TAs’ office hours.
2 Functions to be written
The header file elephant.h in the project05.tgz tarfile contains the prototypes of the functions you are to write, as well as the definition of a structure with typedef name Elephant. An Elephant structure has four fields for the essential data that has to be stored for any elephant: elephant_type, which is an enum used to indicate what kind an elephant is; an unsigned int field id (any elephant naturally has a unique ID); an unsigned short field weight to store an elephant’s weight, and an all–important trunk_length field, which is a float used to represent the magnitude of an elephant’s majestic trunk.
There are several approaches for writing functions that operate upon structures in C:
1. Some functions have structures as parameters but do not modify those structures or need to return structures.
2. Another approach is passing a structure to a function or returning a structure from a function, which is what the function change_weight() did in the lecture example passing+returning-structure.c, as well as the function multiply_terms() in Worksheet #7. This approach copies the structure argument or return value, so it is not efficient if structures are large or the function is called many times. In this project one function returns a structure.
3. Another approach for structure functions is to pass a pointer to a structure to a function, so the function can follow the pointer to access or modify the structure that it points to. This is used for some functions in this project.
Another approach besides these uses concepts we have not covered yet so it is omitted here.
When you look at the public tests (as you should before starting to code) you will see that some of them declare structures whose addresses are passed into your functions. Some functions must examine or use the values of the fields of structures passed in, so it could cause errors if the fields had not previously been initialized. Consequently all of our tests declare Elephant structures and give their fields definite initial values (by calling one of your functions that will do this) before calling your other functions on the structures. Keep this in mind when writing your own tests of your functions.
(Some functions have parameters named el and some have parameters with names like el_ptr. These names are not extremely readable or descriptive but we used them anyway just to reduce the amount of typing you need to do when writing the functions. Although good–quality names help make code more understandable, since this project is not being graded for style and is being assigned with a shorter time to be done in, we erred on the side of shorter but less legible names. However, in projects where you are being graded for style you should err on the side of better names.)
2.1 Elephant new_elephant(enum type which_type, unsigned int id, unsigned short weight, float trunk_length)
This function should return an Elephant structure that has the values of its parameters stored in its fields (the field which_type in the structure’s elephant_type field, etc.). Although in real life there might be some validity constraints for a function like this (for example, a real elephant would be unlikely to have a weight of zero), this function should not do any checking of its parameters’ values. (In the functions below the only validity checks are specifically mentioned; other than the checks specifically mentioned the other functions also should not do any checking of their parameters’ values.)
© 2023 L. Herman; all rights reserved 1
2.2 unsigned short init_elephant(Elephant *const el_ptr, enum type which_type,
unsigned int id, unsigned short weight,
float trunk_length)
This function uses the approach of having a pointer to a structure as a parameter so the function can follow the pointer to access or modify the structure that it points to. It should have a similar effect to the previous function new_elephant() in giving values to all of an elephant’s fields, but operating instead upon an already–existing structure pointed to by its first pointer parameter el_ptr, instead of returning a structure. However, if el_ptr does not point to an existing structure because it is NULL, the function should just return 0 without changing anything. Otherwise it should store its last four parameters’ values into the structure pointed to by el_ptr and return 1.
Important: if el_ptr is not NULL then the caller is passing in the memory address of an existing Elephant structure that it declared before calling this function. This function just has to store values into the existing structure’s fields.
2.3 enum type get_type(Elephant el)
This function should return the value of its parameter el’s field elephant_type.
2.4 unsigned int get_id(Elephant el)
This function should return the value of its parameter el’s field id.
2.5 unsigned short get_weight(Elephant el)
This function should return the value of its parameter el’s field weight.
2.6 float get_trunk_length(Elephant el)
This function should return the value of its parameter el’s field trunk_length.
2.7 void print_elephant(Elephant el)
This function should print the values of the four fields in its Elephant structure el, in the same order they appear in the structure definition. The fields should be separated by a single blank space, but a space should not appear before the first field or after the last field; a newline should be printed after the last field instead. For convenience, the trunk_length field should be printed using the format specifier %g, not %f (some differences between these were mentioned earlier in the News feed). Either the word AFRICAN or ASIAN, in all uppercase letters, should be printed for the elephant_type field. (An enum is just an integer, but printing 0 or 1 is not that descriptive, and elephant–lovers would prefer to see one of these words instead.) Note that there is no automatic way to convert a C enum value from its integer representation to text like there is in Java. (One of the public tests illustrates the expected output format.)
2.8 unsigned short compare(Elephant e1, Elephant e2)
This function should return 1 if its two Elephant structure parameters have all the same values and 0 otherwise.
2.9 unsigned short change_id(Elephant *const el_ptr, unsigned int new_id)
An elephant might naturally need to change its ID at certain times, for example when it begins work at a new job. This function facilitates this process. It should change the id field of the Elephant structure that its first parameter points to, so it has the value new_id, and return 1. However, if its first parameter is NULL it should just return 0 without changing anything.
2.10 unsigned short copy(Elephant *const el_ptr1, const Elephant *const el_ptr2)
Sometimes in programming we need to make a copy of some data in another variable of the same type. This function should do that, by copying the values of the Elephant structure that el_ptr2 is pointing to into the structure that el_ptr1 is pointing to, and returning 1. However, if either parameter is NULL it should just return 0 without changing anything. (Note the different uses of const in the parameters.)
© 2023 L. Herman; all rights reserved 2
• Development procedure review
A.1 Obtaining the project files, compiling, checking your results, and submitting
Log into the Grace machines and use commands similar to those from before:
cd ~/216
tar -zxvf ~/216public/project05/project05.tgz
This will create a directory project05 that contains the files for the project, including the header file elephant.h and the public tests. You must have your coursework in your special course disk space for this class. Create a file in the project05 directory named elephant.c (spelled exactly that way) that will #include the header file elephant.h, and in it write the functions whose prototypes are in elephant.h.
A command like gcc public01.c elephant.c -o public01.x will compile your program for the first public test (or you can use Emacs to compile if desired); replace the 1s in the command with 2s for the second public test, etc. You can also use separate compilation, compiling each source file to form object files, which are then linked together. You are welcome to write a makefile to compile the public tests if you want, but if you do you are advised to compile your code at least once by hand before submitting, just in case any makefile errors would result in your code compiling on Grace but not on the submit server.
As before, use diff to compare the tests’ output to the public test outputs that are in the project tarfile, for example public01.x | diff - public01.output will test your code’s results on the first public test.
Running submit from the project directory will submit your project, but before you submit you must make sure you have passed all the public tests, by compiling and running them yourself. Unless you have versions of all required functions that will at least compile, your program will fail to compile at all on the submit server. (Suggestion– create skeleton versions of all functions when starting to code, that just have an appropriate return statement if they are non–void functions.)
A.2 Grading criteria
Your grade for this project will be based on:
public tests
100 points
• Project–specific requirements, suggestions, and other notes
◦ You cannot modify anything in the header file elephant.h or add anything to elephant.h, because your submission will be compiled on the submit server using our version of this file.
Your code may not comprise any source (.c) files other than elephant.c, so all your code must be in that file. You cannot write any new header files of your own either.
Do not write a main() function in elephant.c, because your code won’t compile (our tests already have main() functions). Write any tests in your own separate source files, and compile them together with elephant.c.
◦ You can only use the C language features that have been covered in class up through Chapter 10 in the Reek text.
◦ For this project you will lose one point from your final project score for every submission that you make in excess of four submissions. You will also lose one point for every submission that does not compile, in excess of two noncompiling submissions. Therefore be sure to compile, run, and test your project’s results before submitting it. Hopefully everyone will check their code themselves carefully, and avoid these penalties.
If your code compiles on Grace but not on the submit server, you may have changed the header file elephant.h which you were not supposed to do, or something in your account setup may be wrong. Run check-account-setup and come to the TAs’ office hours for help if you can’t fix any problems that it identifies on your own. (Other causes of this could be: you put your code in a subdirectory of the project05 directory, you added source or header files, or you wrote a makefile but it is not fully correct.)
If your code passes tests on Grace but not on the submit server, remember that uninitialized variables can cause C programs to work differently on different machines or different times they’re compiled. Recall that you can run check-vars on a program compiled with the -g option to detect use of uninitialized variables.
© 2023 L. Herman; all rights reserved 3
• If you have a problem with your code and come to the TAs’ office hours, you must have used the gdb debugger, explained recently in discussion section, and be prepared to show the TAs how you attempted to debug your program using it and what results you got.
• Academic integrity
Please carefully read the academic honesty section of the syllabus. Any evidence of impermissible cooperation on projects, use of disallowed materials or resources, publicly providing others access to your project code online, or unauthorized use of computer accounts, will be submitted to the Office of Student Conduct, which could result in an XF for the course, or suspension or expulsion from the University. Be sure you understand what you are and what you are not permitted to do in regards to academic integrity when it comes to projects. These policies apply to all students, and the Student Honor Council does not consider lack of knowledge of the policies to be a defense for violating them. More information is in the course syllabus– please review it now.
The academic integrity requirements also apply to any test data for projects, which must be your own original work.
Exchanging test data or working together to write test cases is also prohibited.
© 2023 L. Herman; all rights reserved 4