目录
一,标准库中的string类
string类
string类的常用接口说明
二,string类的模拟实现
经典string类问题
浅拷贝
深拷贝
写时拷贝(了解)
string类的模拟实现
C语言中,字符串是以“\0”结尾的字符集合;C标准库提供了一些str库函数,但库函数与字符串是分开的,不符合OOP思想,且底层空间需要用户自己管理,容易越界访问;
注:编码格式,ASCII、UTF-8/16/32等;
一,标准库中的string类
总结
注:在使用string类时,必须包含#include
string类对象的常见构造
//构造
int main()
{
char str[] = "aba";
string s1; //默认无参数构造
string s2(str); //复制以空结尾的字符序列(C字符串)
string s3(s2); //拷贝构造,即复制
string s4(5, 'a'); //填充5个连续的a
}
string类对象的容量操作
注:
int main()
{
string s("abcd");
cout << s.size() << endl;
cout << s.length() << endl;
s.resize(6);
cout << s.size() << endl;
s.resize(10, 'c');
cout << s << endl;
s.reserve(20);
cout << s.capacity() << endl;
}
string类对象的访问及遍历操作
int main()
{
string s("abcdefg");
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
cout << endl;
//迭代器遍历
//string::iterator it = s.begin();
auto it1 = s.begin();
while (it1 != s.end())
{
cout << *it1;
it1++;
}
cout << endl;
//反向遍历
auto it2 = s.rbegin();
while (it2 != s.rend())
{
cout << *it2;
it2++;
}
cout << endl;
//范围for遍历
for (auto i:s)
{
cout << i;
}
return 0;
}
string类对象的修改操作
int main()
{
string s("abc");
s.push_back('d');
s.append("efg");
s += "hijk";
cout << s.c_str() << endl;
cout << s.find('c') << endl;
cout << s.find("hij", 2) << endl;
cout << s.substr(2, 3) << endl;
cout << s.insert(0, "ab") << endl;
s.reserve(20);
cout << s.erase() << endl; //size为0,capacity不变,类似clear
return 0;
}
string类非成员函数(即全局函数)
int main()
{
string s1;
cin >> s1;
cout << s1 << endl;
getline(cin, s1);
string s2 = "abcd";
getline(cin, s2); //会清除和覆盖之前内容
cout << s2 << endl;
return 0;
}
注:
二,string类的模拟实现
class string
{
public:
//构造函数
string(const char* str = "")
{
if(nullptr = str)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
//析构函数
~string()
{
if(_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char* _str;
};
int main()
{
string s1("abcd");
string s2(s1); //调用默认拷贝构造,值拷贝或浅拷贝
return 0;
}
//传统保守写法
//拷贝构造
string(const string& s)
:_str(new char[strlen(s._str) + 1])
{
strcpy(_str, s._str);
}
//赋值运算符重载
string& operator=(const string& s)
{
if (this != &s)
{
char* tmp = new char[strlen(s._str) + 1];
strcpy(tmp, s._str);
delete[]_str;
_str = tmp;
}
return *this;
}
//析构函数,因为新开了空间
~string()
{
if(_str)
{
delete[] _str;
_str = nullptr;
}
}
//现代写法
//拷贝构造
string(const string& s)
:_str(nullptr)
{
//利用默认构造函数,申请新空间,然后交换
string strtmp(s._str);
swap(_str, strtmp._str);
}
//赋值运算符重载
string& operator=(string s)
{
//直接传值传参调用拷贝构造,然后交换
swap(_str, s._str);
return *this;
}
//赋值运算符重载
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// string strtmp(s._str);
// swap(_str, strtmp._str);
// }
// return *this;
//}
注:数组越界读一般检测不出来,越界写是抽查可能会检测出来;string都会被检测出来;
注:vs是深拷贝,不是写实拷贝,g++是写时拷贝;
namespace mystring
{
class string
{
public:
//迭代器iterator
typedef char* iterator;
typedef const char* const_iterator;
iterator begin() { return _str; }
iterator end() { return _str + _size; }
const_iterator begin()const { return _str; }
const_iterator end()const { return _str + _size; }
public:
//默认构造
string(const char* str = "") //也可为"\0"
{
_size = strlen(str);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
//拷贝构造
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string tmp(s._str);
swap(tmp);
}
//赋值运算符重载
string& operator=(string s)
{
swap(s);
return *this;
}
//析构函数
~string()
{
delete[]_str;
_str = nullptr;
}
//Capacity
void reserve(size_t newcapacity)
{
if (_capacity < newcapacity)
{
char* str = new char[newcapacity + 1];
strcpy(str, _str);
delete[] _str;
_str = str;
_capacity = newcapacity;
}
}
void resize(size_t newsize, char c = '\0')
{
if (newsize > _capacity)
reserve(newsize);
for (size_t i = _size; i < newsize; i++)
_str[i] = c;
_size = newsize;
_str[_size] = '\0';
}
//访问
char& operator[](size_t index)
{
assert(index < _size);
return _str[index];
}
const char& operator[](size_t index) const
{
assert(index < _size);
return _str[index];
}
const char* c_str()const
{
return _str;
}
//修改
void push_back(char c)
{
//if (_size == _capacity)
//{
// size_t newcapacity = _capacity ? _capacity * 2 : 4;
// reserve(newcapacity);
//}
//_str[_size++] = c;
//_str[_size] = '\0';
insert(_size, c);
}
void append(const char* str)
{
//size_t len = strlen(str);
//if (_size + len > _capacity)
//{
// reserve(_size + len);
//}
//strcpy(_str + _size, str);
//_size += len;
insert(_size, str);
}
string& operator+=(char c)
{
push_back(c);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
string& operator+=(const string& s)
{
*this += s._str; //append(s._str);
return *this;
}
string& insert(size_t pos, char c)
{
assert(pos <= _size);
if (_size == _capacity)
{
size_t newcapacity = _capacity ? _capacity * 2 : 4;
reserve(newcapacity);
}
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[end] = c;
++_size;
_str[_size] = '\0';
return *this;
}
string& insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
size_t end = _size + 1;
while (end > pos)
{
_str[end + len - 1] = _str[end - 1];
--end;
}
for (int i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
return *this;
}
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
if (len == npos || len >= _size - pos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
//查找
size_t find(char c, size_t pos = 0) const
{
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == c)
return i;
}
return npos;
}
//kmp方法,bm方法
size_t find(char* substr, size_t pos = 0) const
{
const char* p = strstr(_str + pos, substr);
if (p == nullptr)
return npos;
else
return p - _str;
}
void clear()
{
_size = 0;
}
//交换
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
size_t size()const
{
return _size;
}
size_t capacity()const
{
return _capacity;
}
const static size_t npos;
private:
char* _str;
size_t _size;
size_t _capacity; //不包含'\0'
};
const size_t string::npos = -1;
//非成员函数重载
//+尽量少用
string operator+(const string& s, const char c)
{
string tmp = s;
tmp += c;
return tmp;
}
string operator+(const string& s, const char* str)
{
string tmp = s;
tmp += str;
return tmp;
}
string operator+(const string& s1, const string& s2)
{
string tmp = s1;
tmp += s2;
return tmp;
}
std::istream& operator>>(std::istream& in, string& s)
{
//in >> ch; //获取不到' '或'\0'
s.clear();
char c = in.get();
while (c != ' ' && c != '\n')
{
s += c;
c = in.get();
}
return in;
}
std::ostream& operator<<(std::ostream& out, const string& s)
{
for (size_t i = 0; i < s.size(); i++)
{
out << s[i];
}
return out;
}
std::istream& getline(std::istream& in, string& s)
{
s.clear();
char c = in.get();
while (c != '\n')
{
s += c;
c = in.get();
}
return in;
}
bool operator>(const string& s1, const string s2)
{
size_t i1 = 0, i2 = 0;
while (i1 < s1.size() && i2 < s2.size())
{
if (s1[i1] > s2[i2])
return true;
else if (s1[i1] < s2[i2])
return false;
else
{
++i1;
++i2;
}
}
if (i1 == s1.size())
return false;
else
return true;
}
bool operator==(const string& s1, const string s2)
{
size_t i1 = 0, i2 = 0;
while (i1 < s1.size() && i2 < s2.size())
{
if (s1[i1] != s2[i2])
return false;
else
{
++i1;
++i2;
}
}
if (i1 == s1.size() && i2 == s2.size())
return true;
else
return false;
}
inline bool operator!=(const string& s1, const string s2)
{
return !(s1 == s2);
}
inline bool operator>=(const string& s1, const string s2)
{
return (s1 > s2 || s1 == s2);
}
inline bool operator<(const string& s1, const string s2)
{
return !(s1 >= s2);
}
inline bool operator<=(const string& s1, const string s2)
{
return !(s1 > s2);
}
}