Assignment 08 - String Library
Assignment 08 - String Library
In this assignment, you'll create your own library of string functions. You'll have the opportunity to practice
manipulating strings and managing memory. Additionally, you'll learn the role of header and library files.
You may not call functions in string.h but you can use other code in the Standard C Library.
Additionally, you should write a driver which tests each of these functions on real data.
Returns 1 if all of the characters in the string are either upper- or lower-case letters of the alphabet. It
returns 0 otherwise
returns the number of positions in which s1 and s2 differ, i.e., it returns the number of changes that would
need to be made in order to transform s1 into s2, where a change could be a character substitution, an
insertion, or a deletion.
Shortens the string s to new_len. If the original length of s is less than or equal to new_len, s is unchanged
returns the index of the first occurence of n in the string h or -1 if it isn't found.
returns a pointer to the first occurence of n in the string h or NULL if it isn't found
returns 1 if s is NULL, consists of only the null character ('') or only whitespace. returns 0 otherwise.
Returns a new string consisting of all of the characters of s1 and s2 interleaved with each other. For
example, if s1 is "Spongebob" and s2 is "Patrick", the function returns the string "SPpaotnrgiecbkob"
Changes s so that the first letter of every word is in upper case and each additional letter is in lower case.
Compares s1 and s2 ignoring case. Returns a positive number if s1 would appear after s2 in the dictionary,
a negative number if it would appear before s2, or 0 if the two are equal.
Modifies s so that it consists of only its last n characters. If n is ≥ the length of s, the original string is
unmodified. For example if we call take_last("Brubeck" 5), when the function finishes, the original string
becomes "ubeck"
returns a new string based on s, but without any duplicate characters. For example, if s is the string,
"There's always money in the banana stand.", the function returns the string "Ther's alwymonitbd.". It is
up to the caller to free the memory allocated by the function.
Returns a new string consisting of the characters in s repeated x times, with the character sep in between.
For example, if s is the string all right, x is 3, and sep is , the function returns the new string all
right,all right,all right. If s is NULL, the function returns NULL. It is up to the caller to free any memory
allocated by the function.
Returns a copy of the string s, but with each instance of pat replaced with rep, note that len(pat) can be
less than, greater than, or equal to len(rep). The function allocates memory for the resulting string, and it is
up to the caller to free it. For example, if we call replace("Fiore X", "X", "sucks"), what is returned is the
new string Fiore sucks (but remember, pat could be longer than an individual character and could occur
multiple times).
Returns a string consisting of the first n strings in strs with the character c used as a separator. For
example, if strs contains the strings {"Washington", "Adams", "Jefferson"} and c is '+', the function
returns the string "Washington+Adams+Jefferson"
words is an array of string terminated with a NULL pointer. The function removes any empty strings (i.e.,
strings of length 0) from the array.
Returns an array of string consisting of the characters in s split into tokens based on the delimeter c,
followed by a NULL pointer. For example, if s is "I am ready for a nice vacation" and c is ' ', it returns {"I",
"am", "ready", "for", "a", "nice", "vacation", NULL}
while (*t!='\0')
t++;
return t-s;
}
Arch
Remember that we keep our function declarations in a header file, a .h file. Each of your functions should be in a
separate .c file (e.g., you'll have all_letters in a file called all_letters.c file, the num_in_range in a file called
num_in_range.c .
So you'll have:
A collection of .c files:
one for each function in the library
a test program
A single .h file, which includes the declarations for each of the functions in the library. This is #included by
each of the .c files.
This is just as we did with our little practice math library from class. Recall that the organization was:
We then compiled the .c files (without linking) by typing
gcc -c *.c
which created the .o object files, which we bound together to form a library using the ar command.
Generating the Library
To create the library file, we use the ar command. The syntax is:
ar rcs NameOfTheLibraryFileToCreate listOfFilesToIncludeInTheLibrary
Don't forget that you're including the binary files, i.e., the .o files, not your c source files.
So suppose you have all of your function .o files in a single directory, and you'd like to call your library file
libstr2107.a, you'd type:
ar rcs libstr2107.a *.o
if you see a list of your .o files, you've done it right. The library file name should begin lib and should have a .a
extension.
Note that at the end of the line, it's -l (lower case l, not the number 1), and it's just str2107 not libstr2107.a.
Deliverables
Please send your lab instructor a zip file containing all of your .c files, your .h file and your string library file
(your .a file). In order to help the TA keep track of everyone's files, please include your name in the name of the
tar file.
All of this about "The caller is responsible for freeing the memory ..." should tell you that inside the function you're
going to be allocating the memory for what's returned. Remember to use malloc (or calloc) and don't return a
pointer to local stack memory. For example, something like this:
char *func()
{
char str[50];
...
return str;
}
might compile, but it's wrong. str is allocated on func's stack, and the memory used by str will be likely be given
to some other function as the program continues to run. Instead, you'd do something like:
char *func()
{
char *str;
...
if ((str=malloc(50))==NULL) /* allocate 50 bytes and check */
return NULL; * to see if they were successfully */
* allocated */
...
return str;
}
As we've discussed in class, this is something that you didn't have to worry about in Java, because Java arrays
are allocated on the heap. Remember that the equivalent Java would be:
char[] func()
{
char str[] = new str[50];
...
return str;
}
and as we also said in class, Java's new operator serves the same purpose as C's malloc( )
string literals
Here's another thing that you didn't need to worry about in Java that might cause some headaches in C.
Remember that these two declarations are not exactly the same:
char *str01 = "What time does class end?";
char str02[] = "What time does class end?";
They both look the same when you print them, but if you try to modify str01, you'll get in trouble. The memory
that str01 points to is read-only. str02 isn't, but it's only as much space as is required to hold the letters 'W', 'h',
'a', ..., and the null character ('\0').
None of this is likely to be a big deal in any of the functions you write, but it might come up when you're trying to
test a function. For example, something like:
char *str01 = " Where's the remote control? ";
...
strip(str01);
will give you a segmentation fault, but this doesn't necessarily mean that there's a problem in the strip function.