$34.99
1.1 Purpose
The purpose of this assignment is to introduce you to basic C programming, building on your knowledge of assembly. This assignment will familiarize you with C syntax and how to compile, run, and debug C programs. You will become familiar with how to work with strings, arrays, pointers, and structs in C. You will understand the relationship in C between arrays and pointers, including pointer arithmetic (think about how arrays are stored in memory in assembly). You will also become familiar with how to use a Makefile to automate the compilation of your program.
1.2 Task
In this assignment, you will be the (technologically savvy) manager of your own zoo, using your knowledge of the C programming language to take care of and manage your animals.
You will write C functions to add, remove, and update animals, collect data on how hungry certain animals are, as well as sort the animals in your zoo. For some functions you will have to return whether the function executed successfully (1) or unsuccessfully (0). See the Detailed Instructions section for more details on the specific requirements for each function.
You will write your C code in two files, my string.c and hw7.c. You must complete my string.c before hw7.c, as hw7.c will use the functions implemented in my string.c. In my string.c, you will write your own implementations of common C library functions for working with strings: strlen(), strncmp(), and strncpy(). In hw7.c, you will implement the functionality as mentioned above regarding the zoo. Please see the Detailed Instructions below for more, well, detailed instructions.
Take a look at the sections on Makefiles and Autograder for more info on how to compile and test your program.
1.3 Criteria
Your C code must compile without errors or warnings, using the provided Makefile. Your array of structs should be populated correctly at the end of the program. Your helper functions in my string.c must all be implemented correctly, producing the same behavior for test cases as the equivalent library functions from string.h.
2 Detailed Instructions
2.1 “my string.c” functions
The first part of this homework is to implement three very common C string library functions:
• my strlen: compute the length (excluding the null terminator) of a null-terminated string given a pointer to the first character of the string.
• my strncmp: compare two strings, up to at most n characters. Return a negative integer if the first string is less than the second string, zero if equal, and positive if greater. Some examples of string comparisons are below:
– ”bazz” < ”bog”
– ”rain” < ”rainforest”
• my strncpy: copy at most n characters from a source string to a destination memory location. If the null terminator is not included in the first n characters of source, the destination string should not be null terminated. If the length of source is less than n, you should fill in the remaining characters with null terminators.
The caveat is that you must implement these functions using only pointer notation. That is, you cannot use array indexing notation, such as str[i] = ‘a’. This restriction only applies in the my string.c file. We recommend implementing these functions first so you are able to use these functions as you move on with the assignment.
You will notice that many of the arguments in the my string.c and hw7.c files are of type const char *. This is a pointer to a char that is constant. This means that you cannot edit any of the characters to which a const char * points to. If you attempt to do so, using something like *pointer = ’c’, you will get a compile error. If const does not precede a char * declaration, you can edit the characters to which it points to.
In order to understand the functionalities of these three library functions, you need to take a look at their man page (i.e. manual page). See the section on Man Pages for more info.
What is size t:
size t is an unsigned integer datatype in C that represents the size of a variable in bytes. size t is used in the string library functions.
Some notes:
1. You should complete my string.c before moving on to hw7.c.
2. You are not allowed to use array notation in this file (e.g. s1[0]). All functions should be implemented using pointers and pointer arithmetic only! Think about how arrays and pointers correlate with each other in C. Again, this restriction only applies to this file.
3. You are not allowed to use any of the standard C string libraries (e.g. #include <string.h>).
4. Your string functions should not assume the length of any arguments passed in.
5. For my strncmp, you do not need to return a specific number, as long as it follows the description in the strncmp man page.
6. size t is an unsigned integer datatype typically used to represent the size or length of data, or any other unsigned quantity.
2.2 hw7.c
The second part of this homework is to implement several C functions within the hw7.c file. You will be primarily interacting with the global animals array as well as the global size variable. The animals array must not have gaps between animals (must be contiguous). You will use and update the size variable to keep track of the current number of animals within the animals array.
What is a struct animal:
Each animal in the zoo is represented using the struct animal struct defined in hw7.h:
struct animal { char species[MAX_SPECIES_LENGTH]; char habitat[MAX_HABITAT_LENGTH];
int id;
double hungerScale;
};
Each struct animal contains four member variables:
• species is a string (represented as a null-terminated array of characters) which stores the name of the animal’s species (e.g. [’T’,’i’,’g’,’e’,’r’,’’]).
• habitat is a string (represented as a null-terminated array of characters) which stores the name of the habitat the animal lives in (e.g. [’R’,’a’,’i’,’n’,’f’,’o’,’r’,’e’,’s’,’t’,’’]).
• id is an integer which uniquely identifies each animal, it is guaranteed that no two animals have the same id.
• hungerScale is a double which represents how hungry the animal is, higher hungerScale means the animal is more hungry.
What is the animals array:
The animals array is defined at the top of hw7.c. animals is an array of all the animals in the zoo, and contains struct animal structs as its elements:
struct animal animals[MAX_ANIMAL_LENGTH];
Whenever ”animals array” is mentioned in this pdf, it is referring to this array. All of the functions described below either read or write to this array in some way.
What is size v.s. MAX ANIMAL LENGTH:
size is defined at the top of hw7.c as a global integer variable. size stores the number of animals currently in the animals array:
int size = 0;
Whenever ”size” is mentioned in this pdf, it is referring to this variable. If any of the functions described below add or remove animals from size, you are responsible for also updating size to match the new number of animals in the animals array.
MAX ANIMAL LENGTH is a macro defined in hw7.h that represents the maximum number of animals that can be stored in the animals array.
Functions to Implement:
• int addAnimal(const char *species, int id, double hungerScale, const char *habitat):
In this function, you will add an animal struct with the given species, id, hungerScale, and habitat to the end of the animals array.
– If the given species name’s length (including the null terminator) is above MAX SPECIES LENGTH, truncate the name to be MAX SPECIES LENGTH (including the null terminator). Be mindful of how strings are represented in C!
– If the given habitat name’s length (including the null terminator) is above MAX HABITAT LENGTH, truncate the name to be MAX HABITAT LENGTH (including the null terminator). Be mindful of how strings are represented in C!
– If the animal’s species length is 0, habitat length is 0, or adding the new animal would make size exceed MAX ANIMAL LENGTH, do not create or add the animal to animals.
– Return SUCCESS if you are able to successfully create and add the animal, otherwise return FAILURE.
• int updateAnimalSpecies(struct animal animal, const char *species):
In this function, you will update an animal so that their species is updated to the species parameter passed into this function. The animal to be updated will be the animal in the animals array with the same id as the passed in animal. It is guaranteed that no two animals have the same id.
– If the updated species name’s length (including the null terminator) is above MAX SPECIES NAME SIZE, truncate the nickname to be MAX SPECIES NAME SIZE (including the null terminator).
– If you are able to successfully update the animal’s nickname, return SUCCESS, if you are unable to find the animal based on its id, return FAILURE.
• double averageHungerScale(const char *species):
In this function, you will calculate the average hunger of all the animals in your animals array with the same species as the passed in species parameter so that you know when to feed them. You should return the average hungerScale of these animals as a double.
– If there are no animals in animals who match the passed in species, you should return 0.
• int swapAnimals(int index1, int index2):
In this function, you will swap the position of an animal at index1 with the position of the animal at index2.
– If the indices are negative or beyond the current size of the animals array, do not swap.
– If the animals were successfully swapped, return SUCCESS. Otherwise, return FAILURE;
• int removeAnimal(struct animal animal):
In this function, you will remove an animal with the same id as the passed in animal struct (note: each animal has a unique id). You must maintain array contiguity when removing. This means that there must be no gaps between animals within the animals array after removing. You must also maintain the current ordering of the animals array after removal.
– If there is no animal in the animals array with the same id as the passed in animal, do not remove any animals.
– On successful removal, return SUCCESS. If you cannot find the animal with the given id, return FAILURE.
• int compareHabitat(struct animal animal1, struct animal animal2):
In this function, you will compare two habitats by which comes first lexicographically by habitat name. If habitat1 is less than habitat2, return a negative number. If it is greater, return a positive number. If habitat1 equals habitat2, then return 0 (remember that in lexicographic order, ”pasture” is less than ”pastureland”).
• void sortAnimalsByHabitat(void):
In this function, you will sort the animals array of animals using any sorting algorithm of your choice. The result should be in ascending order. An animal comes before another animal if its habitat is less than the other’s according to compareHabitat. If two animals have the same habitat, then the animal with the greater hungerScale should come first. If two animals have the same habitat and hungerScale, then they are considered equal and either can come first (It will helpful to use compareHabitat and swapAnimals as helper functions).
2.3 hw7.h
A header file is a C file (by convention with the extension .h) that contains function prototypes, struct definitions, as well as macros. Header files are useful so that we can separate these declarations and definitions from our main C code and later include them in other files. You can see in the code that hw7.c includes hw7.h, its header file.
Before getting started with this homework make sure to get familiar with what’s provided in hw7.h. Here is some of what’s defined in hw7.h:
• struct animal: This struct definition is how animals are represented in this homework.
• Prototypes for functions like addAnimal in hw7.c. By including these at the top of hw7.c, we prevent errors from using a function before it is defined.
• Macros for constants such as MAX SPECIES LENGTH, which is defined as 10, the maximum length an animal’s species variable can be.
3 Useful Tips
3.1 Man Pages
The man command in Linux provides “an interface to the on-line reference manuals.” If you are unsure about the specifics of a my string.c function, you should look up the exact details using its man page. This is a great utility for any C and Linux developer for finding out more information about the available functions and libraries. In order to use this, you just need to pass in the function name to this command within a Linux (in our case Docker) terminal.
For instance, entering the following command will print the corresponding man page for the strlen function:
$ man strlen
Additionally, the man pages are accessible online at: http://man.he.net
NOTE: You can ignore the subsections after the “RETURN VALUE” (such as ATTRIBUTES, etc) for this homework, however, pay close attention to function descriptions.
3.2 Debugging with GDB and printf
We highly recommend getting used to “printf debugging” in C early on.
Side Note: Get used to GDB early on as it will come in handy in any C program you will write for the rest of 2110, and even in the future!
When running GDB, if you get to a point where user input is needed, you can supply it just like you normally would. When an error happens, you can get a Java-esque stack trace using the backtrace(bt) command which allows you to pinpoint where the error is coming from. For more info on basic GDB commands, search up “GDB Cheat Sheet.”
4 Checking Your Solution
4.1 Makefiles
Make is a common build tool for abstracting the complexity of working with compilers directly. In fact, the PDF you’re reading now was built with a Makefile! Makefiles let you define a set of desired targets (files you want to compile), their prerequisites (files which are needed to compile the target), and sets of directives (commands such as gcc, gdb, etc.) to build those targets. In all of our C assignments (and also in production level C projects), a Makefile is used to compile C programs with a long list of compiler flags that control things like how much to optimize the code, whether to create debugging information for gdb, and what errors we want to show. We have already provided you a Makefile for this homework, and although you are not being tested on it, we highly recommend that you take a look at this file and understand the gcc commands and flags used to understand how to compile C programs. If you’re interested, you can also find more information regarding Makefiles here.
Since your program is connected to an autograder with multiple files that need to be compiled using particular settings, it’s a little difficult to compile it by hand. To help you out with compiling and running tests, we’ve provided you with a Makefile. The Makefile allows us to simply type the command make followed by a target such as tests, run-case, or run-gdb to compile and run your code.
4.2 Autograder
To test your code manually, compile your code using make and run the resulting executable file with the command-line arguments of your choice.
Keep in mind that you should run all commands inside the Docker terminal in the same directory as the Makefile. We highly recommend running the usual script with -it to get a terminal inside Docker without needing to use the browser window:
./cs2110docker.sh -it
If you use your own Linux distribution/VM, make sure you have the check unit test framework installed. However, keep in mind that your code will be tested on Docker.
To run the autograder locally (without GDB):
# To clean your working directory (use this instead of manually deleting .o files) $ make clean
# Compile all the required files
$ make tests
# Run the tester executable
$ ./tests
The above commands will run all the test cases and print out a percentage, along with details of the failed test cases. If you want to debug a failed test case, see below.
Commands to run/debug a specific failing test case:
• To run specific tests without gdb:
# Run all tests
$ make run-case
# Run a specific test
$ make run-case TEST=testCaseName
• To run specific tests with gdb:
# Run all tests in gdb $ make run-gdb
# Run a specific test in gdb
$ make run-gdb TEST=testCaseName
Example error message: suites/hw7_suite.c:646:F:test_removeAnimal_basic_1: ...
Example command: make run-gdb TEST=test_removeAnimal_basic_1
4.3 Manual Testing
Here is how to manually run your main.c code.
# Clean up all compiled output
$ make clean
# Recompile the hw7 executable
$ make hw7
# Run the hw7 executable
$ ./hw7
Important Notes:
1. The output file will ONLY be graded on Gradescope.
2. All non-compiling homework will receive a zero (with all the flags specified in the Makefile/Syllabus).
3. NOTE: DO NOT MODIFY THE HEADER FILES.
You must place any code elements you define (structs, macros, function declarations, etc.) in the C FILES. Usually placing those definitions in .h files would be good practice, but for this assignment you are not turning them in, and so the declarations would be lost when submitting.
Many test cases are randomly generated and your code should work every time we run the autograder on it, however, there’s no need to submit to Gradescope multiple times once you get the desired grade.
We reserve the right to update the autograder and the test case weights on Gradescope or the local checker as we see fit when grading your solution.
5 Deliverables
Please upload the following files to Gradescope:
1. my_string.c
2. hw7.c
Note: Please do not wait until the last minute to run/test your homework; history has proven that last minute turn-ins will result in long queue times for grading on Gradescope. You have been warned.
6 Appendix
6.1 Appendix D: Rules and Regulations
6.1.1 General Rules
1. Starting with the assembly homeworks, any code you write should be meaningfully commented for your benefit. You should comment your code in terms of the algorithm you are implementing; we all know what each line of code does.
3. Please read the assignment in its entirety before asking questions.
5. If you find any problems with the assignment, it would be greatly appreciated if you reported them to the TAs. Announcements will be posted if the assignment changes.
6.1.2 Submission Conventions
1. Unless otherwise noted, all files you submit for assignments should have your name somewhere near the top of the file as a comment.
3. Do not submit compiled files (.class files for Java code or .o files for C code). Only submit the files we ask for in the assignment.
4. Do not submit links to files. The autograder will not understand it, and we will not manually grade assignments submitted this way, as it is easy to change the files after the submission period ends.
6.1.3 Submission Guidelines
2. You are responsible for ensuring that you have turned in the correct files. After submitting, be sure to download your submission into a brand new folder and test that it works. What you turn in is what we grade; there are no excuses if you submit the wrong files. In addition, your assignment must be turned in via Canvas/Gradescope. Under no circumstances whatsoever will we accept any email submissions of assignments (Note: if you were granted an extension, you will still turn in the assignment over Canvas/Gradescope).
6.1.4 Syllabus Excerpt on Academic Misconduct
Academic misconduct is taken very seriously in this class. Quizzes, timed labs and the final examination are individual work.
Homework assignments are collaborative. In addition, many, if not all, homework assignments will be evaluated via demo or code review. During this evaluation, you will be expected to be able to explain every aspect of your submission. Homework assignments will also be programatically examined to find evidence of unauthorized collaboration.
You are expressly forbidden to supply a copy of your homework to another student via electronic means. This includes simply emailing it to them so they can look at it. If you supply an electronic copy of your homework to another student, and they are charged with copying, you will also be charged. This includes storing your code on any site which would allow other parties to obtain your code, including, but not limited to, public repositories (GitHub), Pastebin, etc. If you would like to use version control, use github.gatech.edu.
6.1.5 Is collaboration allowed?
Figure 1: Collaboration rules, explained colorfully