#include<iostream>
#include<string.h>
#include<assert.h>
#include<stdio.h>
class String
{
public:
//構造函數
String(const char *str="")
:_size(strlen(str))
,_capacity(_size)
{
_str = new char[_size+1];
strcpy(_str,str);
}
void Swap(String& s)
{
std::swap(_str,s._str);
std::swap(_size,s._size);
std::swap(_capacity,s._capacity);
}
//拷貝構造
String(const String& s)
:_str(NULL)
{
String tmp(s._str);
this->Swap(tmp);
}
//賦值運算符的重載
String& operator=(String s)
{
this->Swap(s);
return *this;
}
//析構函數
~String()
{
if(_str)
{
delete[] _str;
_str = NULL;
}
}
//求string的字符個數
size_t Size()
{
return _size;
}
//求string的容量
size_t Capacity()
{
return _capacity;
}
//求string的內容
char *Str()
{
return _str;
}
//判斷string是否爲空
bool Empty()
{
return _size == 0;
}
//[]操作符的重載
char& operator[](size_t pos)
{
return _str[pos];
}
//擴容,只會改變_capacity的大小
void Reserve(size_t n)
{
Expand(n);
}
//可能會同時改變_size和_capacity
//並且還會進行初始化(缺省初始化爲'\0')
void Resize(size_t n,char ch = '\0')
{
if(n <= _size)
{
//此時因爲是縮小了或者不變所以不用改變_capacity的值
_str[n] = '\0';
_size = n;
}
else
{
if(n > _capacity)
{
//此時n超過了容量的大小因此需要擴容
Expand(n);
}
for(size_t i = _size;i < n;++i)
{
_str[i] = ch;
}
_str[n] = '\0';
_size = n;
}
}
//擴容函數(這裏涉及到一個問題就是如何擴容??附在代碼後面)
void Expand(size_t n)
{
if(n > _capacity)
{
char *tmp = new char[n+1];
strcpy(tmp,_str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
//尾插函數
void PushBack(char ch)
{
//方法1:
// if(_size == _capacity)
// {
// Expand(_capacity*2);
// }
// _str[_size] = ch;
// _str[_size+1] = '\0';
// ++_size;
//方法2:可直接調用實現的Insert()函數
Insert(_size,ch);
}
//在string的後面追加一個字符串
void Append(const char *str)
{
size_t len = strlen(str);
if(_size+len >_capacity)
{
Expand(_size+len);
}
strcpy(_str+_size,str);//接着_str的末尾開始往後拷貝
_size += len;
}
//某個位置插入字符
void Insert(size_t pos,char ch)
{
assert(pos <= _size);
if(_capacity == _size)
{
//此時已經相等,如果在想插入一個元素則空間肯定不夠,
//需要擴容
Expand(_capacity*2);
}
int end = _size;
while(end >= (int)pos)
{
//把包括pos位置在內的往後所有元素依次往後移動一個位置
_str[end+1] = _str[end];
--end;
}
//移動完成以後,pos位置就空出來了,將待插入的元素插入
_str[pos] = ch;
++_size;
}
//某個位置插入字符串
void Insert(size_t pos,const char *str)
{
assert(pos <= _size);
size_t len = strlen(str);
if(_size + len > _capacity)
{
Expand(_size+len);
}
int end = _size;
while(end >= (int)pos)
{
_str[end+len] = _str[end];
--end;
}
strncpy(_str+pos,str,len);
//使用strncpy不會將待插入的字符串的'\0'也拷貝進目標字符串
}
//s1+="hello" +=運算符重載,與Append函數功能相同
String& operator+=(const char *str)
{
this->Append(str);
return *this;
}
//s1+=s2 兩個string類的+=實現
String operator+=(const String& s)
{
*this += s._str;//相當於this->operator+=(this,s._str);
return *this;
}
//s1+"hello"
String operator+(const char *str)
{
String ret(*this);
ret.Append(str);
return ret;
}
//s1+s2
String operator+(const String s)
{
return *this+s._str;
}
//尾刪
void PopBack()
{
assert(_size > 0);
--_size;
_str[_size] = '\0';
}
//刪除某一位置往後的len個元素
void Erase(size_t pos,size_t len)
{
assert(pos < _size);
if(pos+len >= _size)
{
//此種情況就是將pos往後的所有都刪掉
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str+pos,_str+pos+len);
_size -= len;
}
}
//在string中查找是否存在某一個字符,若存在返回下標
size_t Find(char ch)
{
for(size_t i = 0;i < _size;i++)
{
if(_str[i] == ch)
{
return i;
}
}
//這裏的npos是string類中的一個公有的成員變量(值爲-1)
//返回這個就說明沒有找到
return npos;
}
//在string中查找是否存在某一個子串,類似於strstr函數
size_t Find(const char *sub) const
{
if(sub == NULL)
{
return npos;
}
char *ret = _str;
while(*ret)
{
char *cur_tmp = (char *)sub;
char *str_tmp = ret;
while(*str_tmp && cur_tmp && *str_tmp == *cur_tmp)
{
str_tmp++;
cur_tmp++;
}
if(*cur_tmp == '\0')
{
//找到了,返回匹配到的子串往後的字符串
//如查找abc在dabcjd23dabce中是否存在,
//結果返回abcjd23dabce這個字符串
return ret-_str;
}
else
{
ret++;
}
}
return npos;
}
bool operator<(const String& s) const
{
const char* str1 = _str;
const char* str2 = s._str;
while(*str1 && *str2)
{
if(*str1 < *str2)
return true;
else if(*str1 > *str2)
return false;
else
{
++str1;
++str2;
}
}
if(*str1 == '\0' && *str2 != '\0')
{
//str1字符串比str2這個字符串要短
return true;
}
else
{
return false;
}
}
bool operator<=(const String& s) const
{
return *this<s || *this==s;
}
bool operator>(const String& s) const
{
return !(*this<=s);
}
bool operator>=(const String& s) const
{
return !(*this<s);
}
bool operator==(const String& s) const
{
const char *str1 = _str;
const char *str2 = s._str;
while(*str1 && *str2)
{
if(*str1 != *str2)
{
return false;
}
else
{
++str1;
++str2;
}
}
if(*str1 == '\0' && *str2 == '\0')
{
return true;
}
else
{
return false;
}
}
bool operator!=(const String& s) const
{
return !(*this==s);
}
private:
char *_str;
size_t _size;
size_t _capacity;
public:
static size_t npos;
};
size_t String::npos = -1;
void Test()
{
String s("hello");
//拷貝構造函數測試
String s1(s);
std::cout<<s1.Str()<<std::endl;
//賦值運算符重載函數測試
String s2;
s2 = s;
std::cout<<s2.Str()<<std::endl;
//[]運算符重載函數測試
std::cout<<s[0]<<std::endl;
//PushBack函數測試
s.PushBack(' ');
std::cout<<s.Str()<<std::endl;
//Append函數測試
s.Append("world");
std::cout<<s.Str()<<std::endl;
//Insert函數測試
s.Insert(11,'O');
std::cout<<s.Str()<<std::endl;
s.Insert(1,'H');
std::cout<<s.Str()<<std::endl;
//s.Insert(15,'&');
//std::cout<<s.Str()<<std::endl;
//PopBack函數測試
s.PopBack();
std::cout<<s.Str()<<std::endl;
//Erase函數測試
s.Erase(2,3);
std::cout<<s.Str()<<std::endl;
s.Erase(5,10);
std::cout<<s.Str()<<std::endl;
//Find函數測試
size_t ret = s.Find('a');
//size_t ret = s.Find('h');
if(ret != String::npos)
{
printf("找到了\n");
}
else
{
printf("沒找到\n");
}
}
int main()
{
Test();
return 0;
}
問題1:如何擴容???
答:呈2倍的增長。但不是一定就是2倍增的,看情況(Linux下是2倍,vs下是1/2倍)。那麼爲什麼2倍的增比較好?因爲如果增多了就很有可能造成空間的極大浪費,而增2倍即有了空間也不至於過於頻繁的去進行增容。
問題2:Reverse()和Resize()的區別???
這個在代碼的兩個函數實現處的註釋中已經說明