1. Due Date
Due by 11:59 pm, Tuesday, Nov. 9, 2021
Your lab partner for Lab 7 is listed here: Lab 7 partners
Our guidelines for working with partners: working with partners, etiquette and expectations
2. Lab Goals
-
Practice using the C string library, both from the inside and out.
-
Systematically write test cases to help ensure correct program behavior.
-
Obtain additional experience with pointers, strings and memory layout, and dynamic memory allocation.
3. Lab Overview
For this lab, you will implement your own version of the core functions in C’s string processing library.
In C, strings are just blocks of memory (e.g., static arrays, or a dynamically allocated block of bytes) that contain one character after another and are terminated with a special null-termination marker.
The functions in the string library abstract the details of memory and
null-termination from the user to make strings less painful to use.
Unfortunately, while they’re much better than nothing, the functions
are still quite low-level. For example, you cannot concatenate
strings with a +
operator like you can in many other languages, and
using strcat
requires that the user allocates and provides
sufficient memory.
Since strings are everywhere, it’s extremely likely that you will find yourself using these functions frequently. A great way to learn how they work is to implement them yourself, so that’s what we will be doing in this lab!
You will be implementing the following functions:
-
strcat
-
strchr
-
strcmp
-
strcpy
-
strdup
-
strlen
-
strstr
Once you’ve written your implementation of these functions, you’ll write a small number of test cases for each to compare your version with that of the built-in C library. This should help you to convince yourself that your implementation is correct.
4. Handy References
-
Use the
man
command on the terminal to view the manual page for a function that you’re curious about using.-
If you prefer to look at manual pages on the web, linux.die.net has an archive of documentation (e.g., strlen).
-
In general though, it’s better to get the manual from your system, since that better reflects the reality of the environment you’re working within. Another system might implement a function slightly differently, and if you’re reading the manual online, who knows which version you’re looking at?
-
-
Here is example of how to view the
strlen
manual page from the command-line:
$ man strlen
5. Lab Starting Point Code
5.1. Getting Your Lab Repo
Both you and your partner should clone your lab repo into
your cs31/labs
subdirectory:
-
get your Lab ssh-URL from the CS31 git org. The repository to clone is named Lab7-userID1-userID2, where user1 and user2 are the user names of you and your Lab partner.
-
cd into your
cs31/labs
subdirectory:$ cd ~/cs31/labs $ pwd
-
clone your repo
$ git clone [your Lab7-userID1-userID2 url] $ cd Lab7-userID1-userID2 $ ls Makefile my_strings.c my_strings.h stringtester.c
5.2. Starting Point Code
The files included in your repo are:
-
Makefile
: builds themy_strings.o
object file and thestringtester
executable file -
my_strings.c
: starting point for your implementation of the string library. Your solution goes here. -
my_strings.h
: the header files for your implementation of the string library. You should not modify this file. -
stringtester.c
: code that demonstrates correctness of your implementation of the string library. You will need to write at least two test cases for each library function.
6. Lab Requirements
-
For each function, your implementation (in
my_strings.c
) should behave exactly as the C library’s version does (when given valid inputs). This includes matching the C library’s argument types and ordering, return value, location of null-terminators, and final state of memory. Read the manual pages to get a formal specification for each function. -
For each function, you should write two or more documented test cases in
stringtester.c
to demonstrate that your version of the function is working as expected. To the extent that you can, you should vary the tests to make them cover different situations that may arise while using your library. -
Your test cases should compare directly against the C string library. It’s fine to make C string library calls inside of
stringtester.c
, but you CAN NOT use any function from strings.h in your implementation inmy_strings.c
-
You should avoid copy-pasting code as much as possible. If you find yourself needing to perform the same operation in more than one function and it’s more than a couple of lines long, write a helper function. The helper function need not be exported as part of the library, it can be a private function for your library to use.
-
For full credit, your solution should be well-commented, it should not use global variables, and it should be free of valgrind errors.
-
Your library should not print any output except in cases where the standard C library also prints output. (I’m not aware of any). It’s fine if you want to include some printing to help you debug your program, but you must remove output from your library prior to submitting it.
7. Tips
-
Test your code in small increments. It’s much easier to localize a bug when you’ve only changed a few lines. You don’t need to write every function before you start working on test cases—you may find it beneficial to write them before moving to the next library function.
-
In many functions, you may need to check for the special end-of-string null-terminator character. There are two ways to represent the null terminator:
-
As a character, the null-terminator is
\0
. The\
indicates that it’s a special character, much like you use the\n
character for a newline or\t
to insert a tab. -
As a numerical value (recall that characters are one-byte numbers defined by ASCII), the null-terminator is
0
. Since characters are represented as 8-bit integers in hardware, an 8-bit numerical0
value corresponds to the end of a string. -
Think about how you might use one function to implement another. For example, you might want to use
my_strlen
inside ofmy_strcat
to tell you where the end of the first string is. Re-using code in this manner will cut down on the total amount of code that you have to write, and it’ll make your code easier to reason about and debug.
-
8. Submitting your Lab
Please remove any debugging output prior to submitting.
To submit your code, commit your changes locally using git add
and
git commit
. Then run git push
while in your lab directory.
Only one partner needs to run the final git push
, but make sure both
partners have pulled and merged each others changes.
Also, it is good practice to run make clean
before doing a git add and
commit: you do not want to add to the repo any files that are built by gcc
(e.g. executable files). Included in your lab git repo is a .gitignore file
telling git to ignore these files, so you likely won’t add these types of files
by accident. However, if you have other gcc generated binaries in your repo,
please be careful about this.
Here are the commands to submit your solution and tester (from
one of you or your partner’s ~/cs31/labs/Lab7-userID1-userID2
subdirectory):
$ git add my_strings.c stringtester.c
$ git commit -m "Lab7 completed"
$ git push
Verify that the results appear (e.g., by viewing the the repository on CS31-F21). You will receive deductions for submitting code that does not run or repos with merge conflicts. Also note that the time stamp of your final submission is used to verify you submitted by the due date, or by the number of late days that you used on this lab, so please do not update your repo after you submit your final version for grading.
If you have difficulty pushing your changes, see the "Troubleshooting" section and "can’t push" sections at the end of the Using Git for CS31 Labs page. And for more information and help with using git, see the git help page.
At this point, you should submit the required Lab 7 Questionnaire (each lab partner must do this).