😇 😇 各位小伙伴们,大家好!我是bug。今天我们来谈谈STL中容器部分的string:
(代码可能会有一点问题,请各位老铁指正 😘 😘 )
一、string的概念
string :C++中的字符串。
字符串对象是一种特殊类型的容器,专门设计来操作的字符序列。 不像传统的c-strings,只是在数组中的一个字符序列,我们称之为字符数组,而C + +字符串对象属于一个类,这个类有很多内置的特点,在操作方式,更直观,另外还有很多有用的成员函数。
二、string的用法
string的常用接口:
construct(构造函数) | 用法 |
---|---|
string() | 构造空的string类对象,即空字符串 |
string(const char* s) | 用C-string来构造string类对象 |
string(const string&s) | 拷贝构造函数 |
操作空间/容量 | 用法 |
---|---|
size(length) | 返回字符串有效字符长度 |
capacity | 返回字符串空间总大小 |
empty | 判断字符串是否为空 |
clear | 清空有效字符 |
reserve | 为字符串预留空间 |
resize | 调整字符串大小 |
遍历操作 | 用法 |
---|---|
operator[] | 返回pos位置的字符,包括了const和非const的重载 |
begin | begin获取一个字符的迭代器 |
end | end获取最后一个字符下一个位置的迭代器 |
修改操作 | 用法 |
---|---|
push_back | 尾插字符 |
append | 尾插字符串 |
operator+= | 尾插字符/字符串 |
c_str | 返回C语言形式的字符串 |
pop_back | 尾删字符 |
find | 从pos开始查找字符,找到返回下标,找不到返回npos |
rfind | (逆置)从pos开始查找字符,找到返回下标,找不到返回npos |
比较操作 | 用法 |
---|---|
operator>> | 输入 |
operator<< | 输出 |
getline | 获取一行字符串 |
relational operators | 比较大小 |
🌳 (1)string对象的创建
string创建对象的方式有很多,比如:
🌵 使用默认构造函数
🌵 使用带参构造函数
🌵 使用拷贝构造函数
🌵 使用赋值运算符重载
🌵 使用迭代器区间进行构造
🌵 创建匿名对象
🍒 🍒 代码⬇️ ⬇️ :
//创建字符串对象的方式:
//默认构造函数
string s1;
//带参构造函数
string s2("hello world");
//拷贝构造函数
string s3(s2);
//s4.operator=("hello world")
string s4 = "hello world";
//迭代器区间进行构造
string s5(s4.begin(), s4.end());
//匿名对象(生命周期很短)
string();
🌳 (2)string的遍历
string有三种遍历的方式:
🌵 通过[]的重载像数组一样遍历。
🌵 通过迭代器进行遍历。
🌵 通过范围for进行的遍历
🍒 🍒 代码⬇️ ⬇️ (可改变原有数据):
//遍历字符串方式(可以改变原数据):
string s("hello world");
//通过[]重载进行遍历
for (size_t i = 0; i < s.size(); i++)
{
cout << s[i] << " ";
}
cout << endl;
//通过迭代器进行遍历
string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//通过范围for进行遍历
for (auto &e : s)
{
cout << e << " ";
}
cout << endl;
🍒 🍒 代码⬇️ ⬇️ (不可改变原有数据):
//遍历字符串的方式(不会改变原数据):
//通过[]重载遍历(返回值带上const)
const string s("hello world");
for (size_t i = 0; i < s.size(); i++)
{
cout << s[i] << " ";
}
cout << endl;
//通过迭代器进行遍历(调用返回值const修饰的迭代器)
string::const_iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//通过范围for遍历(不使用引用时,将s中的数据赋值给e)
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
注意❗️ ❗️
🌱 (1)[]的重载有const和非const版本的。
🌱 (2)迭代器有const和非const版本的,C98中直接将begin、end进行重载。在C11中为了区别const和非const迭代器,引入了cbegin和cend。(和begin、end的const版本就名字不同)
🌱 (3)范围for的本质是迭代器,程序运行过程中,编译器会把范围for替换成迭代器进行操作。同时范围for是通过赋值的方式进行遍历(将数据赋给变量),如果要修改,就要使用引用。
🌳 (3)string的reserve和resize
🍒 🍒 reserve测试代码⬇️ ⬇️ :
string s1("hello world");//容量为11
cout << s1.capacity() << endl;
//容量没有发生变化
s1.reserve(5);
cout << s1.capacity() << endl;
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
//扩容
s1.reserve(20);
cout << s1.capacity() << endl;
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
🍒 🍒 resize测试代码⬇️ ⬇️ :
string s1("hello world");
cout << s1.capacity() << endl;
//发生扩容
s1.reserve(18);
cout << s1.capacity() << endl;
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
//容量没有发生变化
s1.resize(5);
cout << s1.capacity() << endl;
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
//空位补充'!'
s1.resize(16,'!');
cout << s1.capacity() << endl;
for (auto e : s1)
{
cout << e << " ";
}
cout << endl;
三、string的模拟实现
🍒 🍒 这里我们来模拟实现一个简易的string类⬇️ ⬇️ :
//函数
//构造函数
string(const char* ch = "", size_t size = 0, size_t capacity = 0)
string(InputIterator first, InputIterator last)
string(const string& str, size_t pos, size_t len = npos)
string(const string& str)
//交换函数
void swap(string& str)
string& operator=(const string& str)
string& operator+=(const string& str)
//比较函数
friend bool operator > (const lz::string&, const lz::string&);
friend bool operator >= (const lz::string&, const lz::string&);
friend bool operator != (const lz::string&, const lz::string&);
friend bool operator <= (const lz::string&, const lz::string&);
friend bool operator < (const lz::string&, const lz::string&);
friend bool operator == (const lz::string&, const lz::string&);
//查找修改
void reserve(size_t n)
void resize(size_t n, const char& ch = '\0')
void push_back(const char& ch)
void append(const string& str)
string& insert(size_t pos, const char& ch)
string& insert(size_t pos, const string& str)
void pop_back()
string& erase(size_t pos, size_t len = npos)
bool empty()const
size_t find(const char& ch, size_t pos = 0)const
size_t find(const char* str, size_t pos = 0)const
//遍历
char& operator[](size_t i)
const char& operator[](size_t i)const
const size_t& size()const
const size_t& capacity()const
iterator begin()
iterator end()
const_iterator begin()const
const_iterator end()const
const char* c_str()
//标准输入输出
friend istream& operator>> (istream&, lz::string&);
friend ostream& operator<< (ostream&, const lz::string&);
//变量
char* _str;
size_t _size;
size_t _capacity;
🍒 🍒 完整代码⬇️ ⬇️ :
#include<iostream>
#include<assert.h>
using std::endl;
using std::cin;
using std::cout;
using std::ostream;
using std::istream;
namespace lz
{
class string
{
//比较运算符重载
friend bool operator > (const lz::string&, const lz::string&);
friend bool operator >= (const lz::string&, const lz::string&);
friend bool operator != (const lz::string&, const lz::string&);
friend bool operator <= (const lz::string&, const lz::string&);
friend bool operator < (const lz::string&, const lz::string&);
friend bool operator == (const lz::string&, const lz::string&);
//标准输入输出流重载
friend istream& operator>> (istream&, lz::string&);
friend ostream& operator<< (ostream&, const lz::string&);
public:
//无符号整型最大值
static size_t npos;
//迭代器(指针)
typedef char* iterator;
typedef const char* const_iterator;
//构造函数
string(const char* ch = "", size_t size = 0, size_t capacity = 0)
:_str(new char[strlen(ch) + 1])
, _size(strlen(ch))
, _capacity(strlen(ch))
{
strcpy(_str, ch);
}
//迭代器区间构造函数
template<class InputIterator>
string(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
first++;
}
_str[_size] = '\0';
}
//析构函数
~string()
{
delete[]_str;
_str = nullptr;
_size = _capacity = 0;
}
//交换函数(注意!!优先使用类中的交换函数)
void swap(string& str)
{
std::swap(str._str, _str);
std::swap(str._size, _size);
std::swap(str._capacity, _capacity);
}
//拷贝构造函数
string(const string& str)
{
string tmp(str._str);
swap(tmp);
}
//构造函数(取另一个对象的部分进行构造)
string(const string& str, size_t pos, size_t len = npos)
{
//pos只能比字符串的len小
assert(pos < str._size);
//无符号整形的加减法问题,当len = npos时,巨坑:len + pos == 3 <str._size
if (len > str._size - pos)//*********
{
len = str._size - pos;
}
_str = new char[len + 1];
_size = len;
_capacity = _size;
for (size_t i = 0; i < len; i++)
{
_str[i] = str._str[pos + i];
}
_str[_size] = '\0';
}
//赋值运算符重载
string& operator=(const string& str)
{
string tmp(str);
swap(tmp);
return *this;
}
//扩容
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
if (_size != 0)
{
strcpy(tmp, _str);
}
delete[]_str;
_str = tmp;
_capacity = n;
}
}
//扩容+初始化
void resize(size_t n, const char& ch = '\0')
{
//(1)n < _size (2)n < __caoacity && n > _size (3)n > _capacity
if (n < _size)
{
_size = n;
_str[_size] = '\0';
}
else
{
//扩容
if (n > _capacity)
{
size_t new_capacity = (_capacity == 0 ? 4 : n);
reserve(new_capacity);
}
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_size = n;
_str[_size] = '\0';
}
}
//尾插字符
void push_back(const char& ch)
{
if (_size == _capacity)
{
size_t new_capacity = (_capacity == 0 ? 4 : _capacity * 2);
reserve(new_capacity);
}
_str[_size] = ch;
_str[_size + 1] = '\0';
_size++;
}
//尾插字符串
void append(const string& str)
{
/*for (size_t i = 0; i < str._size; i++)
{
push_back(str._str[i]);
}*/
size_t len = strlen(str._str);
if (len + _size > _capacity)
{
reserve(len + _size + 1);
}
strcpy(_str + _size, str._str);
_size = len + _size;
}
//+=重载
string& operator+=(const string& str)
{
append(str);
return *this;
}
//插入字符
string& insert(size_t pos, const char& ch)
{
//判断pos要小于_size
assert(pos < _size);
//扩容
if (_size == _capacity)
{
size_t new_capacity = (_capacity == 0 ? 4 : _capacity * 2);
reserve(new_capacity);
}
//挪动数据
for (char* i = _str + _size; i >= pos + _str; i--)
//这里要使用指针,因为i是无符号整形,
//当我们在头部插入字符时,i的边界是-1,无符号整形的最大值
{
//_str[i + 1] = _str[i];错误示范
*(i + 1) = *(i);
}
//插入
_str[pos] = ch;
_size++;
return *this;
}
//插入字符串
string& insert(size_t pos, const string& str)
{
//
for (char* i = str._str + str.size() - 1; i >= str._str; i--)
{
this->insert(pos, *(i));
}
return *this;
}
//尾删
void pop_back()
{
assert(!empty());
_size--;
}
//删除
string& erase(size_t pos, size_t len = npos)
{
//串不是空串
assert(_str);
assert(pos < _size);
if (len + pos > _size)
{
len = _size - pos;
}
size_t sz = len;
while (sz)
{
//删除一个字符
for (size_t i = pos; i < _size; i++)
{
_str[i] = _str[i + 1];
}
sz--;
}
_size = _size - len;
return *this;
}
//判断串是否为空
bool empty()const
{
return _size == 0;
}
//查找字符
size_t find(const char& ch, size_t pos = 0)const
{
//查找时,不能为空串
assert(!empty());
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return 0;
}
//查找子串
size_t find(const char* str, size_t pos = 0)const
{
assert(!empty());
size_t len = strlen(str);
assert(pos + len <= _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == str[0])
{
pos = i;
break;
}
}
//判断(1)pos(2)pos + len > _size
//pos + len > _size
if (pos > _size - len)
{
return npos;
}
//pos不变
//<1>刚好找到<2>从头到尾没找到
if (_str[pos] != str[0])// 从头到尾没找到
{
return npos;
}
for (size_t i = pos; i < len + pos; i++)
{
if (_str[i] != str[i - pos])
{
return npos;
}
}
return pos;
}
//[]重载
char& operator[](size_t i)
{
assert(i < _size);
return _str[i];
}
const char& operator[](size_t i)const
{
assert(i < _size);
return _str[i];
}
//字符个数
const size_t& size()const
{
return _size;
}
//容量
const size_t& capacity()const
{
return _capacity;
}
//迭代器
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
//无法修改
const_iterator begin()const
{
return _str;
}
const_iterator end()const
{
return _str + _size;
}
//以C语言的形式进行打印(不打印\0)
const char* c_str()
{
return _str;
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
//比较运算符重载
bool operator>(const lz::string& str1, const lz::string& str2)
{
//求出较小的下标
size_t min_index = 0;
if (str1.size() < str2.size())
{
min_index = str1.size() - 1;
}
else
{
min_index = str2.size() - 1;
}
for (size_t i = 0; i <= min_index; i++)
{
if (str1[i] > str2[i])
{
return true;
}
else if (str1[i] < str2[i])
{
return false;
}
}
if (min_index = str1.size() - 1)
return true;
else
return false;
}
bool operator==(const lz::string& str1, const lz::string& str2)
{
//定义下标
size_t index = 0;
//字符串相等时,下标相等
if (str1.size() == str2.size())
{
index = str1.size() - 1;
}
else
{
return false;
}
//一个一个字符进行比较
for (size_t i = 0; i <= index; i++)
{
if (str1[i] != str2[i])
{
return false;
}
}
return true;
}
bool operator>=(const lz::string& str1, const lz::string& str2)
{
return (str1 > str2) || (str1 == str2);
}
bool operator!=(const lz::string& str1, const lz::string& str2)
{
return !(str1 == str2);
}
bool operator<=(const lz::string& str1, const lz::string& str2)
{
return !(str1 > str2);
}
bool operator<(const lz::string& str1, const lz::string& str2)
{
return !(str1 >= str2);
}
size_t lz::string::npos = -1;//无符号整型的最大值
//输出运算符重载
ostream& operator<< (ostream& out, const lz::string& str)
{
for (size_t i = 0; i < str.size(); i++)
{
out << str[i];
}
return out;
}
//输入运算符重载
istream& operator>> (istream& in, lz::string& str)
{
char tmp[1024] = {0};
in >> tmp;
size_t i = 0;
while (tmp[i])
{
str.push_back(tmp[i]);
i++;
}
return in;
}
}
void Test1()//测试插入删除
{
lz::string s1;
lz::string s2("!!!");
s1.push_back('a');
s1.push_back('b');
s1.push_back('c');
s1.push_back('d');
s1.push_back('d');
s1.append(s2);
s1.append("!!!");
s1 += s2;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
size_t ret = s1.find('a');
size_t ret1 = s1.find("abcd");
s1.erase(ret1,6);
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
}
void Test2()//测试reserve+resize
{
lz::string s1("hello world");
cout << s1.capacity();
s1.reserve(9);
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
cout << s1.capacity() << endl;
s1.reserve(15);
cout << s1.capacity() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
s1.resize(4);
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
s1.resize(20,'a');
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";
}
cout << endl;
}
void Test3()//测试构造函数+"="
{
lz::string s1("hello world");
lz::string s2(s1);
cout << s2.c_str() << endl;
lz::string s3(s2.begin(), s2.end());
cout << s3.c_str() << endl;
lz::string s4(s3, 0, 20);
cout << s4.c_str() << endl;
lz::string s5 = "hello world";
cout << s5.c_str() << endl;
s5 = "abcd";
cout << s5.c_str() << endl;
}
void Test4()//测试遍历
{
lz::string s1("hello world");
lz::string::iterator it1 = s1.begin();
while (it1 != s1.end())
{
cout << *it1;
it1++;
}
cout << endl;
cout << s1.c_str() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i];
}
cout << endl;
for (auto e : s1)
{
cout << e;
}
cout << endl;
const lz::string s2("hello world");
lz::string::const_iterator it2 = s2.begin();
while (it2 != s2.end())
{
//*it2 = 'a';
cout << *it2;
it2++;
}
cout << endl;
for (size_t i = 0; i < s2.size(); i++)
{
//s2[i] = 'a';
cout << s2[i];
}
cout << endl;
for (auto& e : s2)
{
//e = 'a';
cout << e;
}
cout << endl;
}
void Test5()//测试标准输入输出流
{
lz::string s1;
lz::string s2;
cin >> s1 >> s2;
cout << s1 << " " << s2 << endl;
}
void Test6()//测试比较运算符
{
lz::string s1("ABCD");
lz::string s2("ABC");
cout << (s1 > s2) << endl;
cout << (s1 >= s2) << endl;
cout << (s1 < s2) << endl;
cout << (s1 <= s2) << endl;
cout << (s1 != s2) << endl;
cout << (s1 == s2) << endl;
}
int main()
{
Test1();
return 0;
}
😎 😎 今天的内容到这里就结束了,希望对各位老铁能有所帮助,我们下期再见!