Description
Assignment Overview
In lecture you have learned that in C an array of characters with a NULL termination is considered a String, whereas an array of characters without a NULL termination is simply an array of characters. The standard library <string.h> is available with most C compilers that includes several functions designed to work with and manipulate Strings in C. Strings are so common in C that knowing how to use these functions in C is considered a basic skill.
The goal of this assignment is to give you experience with strings in C and with the library of functions designed to work with strings, give you an appreciation of how those functions work, and also continue to help you work with pointers and arrays (in the context of C Strings).
Learning Objectives
- Implement a library of functions based on requirements
- Program with pointers using array notation and pointer arithmetic
- Practice with C Strings
- Make working makefiles
Advice
- Test with many examples, not just one
- Start early and ask questions early. Do not wait until the last minute to do this assignment!
- Remember that C Strings require a null terminator (‘\0’)
- Don’t return pointers to stack arrays from functions. The compiler will probably warn you about this too. Always compile with the -Wall
Getting Started
Codio Setup
- Open the Codio assignment via Canvas. This is necessary to link the two systems.
- We have provided three starter code files.
- We have not provided a makefile. Part of the assignment is for you to do this yourself. You can refer to the previous assignment for an example about building a C project that includes multiple .c
Starter Code
We have provided a basic framework and several function definitions that you must implement.
my_string.h
This file contains the function declarations you must implement. Aside from adding the required declarations for my_strrev, my_strccase, and optionally my_strtok, do not modify this file.
my_string.c
This file contains empty implementations for the functions defined in my_string.h. We have provided the implementations of my_strlen using array notation and pointer arithmetic for you. You will provide the remaining implementations in this file.
program1.c
This is a test environment program only. We will not review it or even look at it and it will not be used for grading. You are free to write any code necessary to test your implementations.
Background – Introduction and my_strlen
In lecture, we discussed a commonly used function, strlen, that is part of the string.h library. Its job is to take in a C String, count the number of characters up to (but not including) the NULL character and return the string’s length. As an example, if our string was
char my_string [100] = “Tom” ;
strlen(my_string) would return 3.
Even though there are 100 bytes allocated on the stack for the string, since there are only 3 characters (followed by a NULL), the length of the string is indeed 3.
In lecture, we presented two versions of a strlen-like function. One function uses array notation and the other uses pointer notation. Ultimately they perform the same operation.
my_strlen_array treats the incoming argument (char* string) as if it is an array using array notation (i.e. with square brackets [ and ])
size_t my_strlen_array(const char *str)
int len = 0 ;
while (str[len] != ‘\0’) {
len++ ;
}
return (len) ;
}
my_strlen_pointer treats the incoming argument as the pointer it truly is, using pointer arithmetic to determine the string’s length.
size_t my_strlen_pointer(const char *str)
const char* s;
for (s = str; *s; ++s) ;
return (s – str);
}
Note: size_t is not an actual C type; is a “typedef’ed”, that is, it is a shortcut for unsigned long.
Your task for this assignment is to implement your own library of string functions to mimic the standard C library string functions.
In Codio, we have provided a header file called my_string.h. In that header file, we have declared several functions: my_strlen_array, my_strcpy_pointer, etc.
In my_string.c, we have implemented only two of the many functions: my_strlen_array and my_strlen_pointer, as described above. You will implement the remaining functions.
In a third file: program1.c, we have provided some basic code that calls the functions in your my_string library and compares the output of them to functions in the standard C-library string.h. This is one way to quickly check if your output is correct. Look carefully at these three files before continuing.
Problem 1 – Creating Your Own Library of String Functions
For this problem, your task is to implement your own library of string functions to mimic the standard C library string functions.
Overview
- Your job is to complete the implementation of c and test the functionality in program1.c.
- Notice that you must make two versions of the same function, one using array notation and the other using pointer notation.
- As an example, my_strlen_array uses array notation to calculate the length of the string, while my_strlen_pointer uses a much more efficient implementation using pointers to do the same thing. This is your chance to truly play with pointers and see if you can come up with more efficient techniques to solve problems than were done using array notation.
- Since many of these functions will be new for you, we have included helpful links in the Resources section so you can learn to use each of these functions before you try to implement them!
- You may also be struggling with the const variable keyword, especially as it is used with pointers in C. We have Resources for this as well!
- The main concept you need to understand is that, if a function declares a variable as const, that means the function promises to not modify that variable.
Requirements
- You MUST NOT modify h in any way, except to add the required function declarations my_strrev, my_strccase, and (optionally) my_strtok.
- You MUST NOT use the standard library h in your implementations.
- You MAY use h in program1.c, which is for testing your code.
- You MUST complete the implementations of the my_string library in c.
- You MUST implement my_strcpy_array using array notation and my_strcpy_pointer using pointer notation.
- You MUST implement my_strchr_array using array notation and my_strchr_pointer using pointer notation.
- You MUST implement my_strcat_array using array notation and my_strcat_pointer using pointer notation.
- You MUST implement my_strcmp_array using array notation and my_strcmp_pointer using pointer notation.
- You MUST create a makefile called makefile with the following targets:
- o
- program1
- all
- clean, which MUST remove all .o files only
- clobber, which MUST remove all .o files and all compiled executable programs
- You MAY use your my_string functions inside other my_string functions
- You MUST NOT use a _array function inside a _pointer function
- You MUST NOT use a _pointer function inside a _array function
- You MUST NOT have “debug print statements” in any implementation. If you choose to use print statements inside your functions, you MUST comment them out or remove them before submission. We discourage print statements in general and suggest learning gdb as your debugging tool.
- Your implementations MUST function the same as the standard library functions.
- Part of the assignment is to explore these functions and see how they work with different kinds of inputs. This means you will need to think critically about edge cases, see how the standard library handles them, and implement the same functionality on your own. Therefore, we will not provide a set of requirements for these functions.
- Your implementations MAY return a NULL pointer when any argument is NULL, but we will not be testing these scenarios. This simplification is designed to help you focus on the functionality edge cases.
- You MUST return a NULL pointer in other scenarios, which you will need to discover by investigating the h standard library functions.
- You SHOULD comment your code since this is a programming best practice.
Hints
- For my_strcmp, the return value just needs to be the correct sign (-, 0, or +), not the actual char The specific magnitude of the negative or positive number returned does not matter.
- For my_strcmp, you may find researching “lexicographical order” to be helpful.
- For my_strcat and my_strcpy, you may assume that the destination string is large enough to accommodate the source
Problem 2 – Adding Non-Standard String Functions to Your Library
Overview
- In the previous section you implemented and tested functions that mimic those in the standard C-library. Now you’ll add two functions that don’t exist in the C-library, but will exist in your own my_string library!
- my_strrev
- This function takes a single string argument, reverses the contents of the string that is passed in, and returns a pointer to the resulting string.
- As an example:
char my_string [] = “Tom”
char* ptr = my_strrev(my_string) ;
After my_strrev returns, my_string contains “moT”, and ptr points to the first element in my_string.
- my_strccase
- This function takes a single string argument, converts each character of the string to the opposite case, and returns a pointer to the resulting string.
- As an example:
char my_string [] = “Tom”
char* ptr = my_strccase(my_string) ;
After my_strccase returns, my_string contains “tOM” and ptr, points to the first element in my_string. - As a hint, examine the ASCII table, you will see that if you work on the hexadecimal characters directly, you can very easily convert them to their upper or lowercase equivalents!
- You do not need to make two versions of these functions (pointers and array). You can implement them anyway you see fit. You will need to modify h (adding the proper declaration statement for each of these new functions) and my_string.c (adding the proper definition of each of these new functions). And you will need to create program2.c to properly test these new function’s you’ve created.
- Create a new program called program2.c to test these new functions.
- Be sure to add a “program2” directive to your existing Makefile.
Requirements
- You MUST call the two functions my_strrev and my_strccase.
- my_strrevMUST
- take a single char* argument (the string to reverse)
- reverse the characters “in place”
- It MUST NOT return a new pointer but rather modify the contents of the original string
- It MAY create temporary data to complete the operation
- return a pointer that points to the start of the modified
- my_strccaseMUST
- be called my_strccase (yes, there are two cs, for “change case”)
- take a single char* argument (the string to change cases)
- change the case of the characters “in place” (lowercase becomes uppercase and uppercase becomes lowercase)
- It MUST NOT return a new pointer but rather modify the contents of the original string
- It MAY create temporary data to complete the operation
- It MUST NOT use h. We are explicitly forbidding this header since it trivializes the assignment.
- return a pointer that points to the start of the modified string.
- take no action on non-letter characters (e.g. numbers or symbols).
- You MUST add function declarations for the two functions to h.
- You MUST NOT modify h in any other way.
- You MUST NOT use the standard library h in your implementations.
- You MAY use h in program2.c, which is for testing your code.
- You MUST complete the implementations of the two functions in c.
- You MUST implement the functions using either array notation or pointer notation. You are free to choose either method for these functions.
- You MUST update your makefile for the following targets:
- program2
- all
- clean
- clobber
- You MAY use your own my_string functions inside other my_string
- You MUST NOT have “debug print statements” in any implementation. If you choose to use print statements inside your functions, you must comment them out or remove them before submission. We discourage print statements in general and suggest learning gdb as your debugging tool.
- Your implementations MAY return a NULL pointer when any argument is NULL, but we will not be testing these scenarios.
- You SHOULD comment your code since this is a programming best practice.
Problem 3 – Parsing Strings
Overview
The sscan and sprintf functions
- sscanf and sprintf and are two very useful functions related to scanf and printf frequently used to parse strings and convert data from strings into different data types.
- sscanf works identically to scanf except, instead of reading the keyboard for input, it reads a C String as its input
- sprintf works identically to printf except, instead of using the ASCII display for output, it uses a C String as its output.
- Since you already know how to use scanf and printf, this problem will feel familiar. The two links in the Resources section provide a reference for their arguments/returns and basic function.
- If you prefer, you may find using strcat to be more intuitive than using sprintf. This is a choice left to you.
- DO NOT use your version of my_strcat; use the official library strcat in h for the problem.
- You should be familiar with this function by now, but we have a reference link for it in the Resources
Arguments to main
- Recall from the lectures on the stack, that the function main always has a blank spot for arguments, but our declaration of main never has any arguments. Well, it’s actually possible for main to take arguments. BUT, they can only be specified as follows:
int main (int argc, char** argv) ;
- The first argument: argc (argument count) contains the number of arguments passed to main.
- The second argument: argv (argument vector) is actually a pointer to an array of strings. Each element of the array is a single char* for one of the arguments.
- How exactly do you pass arguments to main? You do it when you start your program in the terminal.
- Take the following code and put it in a file called c
int main (int argc, char** argv) {
printf (“# of arguments passed: %d\n”, argc) ;
for (int i=0; i< argc ; i++) {
printf ( “argv[%d] = %s\n”, i, argv[i] ) ;
}
return (0) ;
}
- Compile it, and then run it with this command:
./program3 arg1 2 arg3 4 arg5
- Watch the output and look at the code above to see how it works! Try it with different arguments and watch how things change.
Problem 3 Task
- Notice that all the arguments passed in are treated as C Strings in your program. Even though 2 is a number, it is treated as a NULL terminated character array (a C String) inside the argv
- You will be adding additional code to c to
- read each char* argument in the argv array,
- determine if it is an integer or a string,
- store the integers into a new array,
- store the strings into a single large string,
- print the contents of the integer array with each integer on a new line,
- and then print the combined large string.
- You will also need to remove any other print statements from the program.
Requirements
- You MUST write your solution to the task in c.
- You MAY use functions such as sscanf, sprintf (which require h), and standard string functions in the string.h standard library.
- Your program MUST do the following:
- Process all arguments provided to your program.
- You MAY assume that the number of arguments is less than 10.
- You MAY assume that the largest string you might create is less than 250 bytes.
- Remove the ./ characters from the zeroth argument of argv.
- Convert any argument that is actually an integer from its string form into an integer using sscanf.
- As a small hint, look at the return type of sscanf (notice that it returns the number of matches it made to your string)
- Store any integer arguments into an array of integers.
- For the above example, your program would generate an array: {2, 4}
- We will not be testing strings that start with integers (e.g. 123abc). If an argument begins with an integer, you can assume that it is always an integer and not a string.
- Store any non-integer argument into 1 large string, each argument separated by spaces
- You MUST use either strcat or sprintf.
- For the above example, your program would generate a string: “program3 arg1 arg3 arg5”.
- Print the contents of your integer array with each element on a new line.
- Print the contents of your single string.
- Print ONLY the integers and string, without any labels or any other additions. For the above example, your program MUST print exactly:
2
4
program3 arg1 arg3 arg5
- Process all arguments provided to your program.
- You MUST update your makefile for the following targets:
- program3
- all
- clean
- clobber
- You MUST NOT have “debug print statements” in your program. If you choose to use print statements as part of debugging, you MUST comment them out or remove them before submission. We discourage print statements in general and suggest learning gdb as your debugging tool.
- You SHOULD comment your code since this is a programming best practice.
Problem 4 (Extra Credit) – my_strtok
Overview
- One of the more difficult string functions to use and to implement is strtok(). This function takes a string and “tokenizes” it; that is, it separates the original string into a series of tokens. This is similar to the Java or Python split
- Since this is an extra credit problem, we will provide minimal guidance. But we do have a resource in the Resources
Requirements
- You MUST add function declarations for this function to h.
- You MUST NOT modify h in any other way.
- You MUST add a function definition for this function to c.
- You MUST NOT use the standard library h in your implementations.
- You MAY use h in program4.c, which is for testing your code.
- Your implementation MUST function the same as the standard library function.
- You MUST implement the functions using either array notation or pointer notation. You are free to choose either method for this function.
- You MUST update your makefile for the following targets:
- program4
- all
- clean
- clobber
- You MAY use your my_string functions inside other my_string
- You MUST NOT have “debug print statements” in any implementation. If you choose to use print statements inside your functions, you must comment them out or remove them before submission. We discourage print statements in general and suggest learning gdb as your debugging tool.
- You SHOULD comment your code since this is a programming best practice.
A Hint
- On the first call to my_strtok, we pass a string we want to tokenize and a delimiter. my_strtok must return the first token (the portion of the string up to but not including the first occurrence of the delimiter).
- On each subsequent call to my_strtok, we pass a NULL pointer instead of the string, and my_strtok must return the next token.
- When no more tokens are found, my_strtok must return NULL. This indicates that my_strtok must “remember” the string passed in when first called.
Testing Your Functions
- c and program2.c are for student testing only. We will not review them or test them in any way.
- Remember to test the return results from functions like my_strrev and my_strccase that both modify the string in place and also return a ptr to the modified string.
- You can assume that we will not pass any NULL pointers to your string functions. You will have to return NULL in some cases, but you do not have to check if any arguments to your functions are NULL. You can also assume that if we wish to modify the string, a string literal will not be passed.
- We recommend testing your functions against the standard library string functions (h). The output and return values should be the same.
- Note that my_strcat_array and my_strcat_pointer modify the original string, so you will want to test with different strings to avoid confusion between test runs
Submission
Submission Checks
There is a single “submission check” test that runs once you upload your code to Gradescope. This test checks that you have submitted all required files and also that your program compiles and any autograder code compiles successfully. It does not run your program or provide any input on whether it works or not. This check just ensures that all the required components exist. This test is performed after uploading to Gradescope.
Ensure that you are passing this check before closing Gradescope. If you are not passing this check, please reach out to TAs for troubleshooting assistance.
Consistency Checks
The autograder will also show the results of six tests:
- testStrCatArrayHelloWorld
- testStrCatPointerHelloWorld
- testStrchrArrayFirstChar
- testStrchrPointerFirstChar
- testStrcmpArraySameWord
- testStrcmpPointerSameWord
The remaining tests will be hidden until after grades are published.
The Actual Submission
You will submit this assignment to Gradescope in the assignment entitled Assignment 10: Strings in C.
Download the required .c source and .h header files (as well as any additional helper files required) and your Makefile from Codio to your computer, then Upload all of these files to the Gradescope assignment. We expect my_string.c, my_string.h, program3.c, and makefile. Do not submit program1.c, program2.c., or program4.c.
Do not not submit intermediate files (anything .o).
You have unlimited submissions until the deadline, after which late penalties apply as noted in the syllabus.
We will only grade the last submission uploaded.
Do not mark your Codio workspace complete. Only the submission in Gradescope will be used for grading purposes.
There is no page matching and no academic integrity submission for autograder assignments.
Grading
This assignment is worth 127.5 points, normalized to 100% for gradebook purposes.
Main Assignment
Problem 1 (standard functions) is worth 72 points (each function is 9 points, with equally weighted sub-tests per function).
Problem 2 (custom functions) is worth 18 points (each function is 9 points, with equally weighted sub-tests per function).
Problem 3 (parsing strings) is worth 10 points.
Problems 1, 2, and the Extra Credit are tested with Unit Testing. We will run different scenarios for each function to validate the functionality (partial credit based on which tests fail).
Problem 3 checks the final output produced by your program and compares that output to the expected output. It must match exactly for credit: double check that your program does not have any extra output.
We will only grade the last submission, regardless of the results of any previous submission.
We will not be providing partial credit for autograder tests.
You may ask for feedback by submitting a regrade request using the Miscellaneous Adjustments rubric item.
Extra Credit
The Extra Credit is worth 6 percentage points so the highest grade on the assignment is 106%.
Your extra credit must not break functionality for the non-extra credit requirements.
There is no partial credit. It must work completely for any credit.
We will not give guidance on how to do this since it is designed to be challenge problem.
Hints or FAQs
Hints from previous semesters
- Ignore the warning produced by returning a const char* when the return type is char* when declaring a pointer to an immutable string.
- Don’t mis-spell my_strccase
- Write many test cases. A common cause of low grades is not being thorough in testing
- Don’t forget the NULL terminator in your strings.
- You will need to add -g to your makefile for all intermediate steps to use gdb for debugging those intermediate object files.
- You no longer need to log gdb output to txt. That was only for Assignment 9. You will probably never log gdb output again and we do not expect to see this anymore.
Resources
strlen reference
https://www.tutorialspoint.com/c_standard_library/c_function_strlen.htm
strcpy reference
https://www.tutorialspoint.com/c_standard_library/c_function_strcpy.htm
strchr reference
https://www.tutorialspoint.com/c_standard_library/c_function_strchr.htm
strcat reference
https://www.tutorialspoint.com/c_standard_library/c_function_strcat.htm
strcmp reference
https://www.tutorialspoint.com/c_standard_library/c_function_strcmp.htm
sscanf reference
https://www.tutorialspoint.com/c_standard_library/c_function_sscanf.htm
sprintf reference
https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
strtok reference
https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
strtok reference (Linux manual pages)
https://man7.org/linux/man-pages/man3/strtok_r.3.html
The const modifier
http://www.geeksforgeeks.org/const-qualifier-in-c/



