做网站图片格式,云服务器做的网站需要备案,贵州省住房和城乡建设厅官网,网站短链接生成器目录 string类介绍访问#xff1a;[ ] 遍历迭代器遍历范围for遍历 容量相关#xff1a;修改相关#xff1a;编码表的了解写时拷贝的了解string的模拟 STL(standard template libaray-标准模板库)#xff1a;是C标准库的重要组成部分#xff0c;不仅是一个可复用的组件库[ ] 遍历迭代器遍历范围for遍历 容量相关修改相关编码表的了解写时拷贝的了解string的模拟 STL(standard template libaray-标准模板库)是C标准库的重要组成部分不仅是一个可复用的组件库而且是一个包罗数据结构与算法的软件框架。
string类介绍
string属于标准库因为它的产生比stl早一些 C为了避免跟c语言库冲突头文件不带.h
string可以管理字符数组
求长度不能用strlenstrlen不能对自定义对象使用而且自定义对象里面的内置类型的私有成员也不能随便访问不同编译器下私有成员名字可能不一样。
平时用string没有用模板实际上它是模板只是库typedef过因为大多数情况用的都是char所以就实例化了 1、4是常用的构造2是拷贝构造3是用str对象的一部分去构造5是用str的前n个初始化6是用n个字符c去初始化7可以用迭代区间去初始化
npos是string里的静态成员变量类型是size_t, -1类型提升全1的无符号是整形的最大值 string s1;string s2(hello);cin s1;cout s1 endl;cout s2 endl;//char str[1600];对比c语言c按需申请使用会更方便//scanf()//想拼接两个string的话string ret1 s1 s1;cout ret1 endl;//和字符串相加也可以string ret2 s1 你好;cout ret2 endl;//相比于c语言中的strcat可读性会更好而且strcat也不能扩容//strcat得找\0string中有size(),可以直接找到结尾string s1(hello world);
string s2 hello world;两种带参构造都可以用
用常量字符串初始化 第一种是构造 第二种是构造拷贝构造单参数的构造函数支持隐式类型转换
访问
[ ] 遍历 // 遍历stringfor (size_t i 0; i s1.size(); i){// 读cout s1[i] ;}cout endl;for (size_t i 0; i s1.size(); i){// 写s1[i];}cout s1 endl;at是一个函数跟[ ] 重载 不同的是at失败后(比如越界)会抛异常[]是断言会终止程序。
s2[0];
s2.at(0);[]用起来会更直观
迭代器遍历
迭代器是遍历数据结构的一种方式目前可以想象成指针因为使用起来很像 每个数据结构的迭代器都是在类里面定义(或typedef)的,属于这个类域
// 迭代器string::iterator it s1.begin();//while (it s1.end()) //这里可以但是不建议因为如果是别的数据结构就不支持了比如listwhile (it ! s1.end()) // 推荐玩法通用{// 读cout *it ;it;}cout endl;it s1.begin();while (it ! s1.end()){// 写*it a;it;}cout endl;cout s1 endl;[ ]用起来方便但不是每个数据结构都能用它针对底层是连续的物理空间的数据结构迭代器才是通用的方式 迭代器屏蔽了底层细节很好体现了c的封装 cbegin这些是想把const iterator区分出来但其实还是直接用begin就好 普通的iterator支持读和写,const iterator只能读 const对象要调用const版本的beginconst版本begin返回const的迭代器 所以迭代器要和s.begin()返回一致
void func(const string s)
{//string::const_iterator it s.begin();auto it s.begin();while (it ! s.end()){// 不支持写// *it a;// 读cout *it ;it;}cout endl;//string::const_reverse_iterator rit s.rbegin();auto rit s.rbegin();while (rit ! s.rend()){cout *rit ;rit;}cout endl;
}void test_string4()
{string s1(hello worldxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy);func(s1);
}范围for遍历 // 原理编译器编译器替换成迭代器// 读for (auto ch : s1){cout ch ;}cout endl;// 写for (auto ch : s1)//ch相当于*it的拷贝所以加才能修改{ch;}cout endl;cout s1 endl;容量相关
size和length string的产生比stl早所以当时用的是length size 具有通用性 ‘\0’标识结束size不算’\0’ 动态增长的数组还需要’\0’是因为要兼容c语言 让string能和c的接口结合起来
string filename;cin filename;FILE* fout fopen(filename.c_str(), r);clear清除数据stl没有严格规定是否释放空间一般是不会释放的因为清掉之后可能还要继续插入数据 max_size本意是想告诉我们string最长有多长不同平台下实现不同它是写死的在我们内存不够时告诉我们也开不了。所以基本用不上。
扩容是怎么扩的
void test_string6()
{string s;size_t old s.capacity();cout 初始 s.capacity() endl;for (size_t i 0; i 100; i){s.push_back(x);if (s.capacity() ! old){cout 扩容: s.capacity() endl;old s.capacity();}}
}在vs上我们会发现string s,它没有存数据容量居然是15也就是16的空间这是因为开了一个16字节的数组 小于16字符串存到buff数组里面 大于等于16存在_str指向的空间buff里面的空间就不要了
这是为了避免系统频繁开小块内存而引发内存碎片 平时string也比较小 _buff[16]_str_size_capacityreserve和resize g下要100就会给100vs2019下要100会给111 可以提前开空间减少扩容提高效率
stl没有规定reserve能不能减少空间一般实现是不会减的(比如g和vs) 不给c默认是给’\0’ 让size变到n
修改相关
插入单个字符
插入字符串
//用的多的也就3和1string ss(world);string s;s.push_back(#);s.append(hello);s.append(ss);couts endl;s #;s hello;s ss;cout s endl;string ret1 ss #;string ret2 ss hello;cout ret1 endl;cout ret2 endl;的效率会较低(拷贝构造再传值返回)尽量用 assign赋值会把原来的数据覆盖
std::string str(xxxxxxx);
std::string base The quick brown fox jumps over a lazy dog.;str.assign(base);
std::cout str \n;insert/erase/repalce能不用就尽量不用因为他们都涉及挪动数据效率不高 接口设计复杂繁多需要时查一下文档即可 string中swap的有效使用场景
空格替换为20%
std::string s2(The quick brown fox jumps over a lazy dog.);
string s3;for (auto ch : s2){if (ch ! ){s3 ch;}else{s3 20%;}}模板的swap代价太高string全局函数还提供了一个swap所以就不会调用模板的swap
find系列
find从字符串pos位置开始往后找字符c rfind从字符串pos位置开始往前找字符c substr找子串从pos位置开始截取n个字符然后返回
void test_string11()
{//string s3(https://legacy.cplusplus.com/reference/string/string/rfind/);string s3(ftp://www.baidu.com/?tn65081411_1_oem_dg);// 协议// 域名// 资源名string sub1, sub2, sub3;size_t i1 s3.find(:);if (i1 ! string::npos)sub1 s3.substr(0, i1);elsecout 没有找到i1 endl;size_t i2 s3.find(/, i13);if (i2 ! string::npos)sub2 s3.substr(i13, i2-(i13));elsecout 没有找到i2 endl;sub3 s3.substr(i2 1);cout sub1 endl;cout sub2 endl;cout sub3 endl;
}编码表的了解
string为什么设计成模板
内存中不能存a、b、c这种概念内存中只有01只能组合成值值和符号之间要有联系就要建立一一映射的关系这就是编码表
每个国家都需要一套编码表 我们的文字很多一个字节一个汉字是不够表示的8个bit有2^8个值 各个国家文字数量的不同 主要有三类方案 UTF-8、UTF-16、UTF-32 这是国际上的为了更好表示中文我们也有自己的一份编码表比如GBK。 兼容ascll常用的汉字用两个字节(110 10)编相对生僻的用三个字节(110 10 10)编特别生僻的用四个字节编 假设一段文字是用UTF-8写的然后改成另外一个编码查的时候对不上就会出现乱码存储格式和解释方式对应不上 我们有时候会出现烫烫烫烫烫是因为数组没有初始化的时候是随机值这个随机值是1开头被解释成汉字查编码表正好是烫取决于编译器用的是什么编码。
写时拷贝的了解 string的模拟
vs下在类里定义静态成员变量时发现在类里可以定义的特例
const static size_t npos -1;//针对const 静态的 整形类型开了一个特例 const static double npos 1.1; //double就不行了
#includeiostream
#includeassert.h
using namespace std;namespace st
{class string{public:typedef char* iterator;typedef const char* const_iterator;string(const char* str ):_size(strlen(str)), _capacity(_size){_str new char[_capacity 1];strcpy(_str, str);}//string(const string str)//{// _str new char[str._capacity 1];// strcpy(_str, str._str);// _size str._size;// _capacity str._capacity;//}//简化后string(const string str):_str(nullptr),_size(0),_capacity(0){string tmp(str._str);//进构造swap(tmp);//this里的数据可能是随机值如果把随机值跟tmp交换//然后tmp出作用域之后调用析构会把随机值空间释放,所以需要初始化_str}~string(){delete[] _str;_str nullptr;_size _capacity 0;}/*string operator(const string s){char*tmp new char[s._capacity 1];strcpy(tmp, s._str);delete[] _str;_str tmp;_size s._size;_capacity s._capacity;return *this;}*//*string operator(const string s){string tmp(s);swap(tmp);return *this;}*///简化后//写好拷贝构造就相当于写好了赋值string operator(string tmp){swap(tmp);return *this;}iterator begin(){return _str;}iterator end(){return _str _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str _size;}char operator[](size_t pos){assert(pos _size);return _str[pos];}size_t size() const{return _size;}size_t capacity() const{return _capacity;}const char* c_str()const{return _str;}void resize(size_t n, char c \0){if (n _size){_str[n] \0;_size n;}else{reserve(n);while (_size n){_str[_size] c;}}_str[_size] \0;}void reserve(int n){if (n _capacity){char* tmp new char[n 1];strcpy(tmp, _str);delete[]_str;_str tmp;_capacity n;}}void push_back(char c){assert(_size _capacity);if (_size _capacity){reserve(_capacity 0 ? 4 : 2 * _capacity);}_str[_size] c;_size;_str[_size] \0;}void append(const char* s){int len strlen(s);if (len _size _capacity){reserve(len _size);}strcpy(_str _size, s);_size len;}string operator(char c){push_back(c);return *this;}string operator(const char* s){append(s);return *this;}bool empty()const{return _size _capacity;}bool operator(const string str)const{for (int i 0; i str.size(); i){if (i this-size())return true;if (this-_str[i] str._str[i])return true;else if (this-_str[i] str._str[i])return false;}return false;}bool operator(const string str)const{for (int i 0; i str.size(); i){if (i this-size() || this-_str[i] ! str._str[i])return false;}return true;}bool operator(const string str)const{return !(*this str);}bool operator(const string str)const{return *this str || *this str;}bool operator(const string str)const{return *this str || *this str;}bool operator!(const string str)const{return !(*this str);}size_t find(char c, size_t pos 0)const{for (int i pos; i (*this).size(); i){if ((*this)._str[i] c){return i;}}return -1;}size_t find(const char* s, size_t pos 0)const{char* str strstr(_str pos, s);return str nullptr ? -1 : str - _str;}string substr(size_t pos, size_t len npos){string s;size_t end lenpos;if (len npos || pos len _size){len _size - pos;end _size;}s.reserve(len);while (pos end){s _str[pos];pos;}return s;}string insert(size_t pos, char c){if (_size _capacity){reserve(_capacity 0 ? 4 : 2 * _capacity);}for (int i size(); i pos; i--){_str[i] _str[i - 1];}_str[pos] c;_size;_str[_size] \0;return *this;}string insert(size_t pos, const char* str){int len strlen(str);if (len _size _capacity){reserve(len _size);}_size len;for (int i size(); i poslen; i--){_str[i-1] _str[i - len - 1];}for (int i 0; i len; i){_str[i pos] str[i];}_str[_size] \0;return *this;}string erase(size_t pos, size_t len string::npos){if (len npos || poslen size()){_str[pos] \0;_size pos;return *this;}for (size_t i pos len; i size(); i){_str[i - len] _str[i];}_size - len;return *this;}void clear(){_str[0] \0;_size 0;}void swap(string s){char* str s._str;size_t size s._size;size_t capacity s._capacity;s._str _str;s._size _size;s._capacity _capacity;_str str;_size size;_capacity capacity;}private:char* _str;size_t _size;size_t _capacity;public:const static size_t npos;};const size_t string::npos -1;ostream operator(ostream out, const string s){for (auto ch : s){out ch;}return out;}istream operator(istream in, string s){s.clear();char buff[129];int i 0;char ch;chin.get();while (ch ! ch ! \n){buff[i] ch;if (i 128){buff[i] \0;s buff;i 0;}ch in.get();}if (i ! 128){buff[i] \0;s buff;}return in;}
}