#include <iostream>
#include <cstring>
#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;
}