Due by 11:59 pm, Thursday, April 6, 2023

Your lab partner for Lab 7 is listed here: Lab 7 partners

Our guidelines for working with partners: working with partners, etiquette and expectations.

1. Lab Goals

  1. Practice using the C string library, both from the inside and out.

  2. Read manual ("man") pages to understand a function’s specification.

  3. Systematically write test cases to help ensure correct program behavior.

  4. Obtain additional experience with pointers, strings and memory layout, and dynamic memory allocation.

2. 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 (sorted alphabetically). Before you begin implementing these, spend some time considering the order in which you write them. Some of these are easier to write than others, and some of these functions may be needed to implement others.

  • 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.

3. Handy References

  • You can read up on some documentation on C libraries and header files.

  • Use the man command on the terminal to view the manual page for a function that you’re curious about using, e.g. man strlen. You can also use google by searching for "man strlen" to get the same information in a possibly-easy-to-read format.

    • Note: 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

4. Lab Starting Point Code

4.1. Getting Your Lab Repo

Both you and your partner should clone your lab repo into your cs31/labs subdirectory:

  1. 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.

  2. cd into your cs31/labs subdirectory:

    $ cd ~/cs31/labs
    $ pwd
  3. clone your repo

    $ git clone [your Lab7-userID1-userID2 url]
    $ cd Lab7-userID1-userID2
    $ ls
    Makefile        my_strings.c    my_strings.h    stringtester.c

4.2. Starting Point Code

The files included in your repo are:

  • Makefile: builds the my_strings.o object file and the stringtester 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.

5. Lab Requirements

  1. 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.

  2. 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.

  3. 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 in my_strings.c

  4. 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.

  5. For full credit, your solution should be well-commented, it should not use global variables, and it should be free of valgrind errors.

  6. 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.

6. 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:

    1. 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.

    2. 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 numerical 0 value corresponds to the end of a string.

    3. Think about how you might use one function to implement another. For example, you might want to use my_strlen inside of my_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.

7. 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-S23). 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.