15-213, Summer 2022
C Programming Lab: Assessing Your C Programming Skills
1 Logistics
There are no late days, grace days, or extensions for this assignment. Start early enough to get it done before the due date. Assume things will not go according to plan, and so you must allow extra time for heavily loaded systems, dropped Internet connections, corrupted files, traffic delays, minor health problems, etc.
A well-prepared student can complete the assignment in 1–2 hours, but it may require longer if you have not done much C programming. If you are not yet registered for the course, you can request an Autolab account and complete the assignment on schedule.
This is an individual project. All handins are electronic. You should work on this assignment on the Shark machines. Please see http://www.cs.cmu.edu/~213/labmachines.html for more information on how to access these machines. The testing for your code will be done using Autolab, using OS and compiler configurations similar to those on the Shark machines. We advise you to test your code on the Shark machines before submitting it.
Before you begin, please take the time to review the course policy on academic integrity at http://www.cs.cmu.edu/~213/academicintegrity.html.
2 Overview
This lab will give you practice in the style of programming you will need to be able to do proficiently, especially for the later assignments in the class. The material covered should all be review for you. Some of the skills tested are:
• Explicit memory management, as required in C.
• Creating and manipulating pointer-based data structures.
• Working with strings.
• Enhancing the performance of key operations by storing redundant information in data structures.
• Implementing robust code that operates correctly with invalid arguments, including NULL pointers.
The lab involves implementing a queue, supporting both last-in, first-out (LIFO) and first-in-first-out (FIFO) queueing disciplines. The underlying data structure is a singly-linked list, enhanced to make some of the operations more efficient.
3 Resources
Here are some sources of material you may find useful:
1. C programming. Our recommended text is Kernighan and Ritchie, The C Programming Language, second edition. Copies are on reserve in the Sorrells Engineering Library. For this assignment, Chapters 5 and 6 are especially important. There are good online resources as well, including: https: //en.wikibooks.org/wiki/C_Programming
- Linked lists. You can consult the lecture materials for 15-122: https://www.cs.cmu.edu/~15122/handouts/10-linkedlist.pdf
- Asymptotic (big-O) notation. If you are unsure what “O(n)” means, consult the lecture materials for 15-122:
https://www.cs.cmu.edu/~15122/handouts/05-bigo.pdf
- Linux Man pages. The authoritative documentation on a library function FUN can be retrieved via the command “man FUN.” Some useful functions for this lab include:
Memory management: Functions malloc and free.
String operations: Functions strlen, strcpy, and strncpy. (Beware of the behavior of strncpy
when truncating strings!)
The Linux man pages can also be viewed online at https://man7.org/linux/man-pages/.
Be sure to follow posts on Piazza providing clarifications and updates on the assignment.
As the Academic Integrity Policy states, you should not search the web or ask others for solutions or advice
on the lab. That means that search queries such as “linked-list implementation in C” are off limits. 4 Logging in to Autolab
All 213/513 labs are being offered this term through a Web service developed by CMU students and faculty called Autolab. Before you can download your lab materials, you will need to update your Autolab account. Point your browser at the Autolab front page: https://autolab.andrew.cmu.edu
You will be asked to authenticate via Shibboleth. After you authenticate the first time, Autolab will prompt you to update your account information with a nickname. Your nickname is the external name that identifies you on the public scoreboards that Autolab maintains for each assignment, so pick something interesting! You can change your nickname as often as you like. Once you have updated your account information, click on
“Save Changes” button, and then select the “Home” link to proceed to the main Autolab page.
You must be enrolled to receive an Autolab account. If you added the class late, you might not be included in Autolab’s list of valid students. In this case, you won’t see the 213 course listed on your Autolab home page. If this happens, contact the staff and ask for an account.
2
If you are still on the waitlist for the course, then download a copy of the archive file (described below) from the course schedule web page. You can get working on the lab and then get an Autolab account once you are enrolled.
5 Downloading the assignment
For all assignments in this class, you should do all your programming and testing using one of the Shark machines, which you can access via an SSH connection. The starter code and testing scripts that we give you are not guaranteed to work anywhere but the Shark machines. You can find a list of all the Shark machines at http://www.cs.cmu.edu/~213/labmachines.html. The Linux Bootcamp will cover using SSH and related topics in greater detail.
To begin working on this assignment, start by creating a directory for this course in a subdirectory of your AFS home directory that is accessible only by you. New Andrew accounts start out with a subdirectory with appropriate access control settings called ~/private, so if you have that directory, these commands are sufficient:
shark$ mkdir ~/private/15213 shark$ cd ~/private/15213
If you don’t have the ~/private directory and don’t know how to create a subdirectory that is accessible only by you, contact the Andrew helpdesk for instructions.
Once you are inside the 15213 directory, use the autolab command to download the starter code: shark$ autolab download 15213-m22:cprogramminglab
You may be prompted to authenticate; follow the instructions. This will create a deeper subdirectory named cprogramminglab containing two files:
shark$ cd cprogramminglab
shark$ ls
cprogramminglab-handout.tar cprogramminglab.pdf
cprogramminglab.pdf is another copy of this writeup; cprogramminglab-handout.tar contains the files you need. Extract them with these commands:
clang cprogramminglab.pdf console.c driver.py
For this lab, you will only need to modify queue.h and queue.c. If you like, you may modify the hidden file .clang-format so that “make format” applies your preferred style. Don’t modify any other files! If you do, the autograder will ignore those modifications and your code probably won’t compile.
shark$ tar --strip=1 -xf cprogramminglab-handout.tar shark$ rm cprogramminglab-handout.tar
shark$ ls
check-format console.h
harness.c Makefile queue.h report.h harness.h qtest.c README traces helper.mk queue.c report.c
3
Queue
head
Additional fields
List head List tail
63616200 6265616400 63616200
cab bead cab
Figure 1: Linked-list implementation of a queue. Each list element has a value field, pointing to an array of characters (C’s representation of strings), and a next field pointing to the next list element. Characters are encoded according to the ASCII encoding (shown in hexadecimal.)
6 Overview
The file queue.h contains declarations of the following structures:
/* Linked list element */ typedef struct list_ele {
char *value;
struct list_ele *next; } list_ele_t;
/* Queue structure */
typedef struct {
list_ele_t *head; /* First element in the queue */ } queue_t;
These are combined to implement a queue of strings, as illustrated in Figure 1. The top-level representation of a queue is a structure of type queue_t. In the starter code, this structure contains only a single field head, but you will want to add other fields. The queue contents are represented as a singly-linked list, with each element represented by a structure of type list_ele_t, having fields value and next, storing a pointer to a string and a pointer to the next list element, respectively. The final list element has its next pointer set to NULL. You may add other fields to the structure list_ele, although you need not do so.
Recall that a string is represented in C as an array of values of type char. In most machines, data type char is represented as a single byte. To store a string of length l, the array has l + 1 elements, with the first l storing the codes (typically ASCII1 format) for the characters and the final one being set to 0. The value field of the list element is a pointer to the array of characters. The figure indicates the representation of the list [“cab”, “bead”, “cab”], with characters a–e represented in hexadecimal as ASCII codes 61–65. Observe how the two instances of the string “cab” are represented by separate arrays—each list element should have a separate copy of its string.
In our C code, a queue is a pointer of type queue_t *. We distinguish two special cases: a NULL queue is one for which the pointer has value NULL. An empty queue is one pointing to a valid structure, but the head field has value NULL. Your code will need to deal properly with both of these cases, as well as queues containing one or more elements.
1Short for “American Standard Code for Information Interchange,” developed for communicating via teletype machines. 4
7 Programming Task
Your task is to modify the code in queue.h and queue.c to fully implement the following functions.
queue_new: Create a new, empty queue.
queue_free: Free all storage used by a queue.
queue_insert_head: Attempt to insert a new element at the head of the queue (LIFO discipline). queue_insert_tail: Attempt to insert a new element at the tail of the queue (FIFO discipline). queue_remove_head: Attempt to remove the element at the head of the queue.
queue_size: Compute the number of elements in the queue.
queue_reverse: Reorder the list so that the queue elements are reversed in order. This function should not allocate or free any list elements (either directly or via calls to other functions that allocate or free list elements.) Instead, it should rearrange the existing elements.
More details can be found in the comments in these two files, including how to handle invalid operations (e.g., removing from an empty or NULL queue), and what side effects and return values the functions should have.
For functions that provide strings as arguments, you must create and store a copy of the string by calling malloc to allocate space (remember to include space for the terminating character) and then copying from the source to the newly allocated space. When it comes time to free a list element, you must also free the space used by the string. You cannot assume any fixed upper bound on the length of a string—you must allocate space for each string based on its length. Note: malloc, calloc, and realloc are the only supported functions in this lab for memory allocation, any other functions that allocate memory on the heap may cause you to lose points.
Two of the functions, queue_insert_tail and queue_size, will require some effort on your part to meet the required performance standards. Naive implementations would require O(n) steps for a queue with n elements. We require that your implementations operate in time O(1), i.e., that the operation will require only a fixed number of steps, regardless of the queue size. You can do this by including other fields in the queue_t data structure and managing these values properly as list elements are inserted, removed and reversed. Please work on finding a solution better than the O(n2) solution for all of the functions.
Your program will be tested on queues with over 1,000,000 elements. You will find that you cannot operate on such long lists using recursive functions, since that would require too much stack space. Instead, you need to use a loop to traverse the elements in a list.
8 Testing
You can compile your code using the command:
shark$ make
If there are no errors, the compiler will generate an executable program qtest, providing a command interface with which you can create, modify, and examine queues. Documentation on the available commands can be found by starting this program and running the help command:
shark$ ./qtest cmd> help
The following file (traces/trace-eg.cmd) illustrates an example command sequence, which you can type into the qtest program:
# Demonstration of queue testing framework # Initial queue is NULL.
show
# Create empty queue
new
# Fill it with some values. First at the head ih dolphin
ih bear
ih gerbil
# Now at the tail
it meerkat
it bear
# Reverse it
reverse
# See how long it is
size
# Delete queue. Goes back to a NULL queue. free
# Exit program
quit
You can also run qtest on an entire trace file all at once, as follows:
shark$ ./qtest -f traces/trace-eg.cmd # This is the example trace.
shark$ ./qtest -f traces/trace-01-ops.cmd # This is the first real trace.
If you try to test the starter code, you will see that it does not implement many of the operations properly.
The traces directory contains 15 trace files, with names of the form trace-k-cat.txt, where k is the trace number, and cat specifies the category of properties being tested. Each trace consists of a sequence of commands, similar to those shown above. They test different aspects of the correctness, robustness, and performance of your program. You can use these, your own trace files, and direct interactions with qtest to test and debug your program.