一、初始string类
在 C++ 中,
std::string
是标准库提供的用于处理字符串的类。它提供了比 C 风格字符串(以'\0'
结尾的字符数组)更方便、更安全的字符串处理方式。要使用
std::string
,需要包含<string>
头文件。并且,std::string
位于std
命名空间中。可以通过using namespace std;
来引入整个std
命名空间,不过这种方式可能会导致命名冲突,更推荐的是使用std::string
这种完整的限定名称。
二、常用接口
1.string类对象的常见构造
string() -- 构造空的string对象,即一个空字符串 --无参构造
string(const char* s) -- 用C->string来构造string对象 --带参构造
string(size_t n,char c) -- 构造并初始化一个string对象,含n个c --带参构造
string(const string& s) -- 拷贝构造 --拷贝构造
2.string类对象的容量操作
size() -- 返回字符串有效长度
length() -- 返回字符串有效字符长度
capacity() -- 返回总空间大小
empty() -- 判空
clear() -- 清空有效字符
reserve() -- 为字符串预留空间
resize() -- 将有效字符的个数改成n个,多出的空间用字符c填充
3. string类对象的访问及遍历操作
operator[]() -- 返回pos位置的字符,const string对象调用
begin + end -- string的迭代器,分别获取第一个字符和以后一个字符的下一个位置
rbegin + rend -- 反向迭代器,分别返回最后一个字符和第一个字符之前的位置
范围for -- C++11支持更简洁的范围for的新遍历方式
4. string类对象的修改操作
push_back() -- 尾插字符
append() -- 字符串末尾追加字符串
operator+=() -- 字符串末尾追加字符串
c_str() -- 返回c语言格式字符串
find() + npos -- 从pos位置开始往后找目标字符,返回其位置
rfind() -- 从pos位置往前开始找目标字符,返回其位置
substr() -- 在字符串的pos位置开始,截取n个字符,将其返回
5.string类非成员函数
operator+() -- 返回一个新构造的字符串对象,其值是 lhs 中的字符后跟 rhs 中的字符的串联。
operator>>() -- 输入运算符重载
operator<<() -- 输出运算符重载
getline() -- 获取一行字符串
relational operators() -- 大小比较
三、string的常见问题
class string
{
public://传统写法string(const string& s){_str = new char[s._capacity + 1];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);}//现代写法string(const string& s){string tmp(s);Swap(tmp);}//传统写法string& operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];_capacity = s._capacity;_size = s._size;strcpy(_str, s._str);}}//现代写法string& operator=(string s){Swap(s);return *this;}void Swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}private:char* _str;int _size;int _capacity;
};
四、string的模拟实现
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;namespace ts
{class string{public:typedef char* iterator;typedef const char* const_iterator;//迭代器iterator begin(){return _str;}//返回最后一个数据的下一个iterator end(){return _str + _size;//0 + 3 = 3}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;//0 + 3 = 3}//初始化列表初始化/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/// 短小频繁调用的函数,可以直接定义到类里面,默认是inlinestring(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}// 深拷贝问题// 传统写法-- 拷贝构造// s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}现代写法//string(const string& s)//{// string tmp(s._str);// Swap(tmp);//Swap(*this,tmp)//}void Swap( string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// s2 = s1// s1 = s1--传统写法string& operator=(const string& s){if (this != &s){delete[]_str;_str = new char[s._capacity];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}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;}//清除原数据但不改变空间大小void clear(){_str[0] = '\0';_size = 0;}//返回数据数目size_t size() const{return _size;}//返回空间大小size_t capacity() const{return _capacity;}//类似取地址操作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);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private://char _buff[16];char* _str;size_t _size;size_t _capacity;//static const size_t npos = -1;static const size_t npos;/*static const int N = 10;int buff[N];*/};bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}
#include"string.h"namespace ts
{//npos的初始化不能在头文件中定义//否则在后面每次链接时,会发生重复定义const size_t string::npos = -1;//保留空间void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcmp(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}//尾插void string::push_back(char ch){//是否需要扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;//注意末尾\0的添加_str[_size] = '\0';}//尾插字符串void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);}strcpy(_str + _size, str);_size += len;}//添加字符--加等一个字符string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}//在指定位置插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);//挪动的时候别忘记了末尾的\0int end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[end] = ch;++_size;}//在指定位置插入字符串void string::insert(size_t pos, const char* str){assert(pos<= _size);size_t len = strlen(str);if (_size + len > _capacity){//扩容// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}//往后挪动数据size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - 1];--end;}//填充字符串for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}//从指定位置开始,删除pos个字符,未指定长度则默认为nopsvoid string::erase(size_t pos, size_t len){assert(pos < _size);if (_size - pos <= len){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i < _size; ++i){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t string::find(const char* str, size_t pos){assert(pos < _size);//strstr--找出第二个字符串首次出现在第一个字符串中的位置const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}//读取字符串在pos位置的len个字符string string::substr(size_t pos, size_t len){assert(pos < _size);// len大于剩余字符长度,更新一下lenif (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}bool operator<(const string& s1, const string& s2){//strcmp -- 第一个字符串大于第二个 返回>0,小于返回<0等于返回=return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return s1 < s2 || s1 == s2;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}ostream& operator<<(ostream& out, const string& s){out << s.c_str();/*for (auto e : s){out << e;}*/return out;}istream& operator>>(istream& in, string& s){//清除数据s.clear();const int N = 256;char buff[N];int i = 0;char ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++];//避免频繁开辟空间if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}}if (i > 0){buff[i] = '\0';s += buff;}return in;}
}