Handy References
- Libraries
and header file documentation.
- 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?
Lab 7 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.
Lab Description
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.
These library functions 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'll find
yourself using these functions frequently. A great way to learn how they work
is to implement them yourself, so that's what we'll be doing in this lab.
You'll 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.
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.
- Test cases should compare directly against C library. It's fine to make C
string library calls inside of stringtester.c, but you should NOT use
any function from strings.h in your implementation in
my_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 please remove output
from your library prior to submitting it.
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 numerical 0 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 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.
Submitting
Please remove any debugging output prior to submitting.
To submit your code, simply 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 push, but make sure both
partners have pulled and merged each others changes. See the section on Using a shared repo on the git help page.