• C++中string的用法总结+底层剖析


    前言:在C语言中,我们经常使用字符串进行一系列操作,经常使用的函数如下:增删改查

    (自己造轮子),C++中设计出string容器,STL库中为我们提供了以上函数,所以我们使用string容器时,就不用造轮子了

    参考网站:https://legacy.cplusplus.com/reference/string/string/?kw=string

    底层实现,这里我用的是VS的编译器(window)(简化版本),linux(g++)这里使用计数引用(这里不采用计数引用实现)

    constructor(构造函数)

    第一个(第四个):是无参构造

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string s;
    7. return 0;
    8. }

    s中只含有'\0'(无参构造时)

    底层实现:(运用全缺省构造)

    1. string(const char* arr = "")
    2. {
    3. int len = strlen(arr);
    4. _str = new char[len + 1];// '\0'要单独开空间
    5. strcpy(_str, arr);
    6. _size = len;
    7. _capacity = len;
    8. }

    第二个:拷贝构造(将 str 中的所有成员变量全部赋值给*this)

    1. string(const string& s)
    2. {
    3. _str = new char[s._capacity + 1];
    4. strcpy(_str, s._str);
    5. _size = s._size;
    6. _capacity = s._capacity;
    7. }

    第三个:将str中的字符串从下标为pos ,拷贝字符的个数为npos

    (注意npos 为默然时,则为字符串能存储最多的个数,不是_capacity,而是系统默然能储存的最大值,此时npos = -1)

    当npos > len - pos 时 , 就拷贝全部

    举个例子:

    destructor(析构函数)

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

    operator=(赋值重载)

    1. string& operator=(const string& s)
    2. {
    3. char* tmp = new char[s._capacity + 1];
    4. strcpy(tmp, s._str);
    5. _size = s._size;
    6. _capacity = s._capacity;
    7. delete[] _str;
    8. _str = tmp;
    9. return *this;
    10. }
    11. //现代写法
    12. string& operator=(string s)
    13. {
    14. swap(s);
    15. return *this;
    16. }

    现代写法含义:传参时,s进行拷贝构造,在交换*this与s

    iterator(迭代器)

    迭代器的行为像指针

    范围for的原理就是迭代器

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. string s("0000000000000000000");
    7. string::iterator it = s.begin();
    8. while (it != s.end())
    9. {
    10. cout << *it << " ";
    11. it++;
    12. }
    13. cout << endl;
    14. return 0;
    15. }
    16. #include
    17. #include
    18. using namespace std;
    19. int main()
    20. {
    21. string s("0000000000000000000");
    22. for( auto e : s )
    23. cout << e << " ";
    24. cout << endl;
    25. return 0;
    26. }

    这两个代码等效,原理都是迭代器

    1. //迭代器底层实现
    2. char* begin()
    3. {
    4. return _str;
    5. }
    6. char* end()
    7. {
    8. return _str + _size;
    9. }
    10. char* rbegin()
    11. {
    12. return _str + _size;
    13. }
    14. char* rend()
    15. {
    16. return _str;
    17. }

    capacity(容量)

    _capacity当前开辟的空间最多能储存多少字符

    _size代表当前有多少个有效的字符

    库里面有提供查询_capacity,_size的函数

    1. int size()
    2. {
    3. return _size;
    4. }
    5. int capacity()
    6. {
    7. return _capacity;
    8. }

    如何扩容:(库里面有两个函数,可以实现扩容)

    第一个reserve

    传入一个size_t的参数,作为要扩容到标准

    当 n <= _capacity 一般不会造成缩容(这个要具体看编译器)

    当 n > _capacity 会扩容

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

    第二个resize函数

    当 n < _size 会造成有效数据的删除(有可能会缩容

    当 n > _size 且n < _capacity 有可能会缩容,但会造成添加有效数据,一直到 n

    当 n > _capacity 会造成扩容,并添加有效数据的个数,一直到 n 

    1. void resize(size_t n, char c = '\0')
    2. {
    3. if (n <= _size)
    4. {
    5. _size = (int)n;
    6. _str[n] = '\0';
    7. }
    8. else
    9. {
    10. reserve(n);
    11. for (; _size < n; _size++)
    12. {
    13. _str[_size] = c;
    14. }
    15. _str[_size] = '\0';// n为最多有效字符个数,_str[n] = '\0';
    16. }
    17. }

    clear函数

    清空有效数据,令_size = 0;

    empty函数

    判断有效数据个数是否为0

    operator[]

    放回下标为pos的字符

    1. char& operator[] (size_t pos)
    2. {
    3. assert(pos < _size);
    4. return _str[pos];
    5. }
    6. const char& operator[] (size_t pos) const
    7. {
    8. assert(pos < _size);
    9. return (const char )_str[pos];
    10. }

    需要assert(判断pos < _size ),防止对未进行赋值的位置解引用

    operator+=(传入的是字符串也可以,因为会进行隐式类型转换)

    1. string& operator+=(const string& s)
    2. {
    3. if (s._size + _size > _capacity )
    4. {
    5. reserve(s._size + _size);
    6. }
    7. strcpy(_str + _size, s._str);
    8. _size += s._size;
    9. return *this;
    10. }

    在字符串末尾添加字符串

    具体使用:与整形变量的使用方法一样

    append(传入的是字符串也可以,因为会进行隐式类型转换)

    1. string& append(const string& str)
    2. {
    3. *this += str;//复用上面的+=
    4. return *this;
    5. }

    举个例子:

    push_back

    在字符串末尾添加一个字符

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

    assign(容量不改变)

    第一个,第三个相当与拷贝构造

    第二个就是将str中的字符串中的下标从subpos位置的sublen个字符,拷贝给*this

    1. string& assign(const string& str, size_t subpos, size_t sublen)
    2. {
    3. assert(_size - subpos >= sublen && sublen >= 0 );
    4. if (sublen > _capacity)reserve(sublen + _capacity);
    5. memcpy(_str, str._str + subpos, sublen);
    6. _size = sublen;
    7. _str[_size] = '\0';
    8. return *this;
    9. }

    第四个将s中的字符串前n个字符,给*this;

    1. string& assign(const char* s, size_t n)
    2. {
    3. if (n > _capacity)reserve(n);
    4. memcpy(_str, s, n);
    5. _size = n;
    6. _str[_size] = '\0';
    7. return *this;
    8. }

    第五个将n个字符c给*this

    1. string& assign(size_t n, char c)
    2. {
    3. if (n > _capacity)reserve(n);
    4. for (int i = 0; i < n; i++)
    5. {
    6. _str[i] = c;
    7. }
    8. _size = n;
    9. _str[n] = '\0';
    10. return *this;
    11. }

    insert

    请注意可以插入一个string

    在pos位置前插入字符或字符串

    1. string& insert(size_t pos, char c)
    2. {
    3. if( _capacity == _size )reserve( 2 * _size );
    4. for (size_t i = _size; i > pos; i--)
    5. {
    6. _str[i] = _str[i - 1];
    7. }
    8. _size++;
    9. _str[pos] = c;
    10. }
    11. string& insert(size_t pos, const char* str)
    12. {
    13. int len = strlen(str);
    14. if (len + _size > _capacity)reserve(len + _size);
    15. for (size_t i = _size + len ; i >= pos + len; i--)
    16. {
    17. _str[i] = _str[i - len];
    18. }
    19. _size += len;
    20. memcpy(_str + pos, str, sizeof(char) * len);
    21. return *this;
    22. }

    使用方法:

    自定义类型的变量 . insert ( 参数列表 )

    erase

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

    从下标为pos的位置,删除len个字符,其中当len == npos时,就将从pos位置起以后(包括pos位置的数据)的数据删除

    find

    1. size_t find(char c, size_t pos = 0) const
    2. {
    3. for (size_t i = pos; i < _size; i++)
    4. {
    5. if (_str[i] == c)return i;
    6. }
    7. return -1;//npos
    8. }
    9. size_t find(const char* s, size_t pos = 0) const
    10. {
    11. char* tmp = strstr(_str , s );
    12. if (tmp == nullptr)
    13. return -1;
    14. else return tmp - _str;
    15. }

    找寻_str中是否存在字符c或字符串s,如果存在返回第一次出现时的下标

    不存在,返回-1

  • 相关阅读:
    python中的小tips
    数组c++介绍
    艾美捷Cy5.5单琥珀酰亚基酯 Cy5.5 NHS酯解决方案
    他凌晨1:30给我开源的游戏加了UI|模拟龙生,挂机冒险
    每日一题 2216. 美化数组的最少删除数(中等,贪心)
    移动端适配-(postcss-pxtorem)
    【Django毕业设计源码】Python考试题库练习系统
    【每日一句】名人金句学英语(20221126)
    [数据结构]~二叉树
    怎样用PHP语言实现远程控制三路开关
  • 原文地址:https://blog.csdn.net/wx20041102/article/details/137961869