1. 标准库中的string类
注意:
1. string是表示字符串的字符串类
2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。 比特就业课
3. string在底层实际是:basic_string模板类的别名,typedef basic_string string;
4. 不能操作多字节或者变长字符的序列。 在使用string类时,必须包含#include头文件(#include<string>)以及using namespace std;
a. string类对象的常见构造
代码举例1
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1; // 相当于类对象的实例化
}
代码举例2
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1("hello world"); // 调用构造函数
cout << t1 << endl;
string t2 = "hello world"; //隐式类型转换(构造函数 + 拷贝构造 + 优化 -> 构造函数)
cout << t2 << endl;
}
代码举例3
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1(10, 'a'); // 拷贝 10 个 a
cout << t1 << endl;
}
运行结果:
代码举例4
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1("hello");
string t2(t1); // 拷贝构造
cout << t2 << endl;
}
b. string类对象的容量操作
- size (返回字符串有效字符长度,没有 '\0 ')
代码举例1
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1 = "hello";
cout << t1.size() << endl;
}
运行结果:
- capacity (返回字符串的总空间大小)
代码举例2
#include <iostream>
#include<string>
using namespace std;
int main()
{
string t1 = "hello";
cout << t1.capacity() << endl;
}
运行结果:
分析:
string 类里面的成员变量有两个可以存储空间,一个是数组,另一个是动态开辟的空间,当数组空间不足时,才会用动态开辟
- reserve(扩大字符串容量,字符有效长度不变:即 size 不变)
代码举例3
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
t1.reserve(100);
cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
}
运行结果:
分析:
有些编译器在分配空间的时候,可能会对于开辟所需的空间再给大一点
- resize (将有效字符的个数该成n个,多出的空间用字符c填充)
代码举例4
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
t1.resize(100);
cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
t1.resize(10); //可以缩小有效长度,但总容量不会随意变动
cout << "有效长度:" << t1.size() << " 总容量:" << t1.capacity() << endl;
t1.resize(20, '*'); //对于的空间可以初始化任意字符
cout << t1 << endl;
}
运行结果:
c. string类对象的访问及遍历操作
- operator[] (返回pos位置的字符,和 C 语言的用法一样,const string类对象调用)
- begin + end (begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器)
代码举例1
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello bit";
string::iterator it = t1.begin();
// it 相当于拿到 首元素的地址了
while (it != t1.end())
{
cout << *it << endl;
it++;
}
}
运行结果:
分析:
- rbegin + rend (rbegin获取最后一个字符的迭代器 + rend获取第一个字符前一个位置的迭代器)
代码举例2
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello bit";
string::reverse_iterator rit = t1.rbegin();
// it 相当于拿到 首元素的地址了
while (rit != t1.rend())
{
cout << *rit << endl;
rit++;
}
}
运行结果:
分析:
- 范围for
代码举例3
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello bit";
for (auto i : t1)
{
cout << i;
}
cout << endl;
for (int i = 0; i < t1.size(); i++)
{
cout << t1[i];
}
}
运行结果:
d. string类对象的修改操作
- push_back (在字符串后面增加一个字符)
代码举例1
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
t1.push_back('a');
t1.push_back('a');
t1.push_back('a');
cout << t1 << endl;
}
运行结果:
- append (在字符串后面再增加一个字符串)
代码举例2
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
t1.append("abcd");
cout << t1 << endl;
}
运行结果:
- operator+= (在字符串后面加一个字符或者一个字符串)
代码举例3
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
t1 += "aabc";
t1 += '*';
cout << t1 << endl;
}
运行结果:
- c_str (返回存储的字符串)
代码举例4
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
t1 += '\0';
t1 += 'a';
cout << t1 << endl;
cout << t1.c_str();
}
运行结果:
分析:
c_str() 是直接返回字符串 ,所以遇到 '\0' 就终止了
而
的完成是根据_size去遍历每个字符串
- find + npos (从字符串pos位置开始往后找字符c,返回第一次遇到的该字符在字符串中的位置)
代码举例5
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
cout << t1.find('o',2) << endl;
// 从下标为 2 的位置去找字符 'o'
cout << t1.find("lo") << endl;
// 默认从下标 0 的位置去找字符串
}
注意:
- 如果找不到,返回 npos ( size_t npos = -1)
- 默认 pos 从 0 下标开始
- rfind(从字符串pos位置开始往前找字符c,返回第一次遇到该字符在字符串中的位置)
代码举例6
#include <iostream>
using namespace std;
int main()
{
string t1 = "hello";
cout << t1.rfind('l') << endl;
}
运行结果:
注意:
- 如果找不到,返回 npos ( size_t npos = -1)
- 默认 pos 从 字符串中的最后一个字符(不是 '\0' ) 下标开始
e. string类非成员函数
- operator>> (输入运算符重载)
- operator<< (输出运算符重载)
- getline (获取一行字符串)
代码举例
#include <iostream>
#include <string>
using namespace std;
int main()
{
string t1;
getline(cin, t1);
cout << t1 << endl;
return 0;
}
注意:
getline 遇到空格不会结束
cin 遇到空格会结束
2. string 类的模拟
namespace lhy
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterater;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterater begin() const
{
return _str;
}
const_iterater end() const
{
return _str + _size;
}
string(const char* str = "")
:_size(strlen(str))
{
_capacity = _size == 0 ? 3 : _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string(const string& t)
:_size(strlen(t._str))
{
_capacity = t._size;
_str = new char[_capacity + 1];
strcpy(_str, t._str);
}
string(int n, char ch)
:_size(n)
{
_capacity = _size;
_str = new char[_capacity + 1];
for (int i = 0; i < n; i++)
{
_str[i] = ch;
}
_str[_capacity] = '\0';
}
string& operator=(const string& t)
{
_size = t._size;
_capacity = t._capacity;
char* tmp = new char[_capacity + 1];
strcpy(tmp, t._str);
delete[] _str;
_str = tmp;
return *this;
}
char& operator[](int pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](int pos) const
{
assert(pos < _size);
return _str[pos];
}
size_t size() const
{
return _size;
}
const char* c_str() const
{
return _str;
}
bool operator>(const string& t) const
{
if (strcmp(_str, t._str) > 0)
{
return true;
}
return false;
}
bool operator==(const string& t) const
{
if (strcmp(_str, t._str) == 0)
{
return true;
}
return false;
}
bool operator<(const string& t) const
{
if (strcmp(_str, t._str) < 0)
{
return true;
}
return false;
}
bool operator<=(const string& t) const
{
return *this < t || *this == t;
}
bool operator>=(const string& t) const
{
return *this > t || *this == t;
}
bool operator!=(const string& t) const
{
return !(*this == t);
}
void push_back(const char ch)
{
if (_size + 1 > _capacity)
{
reserve(_size * 2);
}
_size++;
_str[_size - 1] = ch;
_str[_size] = '\0';
}
void append(const char* str)
{
int len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
void reserve(size_t n)
{
if (n > _size)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void resize(size_t size,char ch = '\0')
{
if (size > _size)
{
reserve(size);
int x = size - _size;
while (x--)
{
*this += ch;
}
_size = size;
}
else
{
_size = size;
_str[_size] = '\0';
}
}
void insert(size_t pos,const char ch)
{
assert(pos <= _size);
if (_size + 1 > _capacity)
{
reserve(_size * 2);
}
_size++;
for (int i = _size; i > pos; i--)
{
_str[i] = _str[i - 1];
}
_str[pos] = ch;
}
void insert(size_t pos,const char* str)
{
assert(pos <= _size);
int len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
_size += len;
for (size_t i = _size; i > pos + len - 1; i--)
{
_str[i] = _str[i - len];
}
strncpy(_str + pos, str, len);
}
void erase(size_t pos,size_t n = npos)
{
assert(pos <= _size);
if (n == npos || pos + n >= _size )
{
_str[pos] = '\0';
_size = pos;
}
else
{
for (int i = pos + n; i <= this->size(); i++)
{
_str[i - n] = _str[i];
}
_size -= n;
}
}
void swap(string &t)
{
std::swap(_size, t._size);
std::swap(_capacity, t._capacity);
std::swap(_str, t._str);
}
size_t find(const char ch, size_t pos = 0)
{
assert(pos < _size);
for (size_t i = pos; i < this->size(); i++)
{
if (_str[i] == ch)
{
return i;
}
}
return -1;
}
size_t find(const char* str, size_t pos = 0)
{
assert(pos < _size);
char *tmp = std ::strstr(_str + pos, str);
if (tmp == nullptr)
{
return -1;
}
else
{
return tmp - _str;
}
}
string& operator+=(const char *str)
{
append(str);
return *this;
}
string& operator+=(const char ch)
{
push_back(ch);
return *this;
}
void clear()
{
_str[0] = '\0';
_size = 0;
}
~string()
{
delete[] _str;
_str = nullptr;
}
private:
char* _str;
size_t _size;
size_t _capacity;
static size_t npos;
};
size_t string::npos = -1;
ostream& operator<<(ostream& out, const string& t)
{
for (size_t i = 0; i < t.size(); i++)
{
out << t[i];
}
return out;
}
istream& operator>> (istream& in,string& t)
{
t.clear();
int i = 0;
char tmp[128];
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
tmp[i++] = ch;
if (i == 126)
{
tmp[i + 1] = '\0';
t += tmp;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
tmp[i] = '\0';
t += tmp;
}
return cin;
}
}