目录
一、标准库中的string类
1、简单介绍string类
2、string类的常用接口注意事项
2.1、string类对象的常用构造
2.2、string类对象的容量操作
2.3、string类对象的访问及遍历操作
2.4、string类对象的修改操作
二、string类的模拟实现
一、标准库中的string类
1、简单介绍string类
(1)string是表示字符串的字符串类;
(2)string类的接口与常规容器的接口基本相同,在添加了一些专门用来操作string的常规操作;
(3)string的底层实际是:basic_string模板类的别名,typedef basic_string<char,char_traits,allocator> string;
(4)不能操作多字节或者变长字符的序列。
2、string类的常用接口注意事项
2.1、string类对象的常用构造
标准库给出的string类对象常用的构造函数有很多,我们经常用到的主流构造方式有三种:用模板提供的默认构造函数构造空的string类对象、用常量字符串构造string类对象以及用现有的string类对象进行拷贝构造string类对象。
2.2、string类对象的容量操作
(1)size()与length()方法的底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况先都是用size()。
(2)clear()只是将string类对象中的有效字符清空,不改变底层空间大小。
(3)resize(size_t n)与resize(size_t n,char c)都是将字符串中的有效字符个数改变成n个,不同的是当字符个数增多时:resize(n)用0来填充多出来的元素空间,resize(size_t n,char c)是用字符c来填充多出来的元素空间。注意:resize()在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间的总大小保持不变,并不会随着元素个数的减少而缩小容量空间。
(4)reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量的大小。
2.3、string类对象的访问及遍历操作
string类对象的访问方式有三种:下标访问、迭代器访问、范围for访问。这里主要讨论迭代器访问方式。
迭代器是一个类,现阶段可以把迭代器当成一个指针来使用(实际上不一定是指针),迭代器是在类的里边定义的,即内部类,使用方式如:string::iterator。string类中与迭代器搭配使用的成员函数包括begin()、end()、rbegin()、rend()。
2.4、string类对象的修改操作
string类提供了很多字符串修改接口,需要说的是:在string尾部追加自字符时,s.push_back(c)/s.append(1,c)/s+='c'三种实现方式几乎一样,一般情况下更多的选用+=操作,+=操作不仅可以连接单个字符,还可以连接字符串;对string操作时,如果能够大概预估到待存储字符串的长度,可以先通过reserve把空间预留好。
二、string类的模拟实现
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>namespace lbj
{class string{friend ostream& operator<<(ostream& _cout, const string& s);friend istream& operator>>(istream& _cin, string& s);typedef char* iterator;public:string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& s) : _str(nullptr), _size(0), _capacity(0){string tmp(s._str);this->swap(tmp);}string& operator=(const string& s){if (this != &s){string temp(s);this->swap(temp);}return *this;}~string(){if (_str){delete[] _str;_str = nullptr;}}//// iteratoriterator begin(){return _str;}iterator end(){return _str + _size;}/// modifyvoid push_back(char c){if (_size == _capacity)reserve(_capacity * 2);_str[_size++] = c;_str[_size] = '\0';}string& operator+=(char c){ push_back(c);return *this;}void append(const char* str){int len = strlen(str);if (_size + len > _capacity){reserve(_size + len);//_capacity = _size + len;}strcpy(_str + _size, str); //strcpy()会将‘\0’也拷贝过来,所以不需要手动添加'\0'_size += len;}string& operator+=(const char* str){append(str);return *this;}void clear(){_size = 0;_str[_size] = '\0';}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}const char* C_Str()const{return _str;}/// capacitysize_t size()const{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return _size == 0;}void resize(size_t newSize, char c = '\0'){if (newSize > _size){// 如果newSize大于底层空间大小,则需要重新开辟空间if (newSize > _capacity){reserve(newSize);}memset(_str + _size, c, newSize - _size);}_size = newSize;_str[newSize] = '\0';}void reserve(size_t newCapacity){// 如果新容量大于旧容量,则开辟空间if (newCapacity > _capacity){char* str = new char[newCapacity + 1];strcpy(str, _str);// 释放原来旧空间,然后使用新空间delete[] _str;_str = str;_capacity = newCapacity;}}/// accesschar& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}///relational operatorsbool operator<(const string& s)const{int res = strcmp(_str, s._str);if (res < 0)return true;return false;}bool operator<=(const string& s)const{return !(*this > s);}bool operator>(const string& s)const{int res = strcmp(_str, s._str);if (res > 0)return true;return false;}bool operator>=(const string& s)const{return !(*this < s);}bool operator==(const string& s)const{int res = strcmp(_str, s._str);if (res == 0)return true;return false;}bool operator!=(const string& s)const{return !(*this == s);}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const{for (size_t i = pos; i < _size; ++i){if (_str[i] == c)return i;//找到,返回下标}return -1;//未找到}// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const{assert(s);assert(pos < _size);const char* src = _str + pos;while (*src){const char* match = s;//如果不匹配,返回子串起始处重新查找const char* cur = src;while (*match && *match == *cur)//结束条件{++match;++cur;}if (*match == '\0')//找到子串{return src - _str;//返回下标}else{++src;}}return -1;//未找到}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){assert(pos <= _size);if (_size > _capacity){//扩容char* newstr = new char[_capacity * 2 + 1];//开空间strcpy(newstr, _str);delete[] _str;_str = newstr;_capacity *= 2;//Expand(_capacity * 2);}//移数据for (int i = _size; i >= (int)pos; --i){_str[i + 1] = _str[i];}_str[pos] = c;_size++;return *this;}string& insert(size_t pos, const char* str){size_t len = strlen(str);if (_size + len > _capacity)//扩容{//扩容char* newstr = new char[_capacity * 2 + 1];//开空间strcpy(newstr, _str);delete[] _str;_str = newstr;_capacity *= 2;//Expand(_size + len);}//后移数据for (int i = _size; i >= (int)pos; --i){_str[len + i] = _str[i];}//拷贝字符串while (*str != '\0'){_str[pos++] = *str++;}_size += len;return *this;}// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len){assert(pos < _size);if (pos + len >= _size)//pos位置之后全为0{_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}private:char* _str;size_t _capacity;size_t _size;};//输入流重载istream& operator>>(istream& _cin, string& s){//预分配100个空间char* str = (char*)malloc(sizeof(char) * 100);char* buf = str;int i = 1;//预处理:跳过流里面的所有空格和回车while ((*buf = getchar()) == ' ' || (*buf == '\n'));for (; ; ++i){if (*buf == '\n') //回车跳出{*buf = '\0';break;}else if (*buf == ' ') //空格跳出{*buf = '\0';break;}else if (i % 100 == 0) //空间不足{i += 100; //追加100个空间str = (char*)realloc(str, i);}else //每次getchar()一个值{buf = (str + i);//为了避免realloc返回首地址改变,不使用++buf,而是用str加上偏移.//每次读取一个字符*buf = getchar();}}//输入完成,更新ss._str = str;s._capacity = s._size = i;return _cin;}//输出流重载ostream& operator<<(ostream& _cout, const string& s){for (size_t i = 0; i < s.size(); ++i){_cout << s[i];}return _cout;}
};