typedef char* iterator;
typedef const char* const_iterator;
定义迭代器的类型。iterator
是一个指向 char
类型的指针,可以用来访问和修改 char
类型的数据。而 const_iterator
是一个指向常量 char
类型的指针,只能用来访问 char
类型的数据,不能修改。
//迭代器:开始
iterator begin()
{
return _str;
}
//迭代器:结束
iterator end()
{
return _str + _size;
}
//const迭代器:开始
const_iterator begin() const
{
return _str;
}
//const迭代器:结束
const_iterator end() const
{
return _str + _size;
}
begin()
返回一个迭代器的起始位置end()
返回一个迭代器的结束位置begin() const
是一个常量迭代器,只能访问,不能修改,返回一个迭代器的end() const
是一个常量迭代器,只能访问,不能修改,返回一个迭代器的结束位置//构造函数
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
, _str(new char[_capacity + 1])
{
//strcpy(_str, str);
memcpy(_str, str, _size + 1);
}
const char*
类型的参数str
,默认为空字符串_size(strlen(str))
计算字符串的字符串的大小_capacity(_size)
计算字符串的容量_str(new char[_capacity + 1])
在堆上分配一个字符数组,将他的地址赋给成员变量———_str
,用来存放字符串的指针memcpy
函数将参数str
的内容复制到_str
指向的内存空间中,这里使用memcpy
函数而不是strpy
函数,是因为memcpy
函数能够复制给定长度的字符到目标区域,而strcpy
函数遇到\0
就结束了,+1是为了在_str字符数组的结尾加一个空字符\0//拷贝构造函数
string(const string& s)
{
_str = new char[s._capacity + 1];
memcpy(_str, s._str, s._size + 1);
_size = s._size;
_capacity = s._capacity;
}
const string&
类型的参数 s
,表示要拷贝的字符串对象。new char[s._capacity + 1]
在堆上动态分配了一个字符数组,并将它的地址赋给成员变量 _str
,即存储字符串的指针。memcpy
函数将s._str
指向的字符串数组的内容复制到_str指向的空间中,+1是为了_str
字符数组的结尾加‘\0’
,保证字符串的正常结束_size = s._size
表示将s._size
的值赋给成员变量_size
,表示字符串的大小_capacity = s._capacity
表示将 s._capacity
的值赋给成员变量 _capacity
,表示字符串的容量。void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string& operator=(string tmp)
{
swap(tmp);
return *this;
}
通过拷贝并交换,将临时对象tmp
和当前对象进行交换,把临时变量tmp的内容拷贝到当前对象中,
最后返回当前对象的引用
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
delete[] _str
释放字符串对象中动态分配的内存空间_str = nullptr
表示将_str
指针置为nullptr
,表示该指针不指向任何有效的内存空间_size
和_capacity
的值全部置为0,表示没有任何空间了const char* c_str() const
{
return _str;
}
c_str()
函数返回一个指向字符串数组的常量指针,指向的字符可以用来读取字符串的内容,但不能修改。
size_t size() const
{
return _size;
}
这段代码是一个字符串类中的成员函数 size()
的实现,其功能是返回字符串对象中存储的字符数量。
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
函数的返回类型是char&
,表示返回一个字符的引用。 函数名是operator[]
,表示这个函数是对[]运算符的重载。函数参数是size_t pos
,表示要访问的元素的位置。assert断言确保pos
小于数组的大小_size
,函数返回 _str[pos]
,即数组中位置为 pos 的字符的引用。
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
函数的返回类型是const char&
,表示返回一个字符的常量引用。 函数名是operator[]
,表示这个函数是对[]运算符的重载。 函数参数是size_t pos
,表示要访问的元素的位置。
在函数的实现中,首先通过assert语句进行断言验证,确保要访问的位置 pos
小于数组的大小 _size
,以防止越界访问。然后,函数返回 _str[pos]
,即数组中位置为 pos
的字符的常量引用。
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
memcpy(tmp, _str, _size + 1);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
_capacity
,重新分配更大的空间tmp
,大小为n+1
,用来存储新分配的内存空间。接着,将_str
的内容复制到tmp
中。_str
的内存空间,在将指针_str
指向tmp
_capacity
的值为nvoid 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';
}
}
如果需要调整的大小n小于当前的大小_size
,就缩小字符串的大小。将_size
更新为n,将_str[_size]设置为‘\0’
,截断字符串保留前个字符串,字符串以‘\0’
结尾
如果需要调整的大小n大于等于当前的大小_size
,扩大字符串并且填充新位置。
void push_back(char ch)
{
if (_size == _capacity)
{
//二倍扩容
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
_size
等于_capacity
进行扩容ch
赋值给字符串_str的末尾位置,并且将字符串的大小_size
+1_str[_str]
设置为‘\0’,以确保字符串以‘\0’结尾void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
//至少扩容到_size+len
reserve(_size + len);
}
memcpy(_str + _size, str, len + 1);
_size += len;
}
_size
加上要添加的字符串的长度 len
超过了容量 _capacity
就需要扩容;如果小于等于就不需要扩容。_size+len
,函数使用memcpy
函数将要添加的字符串str复制到当前字符串的末尾位置_str
+_size
_size
,因为字符串的最后一个字符默认是‘\0’
,不需要再设置了string& operator+=(char ch)
{
push_back(ch);
return *this;
}
使用push_back
函数,将字符ch
添加到字符串的末尾
实现了字符串对象对字符的追加操作,通过这函数,可以将一个字符追加到字符串的末尾
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+n
reserve(_size + n);
}
int end = _size;
while (end >= (int)pos)
{
_str[end + n] = _str[end];
--end;
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = ch;
}
}
assert
先断言,确保插入位置合法_size+n
ch
插入到指定位置pos
之后。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);
}
int end = _size;
while (end >= (int)pos)
{
_str[end + len] = _str[end];
--end;
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
}
pos
不超过当前字符串的长度_size
_size+len
超过当前容量_capacity
,就进行扩容_size
,将__size
添加len
的值void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end = pos + len;
while (end <= _size)
{
_str[pos++] = _str[end++];
}
_size -= len;
}
}
pos
不超过当前字符串的长度_size
end
,即pos+len
;然后使用循环将待删除位置之后的字符逐个向前移动,覆盖待删除的字符;在移动字符完毕后,将字符串的长度减去待删除的长度len
,即_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;
}
}
return npos;
}
_size
,避免越界。ch
ch
相等的字符,则返回该字符的索引位置i
ch
相等的字符`,则返回npos
,表示没有找到size_t find(const char* str, size_t pos = 0)
{
assert(pos < _size);;
const char* ptr = strstr(_str, str);
if (ptr)
{
return ptr - _str;
}
return npos;
}
assert
验证起始位置pos
是否小于字符串的长度_size
,防止越界。strstr()
在_str
字符串中查找子字符串str
的出现位置。如果找到了返回一个指向第一次出现的位置的指针,如果找不到则返回NULL
str
,则使用指针相减的方式计算出相对于-str
的偏移量,即所求的起始位置npos
,表示没有找到string substr(size_t pos = 0, size_t len = npos)
{
assert(pos < _size);
size_t n = len;
if (len == npos || pos + len > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < pos + n; i++)
{
tmp += _str[i];
}
return tmp;
}
assert
验证起始位置pos是否小于字符串的长度,避免越界。len
为npos
或者pos+len
超过了字符串的长度,n
被设置为从pos
到字符串末尾的长度tmp
,并使用reserve()
为该字符串分配足够的容量以容纳字符串pos
到pos+n
的字符添加到tmp
字符串中tmp
字符串对象void clear()
{
_str[0] = '\0';
_size = 0;
}
_str[0]
设置为‘\0’
来将字符串的内容置为空_size
设置为0,表示字符串中不包含任何字符//<
bool operator<(const string& s)
{
int ret = memcmp(_str, s._str,_size
函数内部使用了memcmp
函数进行字符串的比较。memcmp
函数比较两个内存块的内容,并返回一个整数作为比较的结果。
在这个函数中,memcmp
函数比较了两个字符串的内存块的内容和大小:
它使用了_str
和s._str
来分别表示当前字符串对象和参数字符串对象的内存块。
_size
和s._size
表示当前字符串对象和参数字符串对象的大小。
函数中的表达式_size < s._size ? _size : s._size
是为了确定两个字符串之间较小的大小,以便在memcmp
函数中进行比较。
函数通过比较memcmp
函数的返回值和0来判断两个字符串的大小关系:
函数最终返回一个bool类型的值表示最终的大小比较结果:
ret
等于0,则返回_size < s._size
的结果,表示当前字符串对象的大小是否小于参数字符串对象的大小。ret
小于0,则直接返回true,表示当前字符串对象小于参数字符串对象。false
,表示当前字符串对象大于参数字符串对象。//==
bool operator==(const string& s)
{
return _size == s._size && memcpy(_str, s._str, _size) == 0;
}
size
== s._size
判断当前字符串对象和参数字符串对象的大小是否相等,如果不相等就直接返回false
。memcpy
函数来比较当前字符串对象和参数字符串对象的内容。如果两个字符串的内容相等,那么memcpy
函数会返回0。 所以,函数体内的memcmp(_str, s._str, _size) == 0
即为比较当前字符串对象和参数字符串对象的内容是否相等。_size
== s._size
&& memcmp(_str, s._str, _size) == 0
的结果,即当前字符串对象和参数字符串对象的大小相等并且内容相等,则返回true
,表示两个字符串相等;否则返回false
,表示两个字符串不相等。//<=
bool operator<=(const string& s)
{
return *this < s || *this == s;
}
*this < s
判断当前字符串对象是否小于参数字符串对象。如果当前字符串对象小于参数字符串对象,则返回true
。*this == s
判断当前字符串对象是否等于参数字符串对象。如果当前字符串对象等于参数字符串对象,则返回true
。*this < s || *this == s
的结果,即当前字符串对象小于等于参数字符串对象则返回true
,否则返回false
。//>
bool operator>(const string& s)
{
return !(*this <= s);
}
*this <= s
判断当前字符串对象是否小于等于参数字符串对象。如果当前字符串对象小于等于参数字符串对象,则返回false
。!(*this <= s)
判断当前字符串对象不小于等于参数字符串对象。如果当前字符串对象不小于等于参数字符串对象,则返回true
。//>=
bool operator>=(const string& s)
{
return !(*this < s);
}
*this < s
判断当前字符串对象是否小于参数字符串对象。如果当前字符串对象小于参数字符串对象,则返回false
。!(*this 判断当前字符串对象不小于参数字符串对象。如果当前字符串对象不小于参数字符串对象,则返回true
。
//!=
bool operator!=(const string& s)
{
return !(*this == s);
}
*this == s
判断当前字符串对象是否等于参数字符串对象。如果当前字符串对象等于参数字符串对象,则返回false。!(*this == s)
判断当前字符串对象不等于参数字符串对象。如果当前字符串对象不等于参数字符串对象,则返回true
。ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch=in.get();
//处理掉缓冲区前面的空格或者换行
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
//in >> ch;
char buff[128] = { '\0' };
int i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
#pragma once
#include
#include
#include
#include
#include
using namespace std;
namespace bit
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
//迭代器:开始
iterator begin()
{
return _str;
}
//迭代器:结束
iterator end()
{
return _str + _size;
}
//const迭代器:开始
const_iterator begin() const
{
return _str;
}
//const迭代器:结束
const_iterator end() const
{
return _str + _size;
}
/*string()
:_size(0)
,_capacity(0)
,_str(new char[1])
{
_str[0] = '\0';
}*/
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
, _str(new char[_capacity + 1])
{
//strcpy(_str, str);
memcpy(_str, str, _size + 1);
}
string(const string& s)
{
_str = new char[s._capacity + 1];
//strcpy(_str, s._str);
memcpy(_str, s._str, s._size + 1);
_size = s._size;
_capacity = s._capacity;
}
//赋值
/*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;
}
~string()
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
const char* c_str() const
{
return _str;
}
size_t size() const
{
return _size;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
//增删查改
void reserve(size_t n)
{
if (n > _capacity)
{
cout << "reverse()->" < _capacity)
{
//至少扩容到_size+len
reserve(_size + len);
}
//strcpy(_str + _size, str);
memcpy(_str + _size, str, len + 1);
_size += len;
//_str[_size] = '\0';
}
string& operator+=(char ch)
{
push_back(ch);
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+n
reserve(_size + n);
}
int end = _size;
while (end >= (int)pos)
{
_str[end + n] = _str[end];
--end;
}
for (size_t i = 0; i < n; i++)
{
_str[pos + i] = ch;
}
}
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);
}
int end = _size;
while (end >= (int)pos)
{
_str[end + len] = _str[end];
--end;
}
for (size_t i = 0; i < len; i++)
{
_str[pos + i] = str[i];
}
_size += len;
}
void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (len == npos || pos + len >= _size)
{
_str[pos] = '\0';
_size = pos;
_str[_size] = '\0';
}
else
{
size_t end = pos + len;
while (end <= _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;
}
}
return npos;
}
size_t find(const char* str, size_t pos = 0)
{
assert(pos < _size);;
const char* ptr = strstr(_str, str);
if (ptr)
{
return ptr - _str;
}
return npos;
}
string substr(size_t pos = 0, size_t len = npos)
{
assert(pos < _size);
size_t n = len;
if (len == npos || pos + len > _size)
{
n = _size - pos;
}
string tmp;
tmp.reserve(n);
for (size_t i = pos; i < pos + n; i++)
{
tmp += _str[i];
}
return tmp;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
//"hello" "hello" false
//"helloxx" "hello" false
//"hello" "helloxx" ture
/*bool operator<(const string& s)
{
size_t i1 = 0;
size_t i2 = 0;
while (i1 < _size && i2 < s._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;
}
}*/
//小于
bool operator<(const string& s)
{
int ret = memcmp(_str, s._str,_size(const string& s)
{
return !(*this <= s);
}
//大于等于
bool operator>=(const string& s)
{
return !(*this < s);
}
//不等于
bool operator!=(const string& s)
{
return !(*this == s);
}
private:
size_t _size;
size_t _capacity;
char* _str;
public:
const static size_t npos;
};
const size_t string::npos = -1;
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch=in.get();
//处理掉缓冲区前面的空格或者换行
while (ch == ' ' || ch == '\n')
{
ch = in.get();
}
//in >> ch;
char buff[128] = { '\0' };
int i = 0;
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 127)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
};
//测试部分
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]++;
}
cout << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
bit::string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto ch : s1)
{
cout << ch << " ";
}
cout << endl;
}
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 bit");
cout << s1.c_str() << endl;
bit::string s2("hello world");
//cout << s1.c_str() << endl;
s2 += '&';
s2 += '%';
s2 += "hello";
cout << s2.c_str() << endl;
}
void test_string3()
{
bit::string s3("hello English");
cout << s3.c_str() << endl;
s3.insert(0, 5, 'x');
cout << s3.c_str() << endl;
bit::string s4("hello wolrd");
cout << s4.c_str() << endl;
s4.insert(5, "abcde");
cout << s4.c_str() << endl;
}
void test_string4()
{
bit::string s5("hello world");
cout << s5.c_str() << endl;
s5.erase(1);
cout << s5.c_str() << endl;
}
//void test_string5()
//{
// bit::string s5("hello world");
// cout << s5.c_str() << endl;
// s5.find('r',1);
// cout << s5.c_str()<< endl;
//
//}
void test_string6()
{
bit::string ur1 = "ftp:://www.baidu.com/?m=1234567";
size_t pos1 = ur1.find("://");
if (pos1 != bit::string::npos)
{
bit::string protocol = ur1.substr(0, pos1);
cout << protocol.c_str() << endl;
}
//cout << protocol.c_str() << endl;
bit::string domain;
bit::string uri;
size_t pos2 = ur1.find('/', pos1 + 3);
if (pos2 != bit::string::npos)
{
bit::string domain = ur1.substr(pos1 + 3, pos2 - (pos1 + 3));
bit::string uri = ur1.substr(pos2 + 1);
cout << domain.c_str() << endl;
cout << uri.c_str() << endl;
}
}
void test_string7()
{
bit::string s("hello world");
s.resize(10);
//cout << s << endl;
s.resize(13, 'x');
cout << s.c_str() << endl;
s.resize(29, 'y');
cout << s.c_str() << endl;
//C的字符数组,以\0为终止算长度
//string不看\0,以size为终止算长度
std::string ss = "hello world";
ss += '\0';
ss += "!!!!!!!!!";
cout << ss.c_str() << endl;
cout << ss << endl;
std::string copy(ss);
cout << ss << endl;
cout << copy << endl;
}
void test_string8()
{
std::string s;
cin >> s;
cout << s << endl;
cin >> s;
cout << s << endl;
}
void test_string9()
{
string s1("bb");
string s2("aaa");
cout << (s1 < s2) << endl;
}
void test_string10()
{
bit::string s1("aaaa");
bit::string s2("aaaa");
cout << (s1 < s2) << endl;
cout << (s1 > s2) << endl;
cout << (s1 == s2) << endl;
cout << (s1 != s2) << endl;
cout << (s1 >= s2) << endl;
cout << (s1 <= s2) << endl;
}
void test_string11()
{
bit::string s1("hello");
//bit::string s2(s1);
s1.append("aaaaaaa");
cout << "s1:" << s1 << endl;
//cout << "s2:" << s2 << endl;
cout << endl;
bit::string s3("xxxxxxxxxx");
s1 = s3;
cout << s1 << endl;
cout << s3 << endl;
}
int main()
{
test_string11();
return 0;
}