$25
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 managing a fictional class of students and ensuring that the administration of students goes smoothly.
You will write C functions to add a student, remove a student, update a student’s information, compare students, as well as sort the class of students. Your job is to make sure that certain rules are being followed and for some functions you will have to signal whether or not it completed successfully. 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. 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 class of students. Please see the Detailed Instructions below for more, well, detailed instructions.
Take a look at the sections on Makefiles and Testing and Example Output for more info on how to compile and test your program.
While doing the homework, you may find it helpful to draw diagrams of memory locations, as you did with assembly programming. How are arrays represented in memory? How can you use pointers to find the address of array[i]? How are arguments passed to a function and results returned using the stack frame? Remember, C functions are pass by value (push copies of the values of arguments on the stack), just like subroutines in assembly.
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 of a null-terminated string
• my strncmp: compare two strings, up to at most n characters
• my strncpy: copy at most n characters from a source string to a target memory location
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.
Some notes:
1. You are NOT allowed to use array notation in this file. All functions should be implemented using pointers only! Think about how arrays and pointers correlate with each other in C. Again, this restriction only applies to this file.
2. You are NOT allowed to use any of the standard C string libraries (e.g. #include <string.h>).
3. Although expressions passed in to this program have a min/max length, the string functions should not have a boundary on any arguments passed in.
4. For my strncmp, you do not need to return a specific number, as long as it follows the description in the man page.
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 class array as well as the global size variable. The class array must not have gaps between students (must be contiguous). The size variable will be used to keep track of the number of students within the aforementioned array. You should update this variable whenever appropriate. Additionally, you may assume that when giving a student ID, it will never exceed the maximum length as specified in the header file.
• addStudent(const char *name, int age, double gpa, const char *id):
In this function, you will add a student struct with the given name, age, gpa, and id to the end of the class array. If the given name’s length (including the null terminator) is above MAX NAME SIZE, truncate the name to be MAX NAME SIZE. Be mindful of how strings are represented in C! If the given id’s length is smaller than MIN ID SIZE, of if the student with the given name already exists in the class array, or if adding the student would cause the number of students to exceed the maximum size of the class, do not create and add the student. Return SUCCESS when you are able to successfully create and add the student, otherwise return FAILURE.
• updateStudentName(struct student s, const char * name):
In this function, you will update a student so that their name is updated to the name parameter passed into this function. The student to be updated will be the student in the class array with the same name as s. If the updated name’s length (including the null terminator) is above MAX NAME SIZE, truncate the name to be MAX NAME SIZE. If you are able to successfully update the student’s name, return SUCCESS. If you are unable to find the student, return FAILURE.
• swapStudents(int index1, int index2):
In this function, you will swap the position of a student at index1 with the position of the student at index2. If the indices are invalid (such as a negative index or an index beyond the current size of the class) do no swap. On successful swap, return SUCCESS. Otherwise, return FAILURE;
• removeStudent(struct student s):
In this function, you will remove a student with the name in the passed in student struct. You must maintain array contiguity when removing. This means that there must be no gaps between students within the class array. On successful removal, return SUCCESS. If you cannot find the student with the given information, return FAILURE.
• compareStudentID(struct student s1, struct student s2);:
In this function, you will compare two students by using the last three characters of their IDs. If the string formed out of the last three characters of s1 is greater than the string formed out of the last three characters of s2, return a positive value. If it’s less than, return a negative value. If equivalent, return 0.
• sortStudentByID(void));:
In this function, you will sort the class array of students by using any sorting algorithm of your choice. The result should be in ascending order. The ordering of the sorted array is determined by compareStudentID.
2.3 hw7.h
Within this file, you be provided with the function prototypes, the definition of the student struct, as well as various macros that you can use in your implementation of the functions in hw7.c.
2.4 Makefiles and Testing
If you want to write manual tests of your functions, you are allowed to modify main.c to make custom invocations of your program. For example, you may want to create a new helper method that will print out the contents of the class array within hw7.h, implement it hw7.c, and call it in main.c. However, if you choose to create extraneous helper methods to help debug make sure to remove them when submitting to the autograder. Editing main.c, however, should not interfere with the autograder.
Since your program is connected to an autograder, 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.
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, their prerequisites, and sets of directives 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. 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.
To test your code manually, compile your code using make and run the resulting object file with the commandline arguments of your choice.
Keep in mind that you should run all commands inside the Docker terminal. We highly recommend running the usual script as follows to immediately get a terminal:
./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.
Below is an example of manually testing your code.
# Clean up all compiled output
$ make clean
# Recompile the hw7 executable
$ make hw7
# Run the hw7 executable
$ ./hw7
3 Useful Tips
3.1 Man Pages
The man command in Linux provides “an interface to the on-line reference manuals.” 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 use to “printf debugging” in C early on.
Moreover, If you run into a problem when working on your homework, you can use the debugging tool, GDB, to debug your code! Former TA Adam Suskin made a series of tutorial videos which you can find here.
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. For more info on basic GDB commands, search up “GDB Cheat Sheet.”
4 Checking Your Solution
Important Notes:
1. All non-compiling homework will receive a zero (with all the flags specified in the Makefile/Syllabus).
2. 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.
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
This will run all the test cases and print out a percentage, along with details of the failed test cases.
Other available commands:
• To run tests without gdb:
# Run all tests
$ make run-case
# Run a specific test
$ make run-case TEST=testCaseName
• To run tests with gdb:
# Run all tests in gdb $ make run-gdb
# Run a specific test in gdb
$ make run-gdb TEST=testCaseName.