头文件:
#pragma once
#include<iostream>
#include<assert.h>
#include<string.h>
namespace tc
{
class string
{
friend std::ostream& operator<<(std::ostream& _cout, const tc::string& s)
{
iterator it = s.begin();
while (it != s.end())
{
_cout << *it;
++it;
}
return _cout;
}
public:
typedef char* iterator;//简单的把迭代器理解为指针;
public:
string(const char* str = "")
{
if (str == nullptr)
{
str = "";
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
_capacity = strlen(str);
_size = strlen(str);
}
///
string(const string& s)
:_str(nullptr), _size(0), _capacity(0)
{
_size = strlen(s._str);
_capacity = _size;
string tmp(s._str);
std::swap(tmp._str, _str);
}
///
string& operator=(const string& s)
{
string tmp(s);
std::swap(_str, tmp._str);
return *this;
}
~string()
{
if (_str)
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
}
//
// iterator
iterator begin() const
{
return _str;
}
iterator end() const
{
return (_str + _size);
}
/
// modify
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity * 1.5 + 3);
}
_str[_size] = c;
++_size;
_str[_size] = '\0';
}
string& operator+=(char c)
{
push_back(c);
return *this;
}
string& operator+=(const string& s)
{
*this += s._str;
return *this;
}
string& operator+=(const char* str)
{
int newcapacity = _size + strlen(str);
reserve(newcapacity);
strcat(_str, str);
_size = newcapacity;
*(_str + _size) = '\0';
return *this;
}
string& append(const char* str)
{
*this += str;
return *this;
}
string& append(const string& s)
{
*this += s._str;
return *this;
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
const char* c_str()const
{
return _str;
}
/
// capacity
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
bool empty()const
{
return (_size == 0);
}
void resize(size_t n, char c = '\0')
{
int oldsize = _size;
if (n > oldsize)
{
if (n > _capacity)
{
reserve(n);
}
//多余的地方用字符c填充
memset(_str + _size, c, n - _size);
}
_size = n;
_str[_size] = '\0';
}
void reserve(size_t n)
{
int oldcapacity = _capacity;
if (n > oldcapacity)
{
int newcapacity = n + 1;
char* tmp = new char[newcapacity];
if (tmp == nullptr)
{
assert(0);
}
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
/
// access
char& operator[](size_t index)
{
assert(index < _size);
return *(_str + index);
}
const char& operator[](size_t index)const
{
assert(index < _size);
return *(_str + index);
}
char& at(size_t index)
{
if (index >= _size)
throw std::out_of_range("index >= _size");
return _str[index];
}
const char& at(size_t index)const
{
if (index >= _size)
throw std::out_of_range("index >= _size");
return _str[index];
}
/
//relational operators
bool operator<(const string& s)
{
return (strcmp(_str, s._str) < 0);
}
bool operator<=(const string& s)
{
return ((strcmp(_str, s._str) < 0) || (strcmp(_str, s._str) == 0));
}
bool operator>(const string& s)
{
return (strcmp(_str, s._str) > 0);
}
bool operator>=(const string& s)
{
return ((strcmp(_str, s._str) > 0) || (strcmp(_str, s._str) == 0));
}
bool operator==(const string& s)
{
return (strcmp(_str, s._str) == 0);
}
bool operator!=(const string& s)
{
return (strcmp(_str, s._str) != 0);
}
// 返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
for (int i = pos; i < _size; ++i)
{
if (*(_str + i) == c)
{
return i;
}
}
return npos;
}
size_t rfind(char c, size_t pos = npos) const
{
if (pos == npos || pos >= _size)
pos = _size - 1;
int i = pos;
while (i >= 0)
{
if (_str[i] == c)
return i;
--i;
}
return npos;
}
// 返回子串s在string中第一次出现的位置
// 在pos位置上插入字符c/字符串str,并返回该字符的位置
iterator insert(iterator pos, char c)
{
if (pos <begin() || pos >end())
{
return end();
}
if (_size == _capacity)
{
reserve(_size * 1.5 + 3);
}
iterator it = end() - 1;
while (it >= pos)
{
*(it + 1) = *it;
--it;
}
++_size;
_str[_size] = '\0';
*(it + 1) = c;
}
// 删除pos位置上的元素,并返回该元素的下一个位置
iterator erase(iterator pos, size_t len)
{
if (pos < begin() || pos >= end())
{
return end();
}
iterator it = pos + 1;
while (it != end())
{
*(it - 1) = *it;
it++;
}
--_size;
_str[_size] = '\0';
return pos;
}
private:
char* _str;
size_t _capacity;
size_t _size;
const static int npos = -1;
};
}
源文件:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"mystring.h"
int main()
{
tc::string s1("my");
const char* str = "name is ";
tc::string s2(str);
tc::string s3("csdn");
std::cout << s1 << std::endl;
std::cout << s2 << std::endl;
std::cout << s3 << std::endl;
tc::string s4;
s4 += s1;
s4 += s2;
s4 += s3;
std::cout << s4 << std::endl;
s4.push_back('~');
std::cout << s4 << std::endl;
size_t index = s4.find('y', 0);
tc::string::iterator it = s4.begin() + index + 1;
s4.insert(it, ' ');
index = s4.find('e', 0);
it = s4.begin() + index + 1;
s4.insert(it, ' ');
std::cout << s4 << std::endl;
return 0;
}
其实没什么难点,string内部实现的其实就是一个维护字符类型的顺序表;
但要注意:
1、在开辟空间的时候,不能直接给oldcapacity * 1.5,要加上一个随机值,不然第一次是0,那乘出来也是0,就开不了空间了;
2、构造函数中,给出一个字符串的情况下,要提防给出nullptr,对nullptr进行操作是不合法的,所以要赋值成"",
而对于用常量字符串构造的情况下,需要在初始化列表中给出指针的默认值,在2019以上的vs版本,会给出无初始化的指针为nullptr,而在低版本编译器中,会给出值为随机值,是一个野指针,对其进行操作也是不合法的;
而给出一个string对象的情况下,传引用可以少调用一次拷贝函数,我们可以通过swap函数交换它们指针的方式,先创建一个临时变量tmp然后让tmp中的_str和this->_str交换即可,不可以直接用传进来的引用swap。。。这样意思就变了
3、对于构造函数来说,其实有很多种写法
比如:
string(const string& s):_str(nullptr)
{
string tmp(s._str);
std::swap(tmp._str,_str);
}
这个方法实现的前提是,给出了用指针拷贝构造的方法
或者
string(const string& s):_str(new char[strlen(s) + 1]
{
strcpy(_str,s._str);
}
这种就比较好理解,意思就是直接给_str初始化指向堆上一段大小为strlen(s) + 1的空间(+1是为了放\0),然后用strcpy将s._str中的内容拷贝进this->_str
对于运算符重载其实也有几种写法:
string& operator=(const string& s)
{
string tmp(s);
std::swap(s._str,_str);
return *this;
}
string& operator=(const string s)
{
string tmp(s);
std::swap(_str,tmp._str);
return *this;
}