#include #include #include "string215.h" using namespace std; int test_string215(); void pause_215(bool have_newline); int string215::str_len(const char *str) const { int len = 0; const char *search; for(search = str; *search != '\0'; search++) { len++; } return len; } // Make and return a dynamically-allocated copy of the input C string. char *string215::copy_string(const char *input) { char *output = new char[str_len(input)+1]; for(const char *scan = input; *scan != '\0'; scan++) { *output = *scan; output++; } *output = '\0'; if(str_len(input) > 0) { output -= str_len(input); } return output; } // Return true if the two C strings contain the same sequence of characters. bool string215::equal_string(const char *first, const char *second) const { const char *scan1; const char *scan2; if(str_len(first) == str_len(second)) { scan1 = first; scan2 = second; while(*scan1 != '\0') { if(*scan1 != *scan2) { return false; } scan1++; scan2++; } return true; } return false; } // Destructor for the string215 class string215::~string215() { delete[] data; } // Constructor for thwe string215 class string215::string215() { char *arr = new char[0]; arr[0] = '\0'; data = arr; } // A copy constructor that allocates memory and performs a deep copy of the input object string215::string215(const string215 &other) { data = copy_string(other.data); } // Check whether two strings contain the same characters. bool string215::equals(const string215 &other) const { if(equal_string(data, other.data) == true) { return true; } return false; } // Return the length of a string215, not counting the null terminator. int string215::length() const { return str_len(data); } // Return the character at a given index. Returns '\0' if the // index is out of bounds. char string215::getchar(int index) const { const char *stepper = data; if(index <= str_len(data) && index >= 0) { for(int x = 0; x < index; x++) { stepper++; } return *stepper; } return '\0'; } // Set the character at a given index and return false. bool string215::setchar(int index, char newchar) { if(index <= str_len(data) && index >= 0) { for(int x = 0; x < index; x++) { data++; } *data = newchar; return true; } return false; } // Add a suffix to the end of this string. Allocates and frees memory. void string215::append(const string215 &suffix) { char *output = new char[str_len(data)+suffix.length()+1]; for(int x = 0; x < str_len(data); x++) { *output = *data; output++; data++; } for(int x = 0; x < suffix.length(); x++) { *output = suffix.getchar(x); output++; } *output = '\0'; output -= (str_len(data)+suffix.length()+1); delete[] data; data = output; } // Return a pointer to the raw character data (not a copy). const char *string215::c_str() const { const char *pRaw = data; return pRaw; } // Create a string215 that is a (deep) copy of a C string. string215::string215(const char *in_str) { data = copy_string(in_str); } /* string215::replace() - Replace the contents of a string215 with the * contents of a C string. * * Description: * Replace the contents of this string with a copy of the C string * argument. Allocates memory for the new string array, performs a * deep copy of the input, and frees the old array. * * Inputs: * const char *in_str - The C string to copy into this object. * * Outputs: * No return value. The current string's contents are modified to be * character-by-character identical with the C string. */ void string215::replace(const char *in_str) { delete[] data; data = new char[str_len(in_str)+1]; } /* test_string215() - Test the string215 class. * * Description: * Run a number of tests of the various methods of the string215 class. * * Inputs: * No inputs. * * Outputs: * Prints a message about each failed test to cerr. Returns the number of * failed tests. */ int test_string215() { // Current test number. Be sure to increment this before each test! int curr_test = 0; // Number of failed tests. int failed = 0; // TODO: Add at least two additional tests for the append method; // and four tests each for the setchar, equals, and replace methods. // Test both normal and boundary conditions. If the test failed, // print a message to cerr and increment the 'failed' counter. // // Do not change or remove any of the existing tests! // // Note: This function is the only part of the program permitted to // use the functions strcmp, strlen, and so on. // Testing contents: // Tests 1-8 cover the constructors and c_str(). // Tests 9-10 cover length(). // Tests 11-12 cover getchar(). // Tests 13-14 cover append(). // Test 1: the default constructor and c_str(). An empty string // should still be terminated with a '\0' (at position 0), and in // particular should not be represented by a null pointer. curr_test++; string215 empty; const char *cs = empty.c_str(); if (cs == NULL || cs[0] != '\0') { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 2: does the C string constructor faithfully copy its input? curr_test++; char letters[] = "some characters here"; string215 full(letters); if (strcmp(letters, full.c_str()) != 0) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 3: and did it do a deep copy? The pointers should // differ. curr_test++; if (letters == full.c_str()) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 4: make sure c_str() isn't making a copy. If we call // it twice in a row, it should return the same address. curr_test++; if (full.c_str() != full.c_str()) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 5: make sure we can copy an empty string. curr_test++; string215 empty_fromc(""); cs = empty_fromc.c_str(); if (cs[0] != '\0') { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 6: test that the copy constructor copies. curr_test++; string215 full_copy(full); if (strcmp(full_copy.c_str(), full.c_str()) != 0) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 7: and that it does a deep copy. curr_test++; if (full_copy.c_str() == full.c_str()) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 8: test the copy constructor on an empty string. curr_test++; string215 empty_copy(empty); cs = empty_copy.c_str(); if (cs[0] != '\0' || cs == empty.c_str()) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 9: test the length method. curr_test++; if (full.length() != strlen(full.c_str())) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 10: also on an empty string. curr_test++; if (empty.length() != 0) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 11: test getchar for the first and last characters. curr_test++; string215 str("testing"); if (str.getchar(0) != 't' || str.getchar(str.length() - 1) != 'g') { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 12: also on out-of-bounds indices. curr_test++; if (str.getchar(-1) != '\0' || str.getchar(str.length()) != '\0' || str.getchar(9999) != '\0') { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 13: test that append works in a simple case. curr_test++; string215 suffix("123"); str.append(suffix); if (strcmp(str.c_str(), "testing123") != 0) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // Test 14: and that it didn't modify its argument. curr_test++; if (strcmp(suffix.c_str(), "123") != 0) { cerr << "Test " << curr_test << " failed." << endl; failed++; } // TODO: YOUR TESTS GO HERE // Finally, return the number of failed tests return failed; } /* pause_215() - Wait for the user to press ENTER. * * Description: * Optionally read and discard the remainder of the user's last * line of input. Then, prompt the user to press ENTER, then * read and discard another line of input. * * Inputs: * bool have_newline: * True if the user has already entered a newline that the * program has not yet read. If true, this function first * discards remaining input up to and including that newline. * * Reads two lines from standard input if have_newline is true, * one line if it is false. Lines are assumed to be less than * two hundred characters long. * * Outputs: * No return value. * * Prints a prompt to standard output. * * Notes: * This function is intended to be used at the end of a program, * just before returning from main(). Reading another line of * input prevents the console window from closing immediately. * * In general, have_newline should be true if the last user input * from cin used the extraction operator (>>), and false if there * has been no user input or if the last input used getline(). */ void pause_215(bool have_newline) { if (have_newline) { // Ignore the newline after the user's previous input. cin.ignore(200, '\n'); } // Prompt for the user to press ENTER, then wait for a newline. cout << endl << "Press ENTER to continue." << endl; cin.ignore(200, '\n'); } int main() { int failed = test_string215(); if (failed == 0) cout << "All tests passed successfully." << endl; else cout << "Sorry, " << failed << " test(s) failed." << endl; pause_215(false); // Remember that returning zero from main indicates success, while // return anything else means that some kind of error occurred. return failed; }