Skip to content

Instantly share code, notes, and snippets.

@dongguosheng
Last active December 31, 2015 06:19
Show Gist options
  • Save dongguosheng/7946826 to your computer and use it in GitHub Desktop.
Save dongguosheng/7946826 to your computer and use it in GitHub Desktop.
A string class implemented to practice C++.
#include <iostream>
#include "MyString.h"
using namespace std;
void testMyString(const char *, const MyString &);
int main(int argc, char* argv[])
{
const char *s = "const char *";
char str[] = "char array str";
//Test constructors
MyString str1;
MyString str2(s);
MyString str3(str, strlen(str));
cout << "Test constructors" << endl;
cout << "-----------------------------" << endl;
testMyString("str1", str1);
testMyString("str2", str2);
testMyString("str3", str3);
//Test copy constructor
MyString str4(str3);
cout << "Test copy constructor" << endl;
cout << "-----------------------------" << endl;
testMyString("str4", str4);
//Test append
str1.append(str2);
str2.append(str3, 2, 2);
str3.append(5, 'o');
cout << "Test append" << endl;
cout << "-----------------------------" << endl;
testMyString("str1", str1);
testMyString("str2", str2);
testMyString("str3", str3);
// //Test assign
str1.assign("test assign const char *");
str2.assign(str3, 1, 2);
str3.assign("test assign const char * & n", 6);
str4.assign(4, 'c');
cout << "Test assign" << endl;
cout << "-----------------------------" << endl;
testMyString("str1", str1);
testMyString("str2", str2);
testMyString("str3", str3);
testMyString("str4", str4);
// //Test erase
str3.erase();
cout << "Test erase" << endl;
cout << "-----------------------------" << endl;
testMyString("str3", str3);
return 0;
}
void testMyString(const char * str, const MyString &myString){
cout << str << " capacity: " << myString.getCapacity() << " length: " << myString.length()
<< " value: " << myString.data() << endl;
}
#include "MyString.h"
MyString::MyString(void) : capacity(INITIAL_CAPACITY), size(0)
{
s_ptr = new char[INITIAL_CAPACITY];
*s_ptr = '\0';
}
MyString::~MyString(void)
{
delete [] s_ptr;
s_ptr = NULL;
}
MyString::MyString(const char *str)
{
uint_t len = strlen(str);
capacity = INITIAL_CAPACITY;
while(len + 1 > capacity){
capacity *= 2;
}
s_ptr = new char[capacity];
memcpy(s_ptr, str, len + 1);
size = len;
}
MyString::MyString(const char str[], uint_t n) : size(n)
{
capacity = INITIAL_CAPACITY;
while(n + 1 > capacity){
capacity *= 2;
}
s_ptr = new char[capacity];
memcpy(s_ptr, str, n);
s_ptr[n] = '\0';
}
MyString::MyString(const MyString& myString) : capacity(myString.capacity), size(myString.size)
{
s_ptr = new char[capacity];
memcpy(s_ptr, myString.s_ptr, myString.size + 1);
}
// append 退出时会调用MyString析构函数,所以,虽然str是copy,delete str中的char *s_ptr将会影响传入的参数;
// 由于返回类型的设置,导致函数返回后调用了析构函数,同上,会出现不可预料的结果(返回引用,不会发生对象拷贝,自然也不会调用析构函数)
MyString& MyString::append(const MyString &str)
{
uint_t last_capacity = capacity;
setNewCapacity(size + str.size + 1);
if(capacity > last_capacity){
char *result_str = new char[capacity];
memcpy(result_str, s_ptr, size - 1);
delete[] s_ptr;
memcpy(result_str + size, str.s_ptr, str.size + 1);
s_ptr = result_str;
}else {
memcpy(s_ptr + size, str.s_ptr, str.size + 1);
}
size += str.size;
return *this;
}
MyString& MyString::append(const MyString &str, uint_t index, uint_t n)
{
uint_t len_copy = index + n > str.size ? str.size - index : n;
uint_t last_capacity = capacity;
setNewCapacity(size + len_copy + 1);
if(capacity > last_capacity){
char *result_str = new char[capacity];
memcpy(result_str, s_ptr, size);
delete[] s_ptr;
memcpy(result_str + size, str.s_ptr + index, len_copy);
size += len_copy;
s_ptr = result_str;
}else {
memcpy(s_ptr + size, str.s_ptr + index, len_copy);
size += len_copy;
}
s_ptr[size] = '\0';
return *this;
}
MyString& MyString::append(uint_t n, char ch)
{
uint_t last_capacity = capacity;
setNewCapacity(size + n + 1);
if(capacity > last_capacity){
char *result_str = new char[capacity];
memcpy(result_str, s_ptr, size);
delete[] s_ptr;
memset(result_str + size, ch, n);
s_ptr = result_str;
}else {
memset(s_ptr + size, ch, n);
}
size += n;
s_ptr[size] = '\0';
return *this;
}
MyString& MyString::assign(const char *chars)
{
uint_t chars_len = strlen(chars);
uint_t last_capacity = capacity;
setNewCapacity(chars_len + 1);
if(capacity > last_capacity){
delete [] s_ptr;
s_ptr = new char[capacity];
}
memcpy(s_ptr, chars, chars_len + 1);
size = chars_len;
return *this;
}
MyString& MyString::assign(const MyString& str, uint_t index, uint_t n)
{
uint_t len_copy = index + n > str.size ? str.size - index : n;
uint_t last_capacity = capacity;
setNewCapacity(len_copy + 1);
if(capacity > last_capacity){
delete[] s_ptr;
s_ptr = new char[capacity];
}
memcpy(s_ptr, str.s_ptr + index, len_copy);
size = len_copy;
s_ptr[size] = '\0';
return *this;
}
MyString& MyString::assign(const char *chars, uint_t n)
{
uint_t last_capacity = capacity;
setNewCapacity(n + 1);
if(capacity > last_capacity){
delete[] s_ptr;
s_ptr = new char[capacity];
}
memcpy(s_ptr, chars, n);
size = n;
s_ptr[size] = '\0';
return *this;
}
MyString& MyString::assign(uint_t n, char ch)
{
uint_t last_capacity = capacity;
setNewCapacity(n + 1);
if(capacity > last_capacity){
delete[] s_ptr;
s_ptr = new char[capacity];
}
memset(s_ptr, ch, n);
size = n;
s_ptr[size] = '\0';
return *this;
}
MyString& MyString::erase(uint_t index, uint_t n)
{
if(index >= size){
cout << "Index out of range." << endl;
return *this;
}
if(index == 0 && n == -1){
clear();
}
else if(index + n > size){
*(s_ptr + index) = '\0';
size = index + 1;
}
else {
for(uint_t i = 0; i < n; i++){
*(s_ptr + index + i) = *(s_ptr + index + n + i);
}
*(s_ptr + index + n) = '\0';
size -= n;
}
return *this;
}
int MyString::compare(const MyString &str) const
{
char *p = s_ptr;
const char *q = str.data();
while(*p != '\0' && *q != '\0'){
if(*p != *q){
return *p - *q;
}
else {
p++;
q++;
}
}
return *p - *q;
}
int MyString::compare(uint_t index, uint_t n, const MyString &str, uint_t index_str, uint_t n_str) const
{
if (index >= size || index_str >= str.size){
cout << "Index out of range." << endl;
return 0;
}
else {
char *p = s_ptr + index;
const char *q = str.data() + index_str;
int i = 0;
int min_n = n > n_str? n_str: n;
while(*p != '\0' && *q != '\0' && i < min_n){
if(*p != *q){
return *p - *q;
}
else {
p++; q++;
i++;
}
}
return *p - *q;
}
}
MyString::uint_t MyString::copy(char *s, uint_t index, uint_t n) const
{
char *p = s_ptr;
if(index + n > size){
while(*p != '\0'){
*s++ = *p++;
}
return size - index;
}
else {
for(uint_t i = 0; i < n; i++){
s[i] = p[index + i];
}
return n;
}
}
MyString MyString::substr(uint_t index, uint_t n) const
{
if(index >= size){
cout << "Index out of memory." << endl;
return *this;
}
if(index + n > size){
return MyString(s_ptr + index);
}else {
return MyString(s_ptr + index, n);
}
}
MyString::uint_t MyString::find(char ch, uint_t index) const
{
if(index >= size){
cout << "Index out of range." << endl;
}
char *p = s_ptr + index;
uint_t i = 0;
while(p[i] != '\0'){
if(ch == p[i]){
return i + index;
}else {
i ++;
}
}
return -1;
}
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring>
using namespace std;
class MyString
{
public:
typedef unsigned int uint_t;
static const uint_t INITIAL_CAPACITY = 20;
/*
* Constructs an empty string, with a length of zero characters
*/
MyString(void);
~MyString(void);
MyString(const char *str);
MyString(const char chars[], uint_t size);
/*
* Copy constructor
*/
MyString(const MyString& myString);
/*
* Extends the string by appending additional characters at the end of its current value
*/
MyString& append(const MyString &str);
MyString& append(const MyString &str, uint_t index, uint_t n);
MyString& append(uint_t n, char ch);
/*
* Assigns a new value to the string, replacing its current contents
*/
MyString& assign(const char *chars);
MyString& assign(const MyString &str, uint_t index, uint_t n);
/*
* Copies the first n characters from the array of characters pointed by s.
*/
MyString& assign(const char *chars, uint_t n);
/*
* Replaces the current value by n consecutive copies of character c.
*/
MyString& assign(uint_t n, char ch);
inline char& at(uint_t index);
inline const char& at(uint_t index) const;
inline uint_t length() const;
/*
* Erases the contents of the string, which becomes an empty string (with a length of 0 characters)
*/
inline void clear();
/*
* Erases part of the string, reducing its length, use default arguments
*/
MyString& erase(uint_t index = 0, uint_t n = -1);
inline bool empty() const;
/*
* Compares the value of the string object
*/
int compare(const MyString &s) const;
/*
* compare the substring of string(from index span n) to str's substring(from index_str span n_str)
*/
int compare(uint_t index, uint_t n, const MyString &str, uint_t index_str, uint_t n_str) const;
/*
* Copies a substring of the current value of the string object into the array pointed by s. This substring contains the len characters that start at position pos.
* The function does not append a null character at the end of the copied content.
*/
uint_t copy(char *s, uint_t index, uint_t n = 0) const;
inline const char *data() const;
inline uint_t getCapacity() const;
/*
* Returns a newly constructed string object with its value initialized to a copy of a substring of this object.
* The substring is the portion of the object that starts at character position pos and spans len characters (or until the end of the string, whichever comes first).
*/
MyString substr(uint_t index, uint_t n) const;
MyString substr(uint_t index) const;
/*
* Exchanges the content of the container by the content of str, which is another string object. Lengths may differ
*/
inline void swap(MyString &str);
/*
* Searches the string for the first occurrence of the sequence specified by its arguments.
*/
uint_t find(char ch, uint_t index = 0) const;
private:
char *s_ptr;
uint_t capacity; //memory string owns
uint_t size; //string size
inline void setNewCapacity(uint_t size);
};
inline MyString::uint_t MyString::length() const{
return size;
}
inline const char* MyString::data() const {
return s_ptr;
}
inline char& MyString::at(uint_t index){
if(size > index){
return *(s_ptr + index);
}
else {
cout << "Index out of range." << endl;
}
}
inline const char& MyString::at(uint_t index) const{
return this->at(index);
}
inline void MyString::clear(){
if(size != 0){
*s_ptr = '\0';
}
size = 0;
}
inline bool MyString::empty() const{
return size == 0 ? true : false;
}
inline void MyString::swap(MyString &str){
char *temp = s_ptr;
s_ptr = str.s_ptr;
str.s_ptr = temp;
uint_t temp_size = size;
size = str.size;
str.size = temp_size;
temp_size = capacity;
capacity = str.capacity;
str.capacity = temp_size;
}
inline MyString::uint_t MyString::getCapacity() const{
return capacity;
}
inline void MyString::setNewCapacity(uint_t n){
while(n > capacity){
capacity *= 2;
}
}
#endif /* MYSTRING_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment