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 个 acout << 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;}}