当前位置: 首页 > news >正文

网站建设 好公司wordpress 只能做博客

网站建设 好公司,wordpress 只能做博客,职业生涯规划大赛官网报名,做网站 百度推广W...Y的主页 #x1f60a; #x1f354;前言#xff1a; 通过博主的上篇文章#xff0c;我相信大家已经认识了STL并且已经迫不及待想学习了#xff0c;现在我们就走近STL的第一种类——string。 目录 为什么学习string类#xff1f; C语言中的字符串 标准库中的str… W...Y的主页 前言 通过博主的上篇文章我相信大家已经认识了STL并且已经迫不及待想学习了现在我们就走近STL的第一种类——string。 目录 为什么学习string类 C语言中的字符串  标准库中的string类  string类(了解) string类的常用接口说明 string类对象的常见构造 string类对象的容量操作 string类对象的访问及遍历操作 string类对象的修改操作 string类非成员函数 为什么学习string类 C语言中的字符串  C语言中字符串是以\0结尾的一些字符的集合为了操作方便C标准库中提供了一些str系列的库函数但是这些库函数与字符串是分离开的不太符合OOP的思想而且底层空间需要用户自己管理稍不留神可能还会越界访问。 C中的string相对于C语言中的字符数组和字符串处理函数优化了以下方面 自动内存管理C语言中的字符串需要手动管理内存包括分配、释放和确保缓冲区足够大。std::string自动处理内存管理动态调整内部存储以适应字符串的长度减少了内存泄漏和缓冲区溢出的风险。 安全性C语言中的字符串操作容易导致缓冲区溢出和内存错误这些问题可能导致安全漏洞。std::string通过封装字符串数据和提供安全的操作函数降低了这些安全风险。 方便性std::string提供了丰富的成员函数使字符串的操作更加方便和直观。你可以轻松执行字符串连接、查找、替换、截取等操作而不需要编写自定义函数或使用库函数。 抽象性std::string是一个高级抽象数据类型隐藏了底层实现细节。这意味着你不需要关心字符串的内部表示只需使用std::string对象即可这使代码更加清晰和易于维护。 性能尽管std::string引入了一些开销但它通常能够提供很好的性能。它可以动态分配和释放内存以适应字符串的变化而不需要频繁的手动内存操作这在某些情况下可以提高效率。 标准库中的string类  string类(了解) 标准库中的string类 1. 字符串是表示字符序列的类 2. 标准的字符串类提供了对此类对象的支持其接口类似于标准字符容器的接口但添加了专门用于操作单字节字符字符串的设计特性。 3. string类是使用char(即作为它的字符类型使用它的默认char_traits和分配器类型(关于模板的更多信息请参阅basic_string)。 4. string类是basic_string模板类的一个实例它使用char来实例化basic_string模板类并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。 5. 注意这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列这个类的所有成员(如长度或大小)以及它的迭代器将仍然按照字节(而不是实际编码的字符)来操作。 总结 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同再添加了一些专门用来操作string的常规操作。  3. string在底层实际是basic_string模板类的别名typedef basic_stringchar, char_traits, allocatorstring; 4. 不能操作多字节或者变长字符的序列。 在使用string类时必须包含#include头文件以及using namespace std;  string类的常用接口说明 string类对象的常见构造 (constructor)函数名称 功能说明string() 重点 构造空的string类对象即空字符串string(const char* s) 重点 用C-string来构造string类对象string(size_t n, char c) string类对象中包含n个字符cstring(const strings) 重点拷贝构造函数 上述是比较常见的构造函数是用来给字符串进行初始化的。具体的构造函数在C98中有7种而在C11中已经更新至9种。 下面我们通过代码认识一下如何对string进行初始化 int main() {string s1;string s2(hello world);string s3(s2);return 0; } 第一种就是以string() 为模型创建的空字符串第二种是直接传入一个常量字符串即可是以string(const char* s) 为模型创建的。第三种是以string(const strings)为原型进行初始化它也算是一种拷贝构造初始化将我们的s2拷贝构造到s3种去。 以上三种也是最为重要的三种string初始化方式现在我们可以继续拓展一下string为用户提供的其他的初始化方式我们不需要全部记住作为了解即可 #includeiostream #includestring using namespace std; int main() {string s1;string s2(hello world);string s3 hello world;string s4(s3, 6, 3);cout s4 endl;string s5(s3, 6, 13);cout s5 endl;string s6(s3, 6);cout s6 endl;string s7(hello world, 5);cout s7 endl;string s8(10, *);cout s8 endl;return 0; } s4、s5、s6都是使用了string (const string str, size_t pos, size_t len npos);函数原型进行初始化的这个初始化函数的作用是将str的字符串的pos位置后的len长度的字符串进行拷贝到未初始化的字符串中。函数中有一个参数len使用了缺省值的方法进行所以我们不进行传值len也是可以的。 那如果我们的字符串本身大小只有10但我们给予len超过字符串大小的值此函数不会报错它会将字符串从pos位置处的内容拷贝完后结束那npos是什么呢 所以npos代表的就是最大整型长度C祖师爷敢笃定所以的字符串长度全都都没有i整型最大值大所以不传len参数就是默认从pos位置处读取到字符串结尾 。在之后的string接口中会出现许多npos参数我们一定要熟记于心 s7是使用了string (const char* s, size_t n);函数模型进行初始化作用是得到常量字符串的前n个内容进行初始化赋值。 而s8是使用了string (size_t n, char c);的函数模型此函数支持C11以上的版本。作用是初始化n个c的字符作为内容。 以上是比较常用或常见的初始化。 string类对象的容量操作 函数名称功能说明size返回字符串有效字符长度length返回字符串有效字符长度capacity返回空间总大小empty检测字符串释放为空串是返回true否则返回falseclear清空有效字符reserve为字符串预留空间resize将有效字符的个数该成n个多出的空间用字符c填充 以下是对string类对象容量操作实例 int main() {string s1(hello world);cout s1.size() endl;cout s1.length() endl;cout s1.max_size() endl;cout s1.capacity() endl;return 0; } max_size函数是求字符串可以达到的最大长度的一般情况下没有什么用。size与length函数的功能作用是一样的只是出现的先后顺序不同当时string出现时在C标准库中并没有在STL中所以函数接口是length最后加入到STL后为了兼容性将length也加进去。 int main() {// 观察扩容情况 -- 1.5倍扩容string s;//cout sizeof(s) endl;//s.reserve(100);size_t sz s.capacity();cout making s grow:\n;cout capacity changed: sz \n;for (int i 0; i 100; i){s.push_back(c);if (sz ! s.capacity()){sz s.capacity();cout capacity changed: sz \n;}} }我们知道reserve是对数组进行扩容的函数我们可以通过上述函数了解其中扩展的倍数。同样的函数在不同的编译器下的扩容倍数不相同不能一直依赖与vs编译器。  在Linux下扩容是2倍但是初始的空间非常少。在vs下扩容倍数为1.5倍左右初始空间给的多。但是编译器实现自动扩容时也会有消耗如果我们提前知道我们需要多少空间我们可以使用reserve提前开出对应的空间就可以优化时间复杂度。  int main() {// 注意string类对象支持直接用cin和cout进行输入和输出string s(hello, world!!!);cout s.size() endl;cout s.length() endl;cout s.capacity() endl;cout s endl;// 将s中的字符串清空注意清空时只是将size清0不改变底层空间的大小s.clear();cout s.size() endl;cout s.capacity() endl;// 将s中有效字符个数增加到10个多出位置用a进行填充// “aaaaaaaaaa”s.resize(20, a);cout s.size() endl;cout s.capacity() endl;// 将s中有效字符个数增加到15个多出位置用缺省值\0进行填充// aaaaaaaaaa\0\0\0\0\0// 注意此时s中有效字符个数已经增加到15个s.resize(100);cout s.size() endl;cout s.capacity() endl;cout s endl;// 将s中有效字符个数缩小到5个s.resize(5);cout s.size() endl;cout s.capacity() endl;cout s endl; }上述我们在不同情况下使用了resize与clear函数进行操作。我们发现clear函数是将字符串中的内容全部清除而resize是对字符串的内容进行改变如果需要空间不足也可以进行开空间并且可以对字符串进行初始化操作如果我们没有声明初始化字符resize会将内容全部初始化为\0resize也可以进行截断操作将字符串只保留需要的个数切记截断不是缩容因为字符串是一段连续的空间如果进行缩容调用析构函数就会释放字符串的全部空间。 总结 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_arg0)为string预留空间不改变有效元素个数当reserve的参数小于string的底层空间总大小时reserver不会改变容量大小。 string类对象的访问及遍历操作 函数名称功能说明operator[] 重点返回pos位置的字符const string类对象调用begin endbegin获取一个字符的迭代器 end获取最后一个字符下一个位置的迭代器rbegin rendbegin获取一个字符的迭代器 end获取最后一个字符下一个位置的迭代器范围for C11支持更简洁的范围for的新遍历方式 要了解string类对象的访问遍历操作首先就得先纸雕迭代器iterator迭代器Iterator是一种设计模式用于以一种统一的方式遍历容器如列表、集合、字典等中的元素而不暴露容器的内部结构。迭代器提供了一种简洁、一致的访问容器元素的方法使得我们可以在不关心容器内部实现的情况下逐个访问容器中的元素。 在目前string的学习中我们可以先将迭代器iterator理解为一种指针类型使用指针去遍历字符串。 void Teststring4() {string s(hello Bit);// 3种遍历方式// 需要注意的以下三种方式除了遍历string对象还可以遍历是修改string中的字符// 另外以下三种方式对于string而言第一种使用最多// 1. foroperator[]for (size_t i 0; i s.size(); i)cout s[i] endl;// 2.迭代器string::iterator it s.begin();while (it ! s.end()){cout *it endl;it;}// string::reverse_iterator rit s.rbegin();// C11之后直接使用auto定义迭代器让编译器推到迭代器的类型auto rit s.rbegin();while (rit ! s.rend())cout *rit endl;// 3.范围forfor (auto ch : s)cout ch endl; } 这是三种变量字符串的方式第一种方式为 foroperator[]因为[]已经重载该返回的内容是当前下标对应的字符。我们只需要使用for进行遍历下标即可。 第二种方法是使用迭代器而在字符串中迭代器更像一种指针我们使用begin()与end()获取字符串的首位让迭代器it进行遍历即可。 最后一种方法是范围for其实与迭代器的原理是一样的使用范围for后在进行编译时编译器会将范围for的函数进行替换成迭代器函数。  我们可以通过反汇编看出。 rbegin与rend函数与begin和end恰好相反而且我们的迭代器关键字成为reverse_iterator. int main() {string s1(hello world);string::reverse_iterator rit s1.rbegin();while (rit ! s1.rend()){cout *rit ;rit;}cout endl; }而且迭代器在循环中是而不是--我们的惯性思维就觉得应该是--。 因为反向迭代器种应该往左边走反之--往右边走 如果我们创建了一个类外函数此函数的作用就是遍历数组但是参数有const修饰我们还可以继续使用上述遍历方法直接CV上去吗 void Func(const string s) {// 遍历和读容器的数据不能写string::const_iterator it s.begin();while (it ! s.end()){//*it 1;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; }int main() {Func(s1);return 0; } 因为当我们是普通迭代器时begin返回普通迭代器当我们用const修饰时begin就返回有const修饰的所以无论时begin、end、rbegin还是rend都有两个版本有const修饰与无const的。所以我们必须使用const迭代器进行接受bengin的返回值。其实在C11中已经有专门返回和接受const的函数 但是begin函数已经被后人所用习惯了所以使用begin、end……也没有错但要注意区分类型。 每次在声明一个类型太长这是我们就可以使用auto自动识别变量类型 operator[]重载遍历非常好用那为什么还要继续使用迭代器进行访问呢因为目前学习的内容都是一段连续的空间所以说可以使用数组访问但是以后学习链表、二叉树……数据结构的空间是不连续的所以我们就要使用迭代器进行遍历。 其实operator[]与at的函数是一样的都是返回当前pos位置的下标那我们为什么要去鼓励大家去使用operator[]而不是at呢因为operator[]函数体中使用的是assert断言函数如果函数访问越界直接会使程序终止而at函数是抛异常给编译器没有operator[]那么严格但是字符串越界是非常危险的行为所以使用operator[]更加安全。 string类对象的修改操作 函数名称功能说明push_back 在字符串后尾插字符cappend在字符串后追加一个字符串operator (重点)在字符串后追加字符串strc_str(重点) 返回C格式字符串findnpos(重点)从字符串pos位置开始往后找字符c返回该字符在字符串中的位置rfind从字符串pos位置开始往前找字符c返回该字符在字符串中的位置insert在pos位置插入字符c或字符串substr在str中从pos位置开始截取n个字符然后将其返回 insert函数就是在字符串pos位置插入字符串或者字符提供的函数模板也非常多 有在pos位置插入字符串的有在pos位置插入字符的有在pos位置插入n个字符的、也有使用迭代器进行插入的……非常多这里我们看几个常用的函数模型但是我们知道insert从中间插入字符/字符串都要将后面的内容进行平移效率不是很高所以不推荐经常使用insert函数。 int main() {// insert/erase不推荐经常使用能少用就少用// 因为他们可能都存在要挪动数据效率低下string s1(world);s1.insert(0, hello);cout s1 endl;//s1.insert(5, 1, );//s1.insert(5, );s1.insert(s1.begin()5, );cout s1 endl;return 0; } 上面函数的目的就是在world前加上hello在hello与world之间加上空格加上空格有三种表示方式分别是将空格看作字符或字符串还有一种是使用迭代器寻找目标位置。 说了insert插入就要在提一嘴erase在pos位置删除与insert是相对的。 根据函数原型我们就可以正确的使用其函数其中npos与上述的npos意义相同不知道的可以浏览上面内容。 int main() {string s2(hello world);//s2.erase(5, 1);s2.erase(s2.begin() 5);cout s2 endl;s2.erase(5, 30);//s2.erase(5);cout s2 endl;return 0; } 如果字符串的大小小于所需删除的大小直接将字符串全部内容删除即可。 replacd函数就是将pos位置的大小为n字符串进行替换也不推荐使用这里我就不过多演示了有个了解即可。 int main() {string s1(hello world);s1.replace(5, 1, %%d);cout s1 endl;return 0; } 接下来就是我们的重点find函数。find函数还是很方便和实用的。它是从字符串pos位置开始往后找字符c返回该字符在字符串中的位置。 find函数找到了返回下标没找到返回-1而find函数的返回值为size_t所以返回值npos。我们也可以看出find函数的pos参数为缺省参数如果给予pos值就是从pos位置开始寻找如果不传参也可以find函数就从字符串开始位置开始寻找。 我们可以通过学习find函数与replace函数做一道非常经典的题目将字符串中的空格全部替换为$$号 int main() {string s1(hello world i love you);size_t pos s1.find( );while (pos ! string::npos){s1.replace(pos, 1, $$);pos s1.find( , pos 3);}cout s1 endl;return 0; } 这样替换可能导致空间不足我们可以提前算好需要多少空间然后进行提前开空间进行优化 int main() {string s1(hello world i love you);size_t num 0;for (auto ch : s1){if (ch )num;}// 提前开空间避免repalce时扩容s1.reserve(s1.size() 2 * num);size_t pos s1.find( );while (pos ! string::npos){s1.replace(pos, 1, $$);pos s1.find( , pos 3);}cout s1 endl;return 0; } rfind函数与find函数刚好相反rfind函数是从pos位置向前寻找函数参数相同。 c_str的函数也非常重要是返回C格式字符串 int main() {string s1(hello world);cout s1 endl;cout s1.c_str() endl;cout (void*)s1.c_str() endl;return 0; } 直接使用s1标准io流可以进行输出使用此函数也可以进行输出那这个函数有什么用呢s1是属于自定义类型调用自己的流插入而s1.c_str返回的是字符串的指针,而cout打印指针时在一般情况下打印的是指针地址而char*却打印的是字符串。 在特殊情况下我们还必须使用c_str. int main() {cout s1 endl;cout s1.c_str() endl;s1 \0;s1 \0;s1 xxxxx;cout s1 endl;cout s1.c_str() endl;return 0; } 我们先来看一下当给s1\0再加上xxxxx后再次打印后我们可以看出不同 我们如果按照流插入去打印它是按照你的size去打印的不管\0而c_str返回的是const char*遇到\0就会终止无论后面是否还有内容。 在文件打开使用fopen函数时如果字符串是string类时就不能传给fopen所以我们使用c_str即可 int main() { string filename(test.cpp); FILE* fout fopen(filename.c_str(), r); if (fout nullptr)perror(fopen fail);char ch fgetc(fout); while (ch ! EOF) {cout ch;ch fgetc(fout); }fclose(fout); return 0; }substr函数是在str中从pos位置开始截取n个字符然后将其返回一个子字符串我们可以创建一个string类型变量进行接收。 所以我们在特定的场景下进行使用此函数 int main() {string file(string.cpp.tar.zip);size_t pos file.rfind(.);if (pos ! string::npos){//string suffix file.substr(pos, file.size() - pos);string suffix file.substr(pos);cout suffix endl;}string url(http://www.cplusplus.com/reference/string/string/find/);cout url endl;size_t start url.find(://);if (start string::npos){cout invalid url endl;}start 3;size_t finish url.find(/, start);string address url.substr(start, finish - start);cout address endl;return 0; }如果我们想要对一个文件取其后缀我们就可以使用此函数进行截取。上述函数就可以取到一个文件的最后一个后缀或者想要截取网址的中间部分都可以使用substr函数进行操作。 注意 1. 在string尾部追加字符时s.push_back(c) / s.append(1, c) / s c三种的实现方式差不多一般情况下string类的操作用的比较多操作不仅可以连接单个字符还可以连接字符串。 2. 对string操作时如果能够大概预估到放多少字符可以先通过reserve把空间预留好。  string类非成员函数 函数 功能说明operator尽量少用因为传值返回导致深拷贝效率低operator输入运算符重载operator输出运算符重载getline获取一行字符串relational operators 大小比较 这些运算符重载就不过多强调了直接可以使用我们大家也一看就会。 但是getline我们得说一下当我们先创建一个string字符串但不初始化时我们需要用户进行输入一段字符串但是有时会有空格在字符串里充当一个字符当使用cin流进行输入时与scanf相同遇到空格或者回车键时会停止输入所以导致用户输入的字符串不完整。 所以我们引入getline进行一行字符串读取其对空格不停止只对回车键进行停止。 总结string类的接口有几十种上百种我们不需要一一记住在上述文章中提到的都是比较重要也是较为常用的接口我们需要熟记并熟练掌握。 上万字的精讲非常详细如果学到了请支持一下博主吧创作不易
http://www.sadfv.cn/news/420455/

相关文章:

  • 网站开发项目总结范文企业网站导航设计
  • 微信分销网站建设官网创新的盐城网站开发
  • 有没有专门做家纺的网站手机版网站的优势
  • 团队拓展活动长沙seo网站建设
  • 淮安 网站建设安做省民改厅网站
  • 汕头站扩建有连接华东线吗网站建设客户怎么找
  • 网站有几种南宁会制作网站的技术人员
  • 佛山新网站建设报价wordpress api地址
  • 宠物网站建设的可行性展厅设计公司推荐
  • 襄阳地区网站做的好的南通seo招聘
  • 高端的金融行业网站开发中国万网域名注册
  • 东莞品牌设计公司济南做网站优化
  • 网站系统设计目标丽水网站建设公司
  • 公司注册一站式wordpress3.8.3
  • 网站怎么留住用户巩义做网站推广
  • 问答类咨询网站的建设wordpress如何cdn加速
  • 购买网站建设平台网站仿造
  • 网站登录密码怎么取消保存免费建网站知乎
  • 昆明做网站建设怎么样网站设计是什么专业
  • 互助平台网站建设费用深圳专业建网站公司排行
  • 做物流的用什么网站配货dw做的网页在网站图片不显示
  • 跨境建站平台百度网盘资源链接入口
  • 网站的标题可以改吗沈阳唐朝网络推广
  • 网站创意的技术襄阳抖音seo找哪家
  • 淘宝客网站建设视频教程销售和营销的区别
  • 上杭网站开发手机上怎样制作网站
  • 建网站的 公司怎么寻找要建设网站的客户群
  • 个人定制网站怎么做网站图片都是站外连接对seo
  • seo网站推广方案策划书自己做的网站如何让百度搜索
  • 哈尔滨建设银行网站网站建设装修