3. string类的模拟实现
string的构造函数一大堆,用常用的去实现就可以了,蓝色的就是最常用的之一。
operator[]有两个版本,意义是不一样的,普通对象调用第一个,能读能写,const对象调用第二个,只能读。
end()指向的是有效字符的下一个位置。
范围for识别成迭代器,并且名字都不能变,iterator就是迭代器,begin()和end()名字都不能变。
整型提升是小的范围向大的范围提升。
流插入和流提取是允许拷贝的。
常规情况下,流插入和c_str()是没有差别的,有一种情况下是有差别的,c_str()是返回C型的字符串,c型字符串是怎么打印的呢,相当于打印的是一个内置类型,内置类型也就相当于打印的const char* ,const char*打印的原则是遇到“\0”就终止了,而流插入的重载,不管\0,跟\0没有关系,它用范围for或者size()的长度去走,长度是多长,实际就要打印多长。
C语言的字符数组,以\0为终止算长度,string不看\0,以size为终止算长度。
下面是string的模拟实现源代码:
string.h
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
//迭代器也要写两个版本,一个普通对象用,一个const对象用
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
//string 的构造函数不能用字符串直接去初始化,必须要开空间尽可能用初始化列表去初始化。
//string(const char* str)
// :_str(new char[strlen(str) + 1])
// ,_size(strlen(str))
// //capacity不包含\0,一般不包含,因为capacity指的是能包含多少个有效字符,\0不是有效字符
// ,_capacity(strlen(str))
//{
// strcpy(_str, str);
//}
//无参默认构造
//下面这样写不行,如果这样写,_str是空指针,相当于c_str对空指针解引用,程序就会崩溃
//string()
// :_str(nullptr)
// ,_size(0)
// ,_capacity(0)
//{}
//这样写才是对的
//string()
// :_str(new char[1])
// , _size(0)
// , _capacity(0)
//{
// _str[0] = '\0';
//}
//下面是无参和有参初始化合并后的
//string(const char* str = '\0')1.
//string(const char* str = nullptr)2.
//1和2都是错的
//string(const char* str = "\0")可以这样写,但是没必要,这个地方有两个\0
//下面是最优写法
string(const char* str = "")//虽然为空,但是有标识字符\0
:_str(new char[strlen(str) + 1])
,_size(strlen(str))
//capacity不包含\0,一般不包含,因为capacity指的是能包含多少个有效字符,\0不是有效字符
,_capacity(strlen(str))
{
memcpy(_str, str, _size + 1);
}
//拷贝构造的传统写法
//string(const string& s)
//{
// _str = new char[s._capacity + 1];
// memcpy(_str, s._str, s._size + 1);
// _size = s._size;
// _capacity = s._capacity;
//}
//拷贝构造的现代写法
string(const string& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
string tmp(s._str);
swap(tmp);
}
//下面两个函数建议加const
const char* c_str()const
{
return _str;
}
//遍历string
size_t size()const
{
return _size;
}
//operator[]有两个版本,意义是不一样的,普通对象调用第一个,能读能写,const对象调用第二个,只能读。
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
//增删查改
//这里的扩容逻辑用reserve就可以
void reserve(size_t n)
{
cout << "reserve->" << n << endl;
if (n > _capacity)
{
char* tmp = new char[n + 1];
//strcpy(tmp, _str);
memcpy(tmp, _str, _size + 1);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void push_back(char ch)
{
if (_size == _capacity)
{
//二倍扩容
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size++] = ch;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
//至少扩容到_size + len
reserve(_size + len);
}
//strcpy(_str + _size, str);
memcpy(_str + _size, str, len + 1);
_size += len;
}
string& operator+=(const char str)
{
push_back(str);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
void insert(size_t pos, size_t n, char ch)
{
assert(pos <= _size);
if (_size + n > _capacity)
{
//至少扩容到_size + len
reserve(_size + n);
}
//挪动数据
size_t end = _size;
while (end >= pos && end != npos)
{
_str[end + n] = _str[end];
end--;
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = ch;
}
_size += n;
}
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);if (_size + len > _capacity)
{
//至少扩容到_size + len
reserve(_size + len);
}
//挪动数据
size_t end = _size;
while (end >= pos && end != npos)
{
_str[end + len] = _str[end];
end--;
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
}
~string()
{
if(_str)
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
}
void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos || len + pos >= _size)
{
_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end = pos + len;
while (pos <= _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
}
}
size_t find(char ch, size_t pos = 0)
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
//没有找到的话,返回的都是npos
return npos;
}
size_t find(const char* str, size_t pos = 0)
{
assert(pos < _size);
//暴力匹配
const char* ptr = strstr(_str + pos, str);
if (ptr)
{
return ptr - _str;
}
else
{
return npos;
}
}
string substr(size_t pos = 0, size_t len = npos)
{
size_t n = len;
if (len == npos || len + pos > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < pos + n; i++)
{
tmp += _str[i];
}
return tmp;
}
void resize(size_t n, char ch = '\0')
{
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
bool operator<(const string& s) const
{
//size_t i1 = 0;
//size_t i2 = 0;
//while (i1 < _size && i2 < _size)
//{
// if (_str[i1] < s._str[i2])
// {
// return true;
// }
// else if (_str[i1] > s._str[i2])
// {
// return false;
// }
// else
// {
// i1++;
// i2++;
// }
//}
if (i1 == _size && i2 != s._size)
{
return true;
}
else
{
return false;
}
//return i1 == _size && i2 != s._size;
//下面的代码也可以实现
int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
return ret == 0 ? _size < s._size : ret < 0;
}
bool operator==(const string& s) const
{
return _size == s._size &&
memcmp(_str, s._str, _size) == 0;
}
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
{
return !(*this == s);
}
///传统写法
//string& operator=(const string& s)
//{
// if (this == &s)
// {
// char* tmp = new char[s._capacity + 1];
// memcpy(tmp, s._str, s._size + 1);
// delete[] _str;
// _str = tmp;
// _size = s._size;
// _capacity = s._capacity;
// }
// return *this;
//}
//上面的代码用现代的写法
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size,s._size);
std::swap(_capacity,s._capacity);
}
//string& operator=(const string& s)
//{
// if (this != &s)
// {
// string tmp(s);
// swap(tmp);
// }
// return *this;
//}
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
private:
char* _str;
size_t _size;
size_t _capacity;
public:
static size_t npos;//静态成员变量不走初始化列表,它不属于某一个类,而是属于整个类
//下面这个可以不用定义,但本质还是缺省值
//const static size_t npos = -1;
//const static的整型是可以的,double不可以
//const static double x = 1.1;
const static double x;
};
ostream& operator<<(ostream& out, const string& s)
{
//for (size_t i = 0; i < s.size(); i++)
//{
// out << s[i];
//}
for (auto ch : s)
{
cout << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch = in.get();
//char ch;
//in >> ch;
//处理缓冲区前面的空格或者换行
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
char buff[128];
int i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[i] = '\0';
s += buff;
i = 0;
}
//in >> ch;
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
size_t string::npos = -1;
const double string::x = 1.1;
};
//ostream& operator<<(ostream& out, const bit::string& s)
//{
// //for (size_t i = 0; i < s.size(); i++)
// //{
// // out << s[i];
// //}
// for (auto ch : s)
// {
// cout << ch;
// }
// return out;
//}
text.cpp
#include"string.h"
void test_string1()
{
bit::string s1("hello world");
cout << s1.c_str() << endl;
bit::string s2;
cout << s2.c_str() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
++s1[i];
--s1[i];
}
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i];
}
cout << endl;
const bit::string s3("hello world");
s3[0];
//iterator要指定类域,如果没有指定会去全局去找iterator这个东西
bit::string::const_iterator it = s3.begin();
while (it != s3.end())
{
cout << *it;
it++;
}
cout << endl;
for (auto e : s3)
{
cout << e;
}}
void test_string2()
{
bit::string s1("hello world");
cout << s1.c_str() << endl;
//s1.push_back(' ');
//s1.push_back('#');
//s1.push_back('%');
//s1.append("hello lsw");
//s1.append("hello xsq");
//cout << s1.c_str() << endl;
s1 += ' ';
s1 += '#';
s1 += '%';
s1 += "hello world";
cout << s1.c_str() << endl;
}
void test_string3()
{
bit::string s1("hello world");
cout << s1.c_str() << endl;
s1.insert(0, 3, '#');
cout << s1.c_str() << endl;
bit::string s2("helloworld");
s2.insert(5, "%%%%%");
cout << s2.c_str() << endl;
}
void test_string4()
{
bit::string s1("hello world");
cout << s1.c_str() << endl;
s1.erase(5, 3);
cout << s1.c_str() << endl;
s1.erase(5, 30);
cout << s1.c_str() << endl;
s1.erase(2);
cout << s1.c_str() << endl;
}
void test_string5()
{
// 2118
bit::string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";size_t pos1 = url.find("://");
if (pos1 != bit::string::npos)
{
bit::string protocol = url.substr(0, pos1);
cout << protocol.c_str() << endl;
}size_t pos2 = url.find('/', pos1 + 3);
if (pos2 != bit::string::npos)
{
bit::string domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
bit::string uri = url.substr(pos2 + 1);cout << domain.c_str() << endl;
cout << uri.c_str() << endl;
}
}
void test_string6()
{
bit::string s("hello world");
//s.resize(8);
//cout << s.c_str() << endl;
//s.resize(13, 'x');
//cout << s.c_str() << endl;
//s.resize(20, 'y');
s.resize(8);
cout << s << endl;
s.resize(13, 'x');
cout << s << endl;
s.resize(20, 'y');
cout << s << endl;
bit::string ss("hello world");
ss += '\0';
ss += "!!!!!!!!";
cout << ss.c_str() << endl;
cout << ss << endl;
bit::string copy(ss);
cout << ss << endl;
cout << copy << endl;
copy += "xxxxxxxxxxxxxx";
cout << copy << endl;
}void test_string7()
{
bit::string s;
cin >> s;
cout << s << endl;
cin >> s;
cout << s << endl;
}void test_string8()
{
//bit::string s1("bbb");
//bit::string s2("aaa");
//cout << (s1 < s2) << endl;
bit::string s1("hello");
bit::string s2("hello");
cout << (s1 < s2) << endl;
cout << (s1 > s2) << endl;
cout << (s1 == s2) << endl << endl;
bit::string s3("hello");
bit::string s4("helloxxx");
cout << (s3 < s4) << endl;
cout << (s3 > s4) << endl;
cout << (s3 == s4) << endl << endl;
bit::string s5("helloxxx");
bit::string s6("hello");
cout << (s5 < s6) << endl;
cout << (s5 > s6) << endl;
cout << (s5 == s6) << endl << endl;
}void test_string9()
{
bit::string s1("hello");
bit::string s2(s1);
cout << s1 << endl;
cout << s2 << endl;
bit::string s3("xxxxxxxxxxxxx");
s1 = s3;
cout << s1 << endl;
cout << s3 << endl;
}
int main()
{
test_string9();
return 0;
}