• C++string—常用接口介绍+模拟实现+习题讲解


    如果调试一个程序让你很苦恼,千万不要放弃,成功永远在拐角之后,除非你走到拐角,否则你永远不知道你离他多远,所以,请记住,坚持不懈,直到成功。

     

    目录

    前言

    1.string类的常用接口

    1.1string类对象的常见构造:

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

    1.3string类对象的容量操作

    1.4string类对象的修改操作:

    2.string类的模拟实现

    3.string类的习题


    前言

    STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。学会使用STL,许多底层的数据结构以及算法都不需要自己重新造轮子,站在前人的肩膀上,健步如飞的快速开发。

    本篇文章介绍string类,学习string类我们大致分两个方面进行,首先是学习如何使用库中string接口,然后再通过学习string底层源代码的进行模拟实现接口

    在介绍string接口前,首先介绍一个网站可以用来查询C++中的库函数以及STL,后续的学习当中会经常在这个文档上查阅各种接口——https://legacy.cplusplus.com/

    1.string类的常用接口

    string类包含许多接口,在这里我们主要重点介绍string类的常用接口,对于常用的接口我们需要做到不用查阅文档就可以熟练的使用,对于其它接口,只需要做到知道有这种接口,查阅文档会使用即可

    1.1string类对象的常见构造:

    函数名称功能说明
    string()构造空的string类对象,即空字符串
    string(const char* s)用C-string来构造string类对象
    string(const string&s)拷贝构造函数
    string(size_t n, char c) string类对象中包含n个字符c

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

    函数名称功能说明
    operator[]返回pos位置的字符,const string类对象调用
    范围forC++11支持的更简洁的范围for遍历方式
    begin + endbegin获取第一个字符的迭代器 , end获取最后一个字符下一个位置的迭
    代器
    rebing + rend

    rbegin获取最后一个字符下一个位置的迭代器,rend获取第一个字符的迭代器

    operator[]:

      范围for:

     上面是两种string类对象常规的遍历方式,下面介绍一种STL中通用的遍历方式就是迭代器

    迭代器在行为上像指针一样的类型

     正向遍历:begin + end

     

     反向遍历:rebegin + rend

     以上是关于迭代器正向遍历和反向遍历的两种方式,除此之外,库中还有const修饰的函数

    如:

     为什么会存在const修饰的函数呢?通过下面的代码来说明:

    这段代码中我们只是想打印这个字符串,并不做任何的修改,因此可以使用引用,这样做就减少了一次拷贝构造,提高程序的效率,所以在库中也定义了const修饰的函数 

     下面来介绍一个在编写代码时的小技巧:

    上面两行代码是等价的,在使用熟练之后,如果在编写代码的过程中如果觉得定义rit这个变量时类型过长,可以使用auto这个关键字,因为auto可以自动推导变量类型 

     

    1.3string类对象的容量操作

    函数名称功能说明
    size返回字符串有效长度
    length返回字符串有效长度
    capacity返回空间总大小
    clear清空有效字符
    reserve为字符串预留空间
    resize将有效字符的个数该成n个,多出的空间用字符c填充
    size和length函数是等价的:

     capacity函数:

    clear函数:

     reserve函数:

    关于reserve这个函数的好处是什么呢?

     string这个类在构造对象的时候,底层是使用动态增长的方式来按需申请和释放内存的,如果在构造之前就知道大概需要多大的空间,就不用频繁的申请内存,有效避免在堆上频繁申请内存,造成内存碎片的问题

    resize函数:

    功能:将有效字符改成n个,多出的空间用字符c来填充

    因此会存在三种情况:

    n < size  :删除数据

    size < n <= capacity :插入数据

    n > capacity :扩容 + 插入数据

    第一种情况:

    第二种情况: 

    第三种情况: 

    1.4string类对象的修改操作:

    函数名称功能说明
    push_back在字符串后面尾插字符c
    append在字符串后面追加一个字符串
    operator+=在字符串后面追加字符串
    c_str返回c格式字符串
    find 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
    rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
    substr在str中从pos位置开始,截取n个字符,然后将其返回
    insert在pos位置插入字符
    erase删除pos位置处的n个字符
    assign将一个字符串拷贝到一个对象中去
    replace从pos位置开始,将n个字符改成n个字符

    push_back函数:

    append函数:

     operator+=:

    c_str函数:返回一个指向该字符串首字符的指针

     

     find函数:

    rfind函数:

     注:find函数和rfind如果找不到就返回npos

    -1是size_t类型转换后就是最大的整型:

    substr函数:从pos位置开始,截取n个字符,返回截取字符第一个字符的地址

     

    insert函数:

    erase函数: 

     assign函数:

     repalce函数:

     

     2.string类的模拟实现

    1.定义一个string类:为了和库里的区分将类名定义为String

    1. class String
    2. {
    3. public:
    4. //成员函数
    5. private:
    6. //成员变量
    7. };

    接口1:

    构造函数:

    1. //无参构造:
    2. String()
    3. {
    4. char* _str = new char[1];
    5. _str[0] = '\0';
    6. _capacity = _size = 0;
    7. }
    8. //带参构造:
    9. String(const char* str = "")
    10. {
    11. _size = strlen(str);
    12. _capacity = _size;
    13. _str = new char[_capacity + 1];
    14. strcpy(_str, str);
    15. }

    接口2:

    拷贝构造函数:

    1. //传统写法:
    2. String(const String& s)
    3. {
    4. _str = new char[s._capacity + 1];
    5. _capacity = s._capacity;
    6. _size = s._size;
    7. strcpy(_str, s._str);
    8. }
    9. //现代写法
    10. String(const String& s)
    11. :_str(nullptr)
    12. ,_size(0)
    13. ,_capacity(0)
    14. {
    15. String tmp(s._str);
    16. std::swap(_str, tmp._str);
    17. std::swap(_size, tmp._size);
    18. std::swap(_capacity, tmp._capacity);
    19. }
    20. //现代写法的优化:
    21. void swap(String& s)
    22. {
    23. std::swap(_str, s._str);//内置类型调用算法库里面的
    24. std::swap(_size, s._size);
    25. std::swap(_capacity, s._capacity);
    26. }
    27. String(const String& s)
    28. :_str(nullptr)
    29. , _size(0)
    30. , _capacity(0)
    31. {
    32. String tmp(s._str);
    33. //this->swap(tmp);
    34. swap(tmp);//自定义类型使用自己的swap,避免了使用算法库里面的产生三次深拷贝
    35. }

    接口3

    析构函数:

    1. ~String()
    2. {
    3. delete[] _str;
    4. _str = nullptr;
    5. _capacity = _size = 0;
    6. }

    接口4

    赋值重载函数:

    1. //传统写法
    2. String& operator=(const String& s)
    3. {
    4. if (this != &s)
    5. {
    6. char* tmp = new char[s._capacity + 1];
    7. strcpy(tmp, s._str);
    8. delete[] _str;
    9. _str = tmp;
    10. _size = s._size;
    11. _capacity = s._capacity;
    12. }
    13. return *this;
    14. }
    15. //现代写法:
    16. String& operator=(const String& s)
    17. {
    18. if (this != &s)
    19. {
    20. String tmp(s);
    21. swap(tmp);
    22. }
    23. return *this;
    24. }
    25. //现代写法的优化
    26. String& operator=(String s)
    27. {
    28. if (this != &s)
    29. {
    30. swap(s);
    31. }
    32. return *this;
    33. }

    接口5

    operator[]:

    1. char& operator[](size_t pos)
    2. {
    3. return _str[pos];
    4. }

    接口6

    size():

    1. size_t size()
    2. {
    3. return _size;
    4. }

    接口7

    capacity():

    1. size_t capacity()
    2. {
    3. return _capacity;
    4. }

    接口8:

    c_str():

    1. char* c_str()
    2. {
    3. return _str;
    4. }

    接口9:

    begin和end

    1. typedef char* iterator;
    2. iterator begin()
    3. {
    4. return _str;
    5. }
    6. iterator end()
    7. {
    8. return _str + _size;
    9. }

    接口10

    reserve():

    1. void reserve(int n)
    2. {
    3. if (n > _capacity)
    4. {
    5. char* tmp = new char[n + 1];
    6. strcpy(tmp, _str);
    7. delete[] _str;
    8. _str = tmp;
    9. _capacity = n;
    10. }
    11. }

    接口11

    push_back():

    1. void push_back(char ch)
    2. {
    3. if (_size == _capacity)
    4. {
    5. int newCapacity = _capacity == 0 ? 4 : _capacity * 2;
    6. reserve(newCapacity);
    7. }
    8. _str[_size] = ch;
    9. ++_size;
    10. _str[_size] = '\0';
    11. }

    接口12

    append():

    1. void append(const char* str)
    2. {
    3. size_t len = strlen(str);
    4. if (_size+len > _capacity)
    5. {
    6. reserve(_size + len);
    7. }
    8. strcat(_str, str);
    9. _size += len;
    10. }

    接口13

    operator+=():

    1. //+=字符
    2. String& operator+=(const char ch)
    3. {
    4. push_back(ch);
    5. return *this;
    6. }
    7. //+=字符串
    8. String& operator+=(const char* str)
    9. {
    10. append(str);
    11. return *this;
    12. }

    接口14

    insert():

    1. //插入字符
    2. String& insert(size_t pos, const char ch)
    3. {
    4. assert(pos < _size);
    5. if (_size == _capacity)
    6. {
    7. int newCapacity = _capacity == 0 ? 4 : _capacity * 2;
    8. reserve(newCapacity);
    9. }
    10. //写法1:
    11. /* int end = _size;
    12. while (end >= (int)pos)
    13. {
    14. _str[end + 1] = _str[end];
    15. --end;
    16. }*/
    17. //写法2:
    18. int end = _size + 1;
    19. while (end > pos)
    20. {
    21. _str[end] = _str[end - 1];
    22. --end;
    23. }
    24. _str[pos] = ch;
    25. _size++;
    26. return *this;
    27. }
    28. //插入字符串:
    29. String& insert(size_t pos, const char* str)
    30. {
    31. size_t len = strlen(str);
    32. if (_size + len > _capacity)
    33. {
    34. reserve(_size + len);
    35. }
    36. //写法1:
    37. /* int end = _size;
    38. while (end >= (int)pos)
    39. {
    40. _str[end + len] = _str[end];
    41. --end;
    42. }*/
    43. //写法2:
    44. int end = _size + len;
    45. while (end >= pos + len)
    46. {
    47. _str[end] = _str[end - len];
    48. --end;
    49. }
    50. strncpy(_str + pos, str, len);
    51. _size += len;
    52. return *this;
    53. }

    接口15

    erase():

    1. String& erase(size_t pos, size_t len = npos)
    2. {
    3. assert(pos < _size);
    4. if (len == npos || len >= _size - pos)
    5. {
    6. _str[pos] = '\0';
    7. _size = pos;
    8. }
    9. else
    10. {
    11. strcpy(_str + pos, _str + pos + len);
    12. _size -= len;
    13. }
    14. return *this;
    15. }

    接口16

    find():

    1. //查找字符
    2. size_t find(char ch, size_t pos = 0)
    3. {
    4. assert(pos < _size);
    5. int i = pos;
    6. while (_size--)
    7. {
    8. if (_str[i] == ch)
    9. {
    10. return i;
    11. }
    12. i++;
    13. }
    14. return npos;
    15. }
    16. //查找字符串:
    17. size_t find(const char* str, size_t pos = 0)
    18. {
    19. assert(pos < _size);
    20. char* ptr = strstr(_str + pos, str);
    21. if (ptr == nullptr)
    22. {
    23. return npos;
    24. }
    25. else
    26. {
    27. return ptr - _str;
    28. }
    29. }

    接口17

    clear():

    1. void clear()
    2. {
    3. _str[0] = '\0';
    4. _size = 0;
    5. }

    接口18

    resize():

    1. void resize(size_t n, char ch = '\0')
    2. {
    3. if (n > _capacity)
    4. {
    5. reserve(n);
    6. for (int i = _size; i < n; i++)
    7. {
    8. _str[i] = ch;
    9. }
    10. _size = n;
    11. _str[_size] = '\0';
    12. }
    13. else
    14. {
    15. _str[_size] = '\0';
    16. _size = n;
    17. }
    18. }

    流提取:oparetor<<()

    1. ostream& operator<<(ostream& out, String& s)
    2. {
    3. for (int i = 0; i < s.size(); i++)
    4. {
    5. out << s[i];
    6. }
    7. return out;
    8. }

    流插入:oparetor>>()

    1. istream& operator>>(istream& in, String& s)
    2. {
    3. s.clear();
    4. //第一种写法
    5. //char ch = in.get();
    6. 等于空格或者换行就就结束了!
    7. //while (ch != ' ' && ch != '\n')
    8. //{
    9. // s += ch;
    10. // ch = in.get();
    11. //}
    12. // 第一种写法的优化
    13. //减少频繁扩容
    14. char buf[128] = { 0 };
    15. int i = 0;
    16. char ch = in.get();
    17. while (ch != ' ' && ch != '\n')
    18. {
    19. if (i == 127)
    20. {
    21. s += buf;
    22. i = 0;
    23. }
    24. buf[i++] = ch;
    25. ch = in.get();
    26. }
    27. //不足128或者剩下的:
    28. if (i > 0)
    29. {
    30. buf[i] = '\0';
    31. s += buf;
    32. }
    33. return in;
    34. }

     3.string类的习题

    习题1:字符串转换成整数oj链接

    1. class Solution {
    2. public:
    3. int StrToInt(string str) {
    4. int sum = 0;
    5. int flag = 1;
    6. for(int i = 0; isize(); i++)
    7. {
    8. if(str[i] == '+' || str[i] == '-')
    9. {
    10. flag = str[i] == '+'? flag : -flag;
    11. continue;
    12. }
    13. else if(!(str[i] >= '0' && str[i] <= '9'))
    14. {
    15. return 0;
    16. }
    17. else
    18. {
    19. sum = sum*10 + str[i] - '0';
    20. }
    21. }
    22. return sum*flag;
    23. }
    24. };

    习题2:字符串相加oj链接

    1. class Solution {
    2. public:
    3. string addStrings(string num1, string num2) {
    4. int end1 = num1.size()-1;
    5. int end2 = num2.size()-1;
    6. int carry = 0;
    7. string retStr;
    8. retStr.reserve(max(num1.size(),num2.size()+1));
    9. while(end1 >= 0 || end2 >= 0)
    10. {
    11. int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
    12. int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
    13. int ret = val1 + val2 + carry;
    14. carry = ret / 10;
    15. ret %= 10;
    16. retStr += '0' + ret;
    17. end1--;
    18. end2--;
    19. }
    20. if(carry == 1)
    21. retStr += '1';
    22. reverse(retStr.begin(),retStr.end());
    23. return retStr;
    24. }
    25. };

    习题4:仅仅反转字母oj链接

    1. class Solution {
    2. public:
    3. string reverseOnlyLetters(string s) {
    4. int begin = 0;
    5. int end = s.size()- 1;
    6. while(begin < end)
    7. {
    8. while(begin < end && !isalpha(s[begin]))
    9. {
    10. ++begin;
    11. }
    12. while(begin < end && !isalpha(s[end]))
    13. {
    14. --end;
    15. }
    16. swap(s[begin],s[end]);
    17. ++begin;
    18. --end;
    19. }
    20. return s;
    21. }
    22. };

    习题5:字符串中只出现一次的字符oj链接

    1. class Solution {
    2. public:
    3. int firstUniqChar(string s) {
    4. int str[26] = { 0 };
    5. for(auto& ch : s)
    6. {
    7. str[ch - 'a']++;
    8. }
    9. for(int i = 0; i < s.size(); i++)
    10. {
    11. if(str[s[i]-'a'] == 1)
    12. return i;
    13. }
    14. return -1;
    15. }
    16. };

    习题6:字符串中最后一个单词的长度oj链接

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string s;
    7. getline(cin,s);
    8. size_t pos = s.rfind(' ');
    9. cout<size()-pos-1 <
    10. return 0;
    11. }

    习题7:验证字符串是否回文oj链接

    1. class Solution {
    2. public:
    3. bool isCharacter(char ch)
    4. {
    5. return ((ch >= '0' && ch <= '9')
    6. ||(ch >= 'a' && ch <= 'z')
    7. ||(ch >= 'A' && ch <= 'Z'));
    8. }
    9. bool isPalindrome(string s) {
    10. for(auto& ch : s)
    11. {
    12. if(ch >= 'A' && ch <= 'Z')
    13. {
    14. ch +=32;
    15. }
    16. }
    17. int begin = 0;
    18. int end = s.size()-1;
    19. while(begin < end)
    20. {
    21. while(begin < end && !isCharacter(s[begin]))
    22. {
    23. ++begin;
    24. }
    25. while(begin < end && !isCharacter(s[end]))
    26. {
    27. --end;
    28. }
    29. if(s[begin] != s[end])
    30. return false;
    31. else
    32. {
    33. ++begin;
    34. --end;
    35. }
    36. }
    37. return true;
    38. }
    39. };

    习题8:反转字符串(区间部分反转)oj链接

    1. class Solution {
    2. public:
    3. string reverseStr(string s, int k) {
    4. int n = s.size();
    5. for(int i = 0; i2*k)
    6. {
    7. reverse(s.begin()+i,s.begin() + min(i+k,n));
    8. }
    9. return s;
    10. }
    11. };

    习题9:反转字符串中的单词oj链接

    1. class Solution {
    2. public:
    3. string reverseWords(string s) {
    4. int len = s.size();
    5. int begin = 0;
    6. int end = 0;
    7. while(begin < len)
    8. {
    9. while(s[end] != ' ' && s[end] != '\0')
    10. {
    11. ++end;
    12. }
    13. int end1 = end+1;
    14. while(begin < end)
    15. {
    16. swap(s[begin],s[end-1]);
    17. ++begin;
    18. --end;
    19. }
    20. begin = end1;
    21. end = end1;
    22. }
    23. return s;
    24. }
    25. };
  • 相关阅读:
    [附源码]计算机毕业设计JAVAjsp医院网上预约系统
    WEB使用百度地图展示某地地址
    【numpy简介、入门、数组创建】
    windows10 Docker Desktop中部署clickhouse
    【C++】走进 ⌈ 类和对象 ⌋ 的核心 - 感受C++的精华 _ 剖析默认成员函数 | 构造函数 | 析构函数 | 拷贝构造函数 | 赋值运算符重载
    JMM对正确同步的多线程程序的内存一致性的保证
    python in excel 如何尝鲜 有手就行
    【appium】Hybrid应用自动化|微信小程序自动化
    2023 年 QQ 小程序企业资质开通 QQ 支付、微信支付轻量级后台搭建(详细教程)
    Unity直接调用java代码(不打jar包)
  • 原文地址:https://blog.csdn.net/qq_65307907/article/details/127545492