• C++(string类)


    本节目标:

    1、为什么要学习string类

    2.标准库中的string类

    3.vs和g++下string结构说明


    1.为什么学习string类

    1.1 c语言中的字符串

      C 语言中,字符串是以 '\0' 结尾的一些字符的集合,为了操作方便, C 标准库中提供了一些 str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合 OOP的思想,而且底层空间需要用户自己管理,稍不留神可 能还会越界访问。

    1.2string类简介

      string是C++ 编程语言中的字符串。在C++中字符串处理可以使用c语言字符串形式char *,也可以使用string类格式。
      string 是一个类,类内有char *指针,通过容器方式管理字符串。使用string类型需要需要包含头文件string。

    2.标准库中的string类

    2.1 string类

    需要了解的是:
    1. string 是表示字符串的字符串类
    2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作。
    3. string 在底层实际是: basic_string 模板类的别名:
    typedef basic_string<char, char_traits, allocator> string;
    
    4. 不能操作多字节或者变长字符的序列。
    需要注意:在使用string类时,必须包含头文件#include,以及using namespace std

    2.2string 类的常用接口说明(常用的,对于一些非常用的可以去官网查找手册)

    1.string类的构造函数

      string常见的构造函数有:无参构造,用c_string构造string类对象,拷贝构造函数

    1. 无参构造:string()
    2. c_string构造string类对象:string(const char *str);
    3. 拷贝构造:string(const string &str);
    4. 初始化字符串为count个c字符:string(int count,char c);

    代码如下所示:

    2 string类对象的容量操作 

     string 常用的容量操作如下表所示:

    函数名称

    功能说明

    size(重点)

    返回字符串有效字符长度

    length

    返回字符串有效字符长度

    capacity

    返回空间总大小

    empty(重点)

    检测字符串释放为空串,是返回true,否则返回false

    clear(重点)

    清空有效字符

    reserve(重点)

    为字符串预留空间**

    resize(重点)

    将有效字符的个数该成n个,多出的空间用字符c填充

     

    1. size() length() 方法底层实现原理完全相同,引入 size() 的原因是为了与其他容器的接口保持一
    致,一般情况下基本都是用 size()
    1. #include
    2. #include
    3. int main()
    4. {
    5. std::string str("Test string");
    6. std::cout << "The size of str is " << str.size() << " bytes.\n";
    7. return 0;
    8. }

     3. clear()只是将string中有效字符清空,不改变底层空间大小。

    1. #include
    2. #include
    3. int main ()
    4. {
    5. char c;
    6. std::string str;
    7. std::cout << "Please type some lines of text. Enter a dot (.) to finish:\n";
    8. do {
    9. c = std::cin.get();
    10. str += c;
    11. if (c=='\n')
    12. {
    13. std::cout << str;
    14. str.clear();
    15. }
    16. } while (c!='.');
    17. return 0;
    18. }

     

     

     

    4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。

    1. void TestPushBackReserve()
    2. {
    3. string s;
    4. s.reserve(100);
    5. size_t sz = s.capacity();
    6. cout << "capacity changed: " << sz << '\n';
    7. cout << "making s grow:\n";
    8. for (int i = 0; i < 100; ++i)
    9. {
    10. s.push_back('c');
    11. if (sz != s.capacity())
    12. {
    13. sz = s.capacity();
    14. cout << "capacity changed: " << sz << '\n';
    15. }
    16. }
    17. s.clear();
    18. cout << "capacity changed: " << sz << '\n';
    19. s.reserve(10);
    20. sz = s.capacity();
    21. cout << "capacity changed: " << sz << '\n';
    22. }
    23. int main()
    24. {
    25. TestPushBackReserve();
    26. return 0;
    27. }

     

     

    5. resize(size_t n) resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

    1. int main()
    2. {
    3. string s1("hello world");
    4. // 开空间
    5. s1.reserve(100);
    6. cout << s1.size() << endl;
    7. cout << s1.capacity() << endl;
    8. // 开空间+填值初始化
    9. //s1.resize(200);
    10. s1.resize(200, 'x');
    11. cout << s1.size() << endl;
    12. cout << s1.capacity() << endl;
    13. s1.resize(20);
    14. cout << s1.size() << endl;
    15. cout << s1.capacity() << endl;
    16. s1.resize(0);
    17. cout << s1.size() << endl;
    18. cout << s1.capacity() << endl;
    19. return 0;
    20. }

     

     

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

    函数名称

    功能说明

    operator[](重点)

    返回pos位置的字符,const string类对象调用

    begin+ end

    begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器

    rbegin + rend begin

    获取一个字符的迭代器 + end获取最后一个字符下个位置迭代器

    范围for

    C++11支持更简洁的范围for的新遍历方式

    1.operator[] 

    1. #include
    2. #include
    3. int main()
    4. {
    5. std::string str("Test string");
    6. for (int i = 0; i < str.length(); ++i)
    7. {
    8. std::cout << str[i];
    9. }
    10. return 0;
    11. }

     

     2.迭代器和范围for

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. std::string s1("Test string");
    8. // 迭代器
    9. string::iterator it = s1.begin();
    10. while (it != s1.end())
    11. {
    12. // 写
    13. (*it)--;
    14. ++it;
    15. }
    16. cout << endl;
    17. it = s1.begin();
    18. while (it != s1.end())
    19. {
    20. // 读
    21. cout << *it << " ";
    22. ++it;
    23. }
    24. cout << endl;
    25. // 范围for
    26. // 底层替换为迭代器
    27. //for (char& ch : s1)
    28. for (auto& ch : s1)
    29. {
    30. ch++;
    31. }
    32. cout << endl;
    33. for (char ch : s1)
    34. {
    35. cout << ch << " ";
    36. }
    37. cout << endl;
    38. }

    3.string类对象的修改操作

     

    函数名称 

    功能说明

    push_back

    在字符串后尾插字符c

    append      

     在字符串后追加一个字符串

    operator+= (重点)

    在字符串后追加字符串str

    c_str(重点)

    返回C格式字符串

    find + npos(重点)

    从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置

    rfind

    从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置

    substr

    在str中从pos位置开始,截取n个字符,然后将其返回

     push_back 尾插字符,append尾插字符串字面就能理解,其实他们都可以用+=实现,

    string的连接是通过加法操作符实现的,加号两边可以随意组合string或是字符串字面量。

    1. #include
    2. #include
    3. using namespace std;
    4. //string的连接
    5. int main()
    6. {
    7. string s1 = "";
    8. string s2 = "";
    9. cout << "请输入两个用空格间隔的字符串:" << endl;
    10. cin >> s1 >> s2 ;
    11. string s3 = s1 + s2 ;
    12. cout << "字符串连接的结果为:" << s3 << endl;
    13. for (int i = 0;i < 3;i++)
    14. {
    15. string s4 = "";
    16. cout << "请输入字符串:" << endl;
    17. cin >> s4;
    18. s3 +=s4;
    19. cout << "字符连接的结果是: " << s3 << endl;
    20. }
    21. return 0;
    22. }

    字符串的查找与替换

    string字符串查找有find、rfind函数。

    • find函数是从左往右查找,查找成功返回第一个出现的下标,失败返回-1。
    • rfind是查找最后一个出现的下标,失败返回-1。 replace函数实现字符串替换。

     //find函数:从左往右查找
    返回值:查找成功返回出现的位置,失败返回-1
    int find(const string&str,int pos=0)const;//形参pos表示开始查找的起始位置
    int find(const char *str,int pos=0)const;
    int find(const char *str,int pos=0,int n)const;//从str的第pos开始的前n个字符中str出现的位置
    int find(const char c,int pos=0);//查找字符c
    //rfind函数:从右往左查找
    int rfind(const string &str,int pos=npos);从pos位置开始查找str最后一次出现的位置
    int rfind(const char *str,int pos=npos);从pos位置开始查找str最后一次出现的位置
    int rfind(const char *str,int pos=pos,int n);从pos开始的前n个字符中str最后一次出现的位置
    int rfind(const char c,int pos=0);//查找c最后一次出现的位置
    //字符串替换
    string &replace(int pos,int n,const string &s);//将字符串的第pos位置开始的n个字符替换成s
    string &replace(int pos,int n,const char *s);

     

    1. #include < iostream >
    2. #include < string >
    3. using namespace std;
    4. void test()
    5. {
    6. string str = "1asd3as456asd4789asd";
    7. int pos = str.find("asd");//查找asd第一次出现的位置
    8. cout << "pos=" << pos << endl;
    9. string temp = "asd";
    10. pos = str.find(temp,7);//从第7个位置开始查找asd出现的位置
    11. cout << "pos=" << pos << endl;
    12. pos = str.rfind(temp);//查找最后一次出现的位置
    13. cout << "pos=" << pos < < endl;
    14. pos = str.rfind("asd",7,2);//从第3个位置开始往前查找,查找"asd"中的前2个字符在str中最后一次位置
    15. cout << "pos=" << pos << endl;
    16. //字符串替换
    17. str.replace(1, 7, "c++");//从第一个位值开始将str的7个字符替换为c++
    18. cout << "str=" << str << endl;
    19. }
    20. int main()
    21. {
    22. test();
    23. system("pause");
    24. }

     函数                                                                   功能说明
    operator+                                            尽量少用,   因为传值返回,导致深拷贝效率低
    operator>> (重点)                           输入运算符重载
    operator<< (重点)                           输出运算符重载
    getline (重点)                                  获取一行字符串
    relational operators (重点)             大小比较

      4string的读写 

      利用cout可以打印string,即将string输出到标准输出端,也就是命令行窗口。类似的,c++也提供了一种方法从标准输入端,也就是键盘将数据写入string。

    1. #include
    2. #include
    3. using namespace std;
    4. //string的读写
    5. int main()
    6. {
    7. string s1;
    8. string s2;
    9. cout << "请输入用两个空格隔开的字符串!" << endl;
    10. cin >> s1 >> s2;
    11. cout << "s1: " << s1 << endl;
    12. cout << "s2: " << s2 << endl;
    13. return 0 ;
    14. }

    5 字符串比较

      string类中字符串比较函compare数有多个重载版本,既可以和C语言风格const char *字符串进行比较,也可以和string类字符串进行比较。相等返回0,不相等返回!0值。

    字符串比较:
    int compare(const char *str);//相等返回0,否则返回非0值
    //比较string的len个字符,从idx位置开始
    int string::compare (size_type idx, size_type len, const string& str) const
    //从指定位置指定长度开始比较
    int string::compare (size_type idx, size_type len, const string&str, size_type str_idx, size_type str_len) const
     

    1. #include < iostream >
    2. using namespace std;
    3. #include < string >
    4. void test()
    5. {
    6. string str1 = "hello,world";
    7. if (str1 == "hello,world")
    8. {
    9. cout << "[const char *]相等" << endl;
    10. }
    11. string str2 = "hello,world";
    12. if (str1 == str2)
    13. {
    14. cout << "[string]相等" << endl;
    15. }
    16. if (!str1.compare("hello,world"))
    17. {
    18. cout << "[compare]相等" << endl;
    19. }
    20. //比较str1的前6个字符
    21. int ret=str1.compare(0,6,"hello,");
    22. cout << "ret=" << ret << endl;
    23. //从str1的第0个开始开始取出6个字符,
    24. //从"c++,hello,"的第4个位置开始,取出6个字符进行比较
    25. ret = str1.compare(0, 6, "c++,hello,", 4, 6);
    26. cout << "ret=" << ret << endl;
    27. }
    28. int main()
    29. {
    30. test();
    31. system("pause");
    32. }

    6字符串的插入与删除

    string类中插入函数insert支持多种插入方式,有多个重载版本。
    字符串删除可以使用erease函数实现。

     

    c++插入:
    string& insert(int pos,const char *s);//从第pos位置开始插入s
    string& insert(int pos,const string &s);

    string &insert(int p0, const char *s, int n);//从p0位置开始插入s,插入的s连续n个字符
    string &insert(int p0,const string &s, int pos, int n);//从p0位置开始插入s,插入的s从pos开始,连续n个字符

    string &insert(int p0, int n, char c);//从p0处插入n个字符c

    c++删除字符串
    string &erase(int pos,int n=npos);//从pos位置开始删除n个字符
     

    1. #include < iostream >
    2. #include < string >
    3. using namespace std;
    4. void test()
    5. {
    6. string str = "hello,";
    7. str.insert(2,"aaa");//从第2个位置开始插入aaa
    8. cout < < "str=" << str << endl;
    9. str.insert(4, "1234", 1, 2);//从第4个位置插入,从"1234"的第1个位置开始,连续两个字符插入到str中
    10. cout << "str=" << str << endl;
    11. //字符串删除
    12. str.erase(2,4);//从第2个位置开始,删除4个字符
    13. cout << "str=" << str << endl;
    14. str.erase();//清空字符串
    15. cout < < "str=" << str <<"\t长度:"<< str.size()<

     3.vs和g++下string结构说明

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

    3.1vs下string的结构:

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

     

    1. union _Bxty
    2. { // storage for small buffer or pointer to larger one
    3. value_type _Buf[_BUF_SIZE];
    4. pointer _Ptr;
    5. char _Alias[_BUF_SIZE]; // to permit aliasing
    6. } _Bx;

          这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内 部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。  其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量 最后:还有一个指针做一些其他事。  故总共占16+4+4+4=28个字节。   

    3.2.g++string的结构

    G++ 下, string 是通过写时拷贝实现的, string 对象总共占 4 个字节,内部只包含了一个指针,该指
    针将来指向一块堆空间,内部包含了如下字段:
    • 空间总大小
    • 字符串有效长度
    • 引用计数
    1. struct _Rep_base
    2. {
    3. size_type _M_length;
    4. size_type _M_capacity;
    5. _Atomic_word _M_refcount;
    6. };
    • 指向堆空间的指针,用来存储字符串。
  • 相关阅读:
    Java多线程相关概念
    合并区间【贪心算法】
    springmvc复习(第二天)(黑马版)
    电脑如何下载视频号的视频?电脑微信视频号使用的方法!
    【数据集NO.3】人脸识别数据集汇总
    FMC子卡设计原理图:FMCJ450-基于ADRV9009的双收双发射频FMC子卡
    mybatis二级缓存原理
    容器镜像基础(nydus)
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java旅游管理系统3ohx4
    Java虚拟机启动整体流程和基础学习(内容很多,不可快餐阅读),推理+源码论证
  • 原文地址:https://blog.csdn.net/weixin_45476980/article/details/133435059