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

C++初阶学习——探索STL奥秘——标准库中的string类

1. 为什么学习string类?

在我们学习C语言的时候,有一个点是非常难处理的,那就是字符串,在我们对字符串访问,增删查改时都是非常不便的,所以我们封装了一个string类主要来处理字符串有关的问题

2. 标准库中的string类

2.1 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_string string;

4. 不能操作多字节或者变长字符的序列。

在使用string类时,必须包含#include头文件以及using namespace std;

2.2 string类的常用接口说明

1. string类对象的常见构造

 

 从cplusplus可以查得string类的所有构造函数

 代码:

#include<string>
#include<iostream>
using namespace std;
int main()
{string();               //1、构建了一个空的string对象,这个对象只在本行起作用,除非加const修饰string s1("abc");       //2、直接构造cout << "s1:" << s1 << endl;char arr[] = "abc";string s2(arr);         //3、用一个字符串的首地址来构造cout << "s2:" << s2 << endl;string s3 = s1;         //4、拷贝构造(用一个已经存在的类对象给另一个对象初始化)cout << "s3:" << s3 << endl;string s4(3, 'x');      //5、构造时将前N个赋值为同一个字符cout << "s4:" << s4 << endl;return 0;
}

 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的底层空间总大小时,reserver不会改变容量大小

 

 

 

 

 

 

 

代码: 

#include<string>
#include<iostream>
using namespace std;
int main()
{string s1("abcdef");cout <<"s1:"<< s1 << endl;cout << "size:" << s1.size() << endl;        //有效字符的个数cout << "length:" << s1.length() << endl;    //有效字符的个数//上面这两个功能上差别不大,一般我们用size()用的多一点cout << "capacity:" << s1.capacity() << endl;   //开辟的空间大小(当空间不够时会自动扩容,扩容空间为原空间的1.5倍(与环境有关))cout << "empty:" << s1.empty() << endl;     //检查字符串是否为空,0表示非空,1表示空s1.clear();                                 //清空字符串cout <<"s1:"<< s1 << endl;s1.reserve(100);                            //开辟指定大小空间(一般会多一点)cout << "capacity:" << s1.capacity() << endl;s1.resize(5, 'a');cout << "size:" << s1.size() << endl;cout << "s1:" << s1 << endl;return 0;
}

3. string类对象的访问及遍历操作

 

代码: 

 

#include<iostream>
using namespace std;
#include<string>
int main()
{string s1("abcdef");//访问方法:下标访问法cout << s1[0] << endl;cout << s1[3] << endl;s1[0] = 'h';//1、下标遍历法cout << "下标遍历法:";for (int i = 0; i < s1.size(); i++){cout << s1[i] << " ";}cout << endl;//2、迭代器法(正向)cout << "迭代器法(正向):";string::iterator it = s1.begin();for (; it != s1.end(); it++){cout << *it << " ";}cout << endl;//3、迭代器(反向)cout << "迭代器(反向):";string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";rit++;}cout << endl;//范围for法cout << "范围for法:";for (auto e : s1){cout << e << " ";}cout << endl;return 0;
}

 4. string类对象的修改操作

代码: 

#include<iostream>
using namespace std;
#include<string>
int main()
{string s1("zhan");cout << s1 << endl;//push_back  在末尾加入字符cout << "push_back后:";s1.push_back('g');cout << s1 << endl;//append     在末端加入字符串cout << "append后:" ;s1.append(" san");cout << s1 << endl;//operator+= 在末端随意添加cout << "+=后:";s1 += " 18";cout << s1 << endl;//c_str    返回C格式字符串cout << "c_str:";const char* m = s1.c_str();cout << m << endl;//find  从pos位置开始查找字符并返回其位置cout << "find:";int npos1 = s1.find('a');cout << npos1 << endl;//rfind  从pos位置开始往前查找字符并返回其位置cout << "rfind:";int npos2 = s1.rfind('a');cout << npos2 << endl;//substr  从pos位置开始截取n个字符并返回cout << "substr后:";string tmp = s1.substr(npos1, npos2 - npos1);cout << tmp << endl;return 0;
}

注意:

 1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多

一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。  

5. string类非成员函数 

代码:

#include<iostream>
using namespace std;
#include<string>
int main()
{string s1("hello ");string s2("world");//operator+    涉及深层拷贝,不建议多用cout << "operator+后:";cout << operator+(s1, s2) << endl;//operator>>   输入运算符重载cout << "operator>>:";string s3;operator>>(cin,s3);cout << s3 << endl;//operator<<    输出运算符重载cout << "operator<<:";operator<<(cout, s1) << endl;//getline      获取一行字符串cout << "getline:";string s4;getline(cin, s4);    //这个在这个程序中测不出来,需要单独测试cout << s4 << endl;//relational operators   比较大小//这个函数库中有各种各样的比较函数(==、>、<......),函数类型为bool,感兴趣的可以自己探索一下return 0;
}

 

6. vs和g++下string结构的说明

注意:

下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字 符串的存储空间: 当字符串长度小于16时,使用内部固定的字符数组来存放

当字符串长度大于等于16时,从堆上开辟空间  

union _Bxty
{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内 部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量

最后:还有一个指针做一些其他事情。 故总共占16+4+4+4=28个字节。

g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指 针将来指向一块堆空间,内部包含了如下字段:

空间总大小

字符串有效长度

引用计数  

struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};

指向堆空间的指针,用来存储字符串。 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • PyCharm2024 专业版激活设置中文
  • 论文总结:A Survey on Evaluation of Large Language Models-鲁棒性相关内容
  • 爬虫基本原理入门
  • Preact:轻量级替代React的选择
  • 【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 亲子游戏(200分) - 三语言AC题解(Python/Java/Cpp)
  • STM32H7的LPUART基础和唤醒示例
  • Kylin Cube资源使用限制:优化大数据查询性能的策略
  • 人工智能:大语言模型提示注入攻击安全风险分析报告下载
  • 【多线程】单例模式
  • leetcode-114. 二叉树展开为链表
  • javaEE-02-servlet
  • 科普文:Linux系统安全加固指南
  • js 数组常用函数总结
  • [M模拟] lc2844. 生成特殊数字的最少操作(简单易错+分类讨论+代码优化技巧)
  • QtCMake工程提升类后找不到头文件
  • 【剑指offer】让抽象问题具体化
  • Effective Java 笔记(一)
  • Nacos系列:Nacos的Java SDK使用
  • PHP 小技巧
  • Ruby 2.x 源代码分析:扩展 概述
  • TypeScript迭代器
  • 前端设计模式
  • 前嗅ForeSpider采集配置界面介绍
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 突破自己的技术思维
  • 无服务器化是企业 IT 架构的未来吗?
  • 由插件封装引出的一丢丢思考
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • #每天一道面试题# 什么是MySQL的回表查询
  • (1)(1.13) SiK无线电高级配置(六)
  • (1)虚拟机的安装与使用,linux系统安装
  • (2022 CVPR) Unbiased Teacher v2
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (原創) 未来三学期想要修的课 (日記)
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • (转)用.Net的File控件上传文件的解决方案
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • (最新)华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—(共12套)(每套四十题)
  • . NET自动找可写目录
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net core Redis 使用有序集合实现延迟队列
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • @31省区市高考时间表来了,祝考试成功
  • @Documented注解的作用
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • [ C++ ] STL---仿函数与priority_queue
  • [ web基础篇 ] Burp Suite 爆破 Basic 认证密码
  • [ 物联网 ]拟合模型解决传感器数据获取中数据与实际值的误差的补偿方法
  • [ACTF2020 新生赛]Upload 1
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [Android Studio] 开发Java 程序