STL容器之string类

文章目录

  • STL容器之string类
    • 1、 什么是STL
    • 2、STL的六大组件
    • 3、string类
      • 3.1、string类介绍
      • 3.2、string类的常用接口说明
        • 3.2.1、string类对象的常见构造
        • 3.2.2、string类对象的容量操作
        • 3.2.3、string类对象的访问及遍历操作
        • 3.2.4、 string类对象的修改操作
        • 3.2.5、 string类非成员函数
      • 3.3、 vs和g++下string结构的说明
    • 4、string类的模拟实现

img

STL容器之string类

1、 什么是STL

C++标准模板库(Standard Template Library,STL)是C++标准库的一部分,提供了一组通用的模板类和函数,以实现常见的数据结构和算法


2、STL的六大组件

STL包含了多个模块,其中一些主要的包括:

  1. 容器(Containers)

    • string:它被设计为一个动态数组,提供了一系列成员函数来操作字符串,同时自动处理内存的分配和释放。

    • vector: 动态数组,可动态调整大小。

    • list: 双向链表。

    • deque: 双端队列,支持在两端高效地插入和删除元素。

    • queue: 队列。

    • stack: 栈。

    • set: 集合,不允许重复元素。

    • map: 映射,键-值对的关联容器。

    • unordered_set 和 unordered_map: 使用哈希表实现的集合和映射。

  2. 算法(Algorithms)

  • 提供了许多常见的算法,如排序、搜索、遍历等。
  • 包括了泛型算法,例如 sortfindbinary_search 等。
  1. 迭代器(Iterators)

    • 提供了多种迭代器类型,用于遍历不同类型的数据结构。
  2. 函数对象(Function Objects)也称仿函数(functor)

  • 包括了一些预定义的函数对象,如比较器等。
  1. 适配器(Adapters)

    • 提供了用于修改容器接口的适配器,如 stackqueue priority_queue(优先队列,基于堆实现)。
  2. 空间配置器(allocator)

  • std::allocator: 是STL中默认的空间配置器。它使用 newdelete 运算符来进行内存分配和释放。

3、string类

3.1、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_string<char, char_traits, allocator> string
  4. 不能操作多字节或者变长字符的序列

注意在使用string类时,必须包含#include头文件(#include <string>)以及using namespace std;

3.2、string类的常用接口说明

string类对象其实就是字符串,但是字符串不一定是string类对象

3.2.1、string类对象的常见构造
(constructor)函数名称功能说明
string()(重点)构造空的string类对象,即空字符串
string (const string& str)(重点)拷贝构造函数
string (const string& str, size_t pos, size_t len = npos)构造从string类对象str的pos位置向后len长度的string类对象
string (const char s)(重点)*用C-string(字符串,不是字符串对象)来构造string类对象
string (const char s, size_t n)*构造字符串s从开始位置到n位置的string类对象
string (size_t n, char c)构造n个连续字符c的string类对象
int main() {//构造函数/拷贝构造函数string s1;cout << s1 << endl;string s2("hello");cout << s2 << endl;string s3(s2);cout << s3 << endl;string s4(s3, 2, 10);cout << s4 << endl;string s5("world", 2);cout << s5 << endl;return 0;
}
3.2.2、string类对象的容量操作
函数名称功能说明
size(重点)返回string类对象有效字符长度
length返回string类对象有效字符长度
max_size返回string类对象可以达到的最大字符长度
resize(重点)将有效字符的个数改成n个,多出的空间用字符c填充(如果有参数字符c)
capacity返回当前已经分配给string类对象的存储空间大小,单位是字节
reserve(重点)要求string类对象的容量调整为计划好的容量(参数为n),如果n小于之前的容量,则不调整,大于则调整为n(看编译器,有些编译器可能大于n)
clear(重点)清空string类对象的内容,使其变成一个空字符串
empty(重点)判断string类对象是不是空
int main() {string s1("hello world a");cout << s1.capacity() << endl;//返回当前已经分配给字符串的存储空间大小,单位是字节cout << s1.size() << endl;//返回字符串有效字符长度cout << s1.length() << endl;//返回字符串有效字符长度cout << s1.max_size() << endl;//返回字符串可以达到的最大字符长度s1.resize(25, 'x');//将有效字符的个数该成n个,多出的空间用字符c填充(如果有参数字符c)cout << s1.size() << endl;cout << s1.capacity() << endl;s1.reserve(33);//要求字符串的容量调整为计划好的容量(参数为n),如果n小于之前的容量,则不调整,大于则调整为n(看编译器,有些编译器可能大于n)cout << s1 << endl;cout << s1.capacity() << endl;s1.clear();//清空字符串的内容,使其变成一个空字符串cout << s1.empty() << endl;//判断字符串是不是空return 0;
}

注意

  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不会改变容量大小只影响容量,不影响数据
3.2.3、string类对象的访问及遍历操作
函数名称功能说明
operator[](重点)返回string类对象在pos位置的字符引用,分const和非const,const则字符串内容(字符)不能被修改
at和opreator功能一样
back取string类对象象的末尾字符
front取string类对象的最前面字符
begin返回一个迭代器指向string类对象最前面的字符,分const和非const,const是使得this指向的内容不能改变
end返回一个迭代器指向string类对象最后面的字符的后面一个位置,和begin一样,分const和非const
rbegin反向迭代器,和begin差不多,就是这是指向string类对象最末尾字符位置
rend反向迭代器,和begin差不多,就是这是指向string类对象最前面字符的前一个位置
cbegin和begin差不多,但是这是专门用于const迭代器的
crbegin和cbegin差不多,就是这是指向string类对象最末尾字符位置
范围forC++11支持更简洁的范围for的新遍历方式
int main() {const string str1("hello ynu");string str2("hello ynu");//    str1[1] = '1';//常量string对象,这里调用的是const char& operator[] (size_t pos) const;str2[1] = 'n';str2.at(2) = 'y';char ch1 = str2.back();char ch2 = str2.front();string::iterator it2 = str2.begin();while (it2 != str2.end()) {cout << *it2;fflush(stdout);//将缓冲区数据刷新到终端it2++;}cout << endl;//const迭代器string::const_iterator it1 = str1.begin();while (it1 != str1.end()) {cout << *it1;it1++;}cout << endl;//反向迭代器string::reverse_iterator it3 = str2.rbegin();while (it3 != str2.rend()) {cout << *it3;it3++;}cout << endl;//专属/const迭代器string::const_iterator it = str1.cbegin();while (it != str1.end()) {cout << *it;it++;}cout << endl;//范围forfor (auto e: str2) {cout << e;}cout << endl;return 0;
}

3.2.4、 string类对象的修改操作
函数名称功能说明
operator+=(重点)在string类对象末尾追加字符、字符串或者string类对象
append在string类对象末尾追加字符(参数需要加上添加字符的个数n)、字符串或者string类对象
push_back在string类对象末尾增加一个字符
npos(重点)大小为无符号数的最大值,用int表示即-1
insert在string类对象pos位置之前插入字符(参数需要加上添加字符的个数n)、字符串或者string类对象
erase从string类对象pos位置开始删除长度为len的字符串,若不指定len,则len为npos(最大无符号int值)
replace从string类对象pos位置开始向后长度为len的字符串替换为新字符(参数需要加上添加字符的个数n)、新字符串或者新string类对象
swap用一个新string类对象交换本string类对象的内容。注意这里是引用,可以减少对象拷贝
c_str(重点)返回C格式字符串,这个比data常用
data和c_str一样
copy将string类对象从pos位置开始向后的n个字符复制到新字符数组里,并返回这个复制的字符串长度
findstring类对象从pos位置开始向后查找字符、字符串或者string类对象,返回第一次出现的起始字符位置。pos不指定,则从string类对象的第一个字符开始查找。没找到则返回npos
rfind和find差不多,这是pos位置从后往前找,找到返回返回第一次出现的起始字符位置。没找到返回npos
find_first_of在string类对象中找到字符、字符串和string类对象里的匹配的任意字符的第一个位置
substr返回一个string类对象,这个string类对象是原string类对象从pos位置开始向后len长度的截取的字符串副本
int main() {string s1("hello world");string s2("no no no");//operator+=s2 += "hh";s2 += 'x';s2 += s1;//appends1.append(1, 'x');s1.append("hh");s1.append(s2);//push_backs2.push_back('x');//inserts1.insert(0, "xx");s1.insert(0, 2, 'x');//erases1.erase(0, 4);//replaces1.replace(0, 4, "x");//swaps1.swap(s2);//c_strconst char *str = s1.c_str();//dataconst char *str1 = s1.data();string s3("hello world");//copychar buffer[20] = {0};size_t length = s3.copy(buffer, 8, 0);buffer[length] = '\0';cout << buffer << endl;//findsize_t found1 = s3.find('d', 3);cout << found1 << endl;size_t found2 = s3.find('f');//测试是不是用int表示的-1int test = found2;cout << found2 << endl;cout << test << endl;//rfindsize_t found3 = s3.rfind("ll", 5);cout << found3 << endl;string s4("hello gun qnd world haha no --skas wcl cb ");//find_first_ofsize_t found4 = s4.find_first_of("gunwcqnd", 0);while (found4 != std::string::npos) {s4[found4] = '*';found4 = s4.find_first_of("gunwcqnd", found4 + 1);}cout << s4 << endl;//substrstring sub_str = s4.substr(0, 9);cout << sub_str << endl;return 0;
}

注意

  1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

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

3.2.5、 string类非成员函数
函数名称功能说明
operator+返回一个string类对象,这是string类对象是(字符、字符串、string类对象)的其中两个的串联
relational operators(重点)包含操作符==、!=、<、<=、>、>=,返回值都是bool类型
swap交换两个string类对象的值。这是非成员函数,还有一个成员函数swap
operator>>(重点)从输入流中提取字符串,并存储到string类对象str中,str中之前到数据将会被覆盖。即输入运算符重载
operator<<(重点)将string类对象str的字符序列插入到输出流中。即即输出运算符重载
getline(重点)获取一行字符串。弥补了operator>>的缺陷(遇到第一个空格就只读到第一个空格之前的字符串)
int main() {//operator+string s1("hello");string s2("world");string s3 = s1 + s2;cout << s3 << endl;string s4 = s1 + 'x';cout << s4 << endl;//operator==bool b = s1 == s2;cout << b << endl;//swapcout << s1 << endl;cout << s2 << endl;swap(s1, s2);cout << s1 << endl;cout << s2 << endl;//operator>>cin >> s1;cout << s1 << endl;//operator<<cout << s2 << endl;string s5("hello ynu");//getlinegetline(cin, s5);cout << s5 << endl;return 0;
}

3.3、 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;
      };
      

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

  • CLion下string的结构

    CLion下string对象总共占12个字节,是在_rep里存储了三个指针,分别是__l、__s、__r。因此总共12+4+4+4 = 24字节。


4、string类的模拟实现

  • main.cpp文件

    #include "string.h"int main() {
    //    xp::test_string1();
    //    xp::test_string2();
    //    xp::test_string3();
    //    xp::test_string4();
    //    xp::test_string5();
    //    xp::test_string6();
    //    xp::test_string7();
    //    xp::test_string8();
    //    xp::test_string9();
    //    xp::test_string10();
    //    xp::test_string11();xp::test_string12();return 0;
    }
  • string.cpp文件

    //
    // Created by 徐鹏 on 2023/11/29.
    //#include "string.h"namespace xp {string::string(const char *s) {_size = strlen(s);//这里还没有size()呢,size()得自己写_capacity = _size;_str = new char[_capacity + 1];//多开一个空间存\0strcpy(_str, s);}//拷贝构造函数 --   传统写法
    //    string::string(const string &str) {
    //        _size = str._size;
    //        _capacity = str._capacity;
    //        _str = new char[_capacity + 1];
    //        strcpy(_str, str._str);
    //    }//  现代写法string::string(const string &str) : _str(nullptr), _size(0),_capacity(0) {//这里得使用初始化列表或者在private里得成员变量进行缺省,防止交换后tmp指向随机值,调用析构就会出错string tmp(str._str);swap(tmp);}void string::swap(string &str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}void string::reserve(size_t n) {if (n > _capacity) {//扩容char *new_str = new char[n + 1];strcpy(new_str, _str);delete[] _str;_str = new_str;_capacity = n;}//小于等于则不改变容量}void string::resize(size_t n) {if (n > _capacity) {//需要重新开辟空间reserve(n);} else {//缩小容量和有效字符_capacity = n;_size = n;_str[n] = '\0';}}char &string::operator[](size_t pos) {assert(pos < _size);return _str[pos];}const char &string::operator[](size_t pos) const {assert(pos < _size);return _str[pos];}char &string::at(size_t pos) {
    //        assert(pos < _size);
    //        抛异常return _str[pos];}const char &string::at(size_t pos) const {
    //        assert(pos < _size);
    //        抛异常return _str[pos];}void string::append(const string &str) {size_t total_size = _size + str._size;//如果新插入的字符串加上之前的字符串的长度大于容量,则需要扩容if (total_size > _capacity) {reserve(total_size);}//把字符加进来for (int i = 0; i < str._size; ++i) {_str[_size++] = str[i];}_str[_size] = '\0';}void string::append(const char *s) {size_t total_size = _size + strlen(s);//如果新插入的字符串加上之前的字符串的长度大于容量,则需要扩容if (total_size > _capacity) {reserve(total_size);}//把字符加进来strcpy(_str + _size, s);_size += strlen(s);}string &string::operator+=(const string &str) {append(str);return *this;}string &string::operator+=(const char *s) {string str(s);append(str);return *this;}string &string::operator+=(char c) {push_back(c);return *this;}void string::push_back(char c) {size_t total_size = _size + 1;//如果新插入的字符加上之前的字符串的长度大于容量,则需要扩容if (total_size > _capacity) {reserve(total_size);}//把字符加进来_str[_size++] = c;_str[_size] = '\0';}string &string::insert(size_t pos, const string &str) {assert(pos < _size);
    //        size_t total_size = _size + str._size;
    //        //如果新插入的字符串加上之前的字符串的长度大于容量,则需要扩容
    //        if (total_size > _capacity) {
    //            reserve(total_size);
    //        }
    //        int end = _size;
    //        //pos后面数据先后移,每个元素后移str._size,这里end最后等于-1
    //        while (end >= (int) pos) {
    //            _str[end + str._size] = _str[end];
    //            --end;
    //        }
    //
            size_t end = total_size;
            //pos后面数据先后移,每个元素后移str._size,这里end最后等于0
            while (end > pos) {
                //当end减去str._size的时候,也就是预留的给插入的长度小于str._size时候,说明pos后面的数据移动完成,直接退出就行
                if (end - str._size < 0)
                    break;
                _str[end] = _str[end - str._size];
                --end;
            }
    //        //插入数据
    //        strncpy(_str + pos, str._str, str._size);
    //        _size = total_size;insert(pos, str.c_str());//复用return *this;}string &string::insert(size_t pos, const char *s) {assert(pos < _size);size_t total_size = _size + strlen(s);if (total_size > _capacity) {reserve(total_size);}size_t end = total_size;//pos后面数据先后移,每个元素后移str._size,这里是相当于元素后移,这里end最后等于0while (end > pos) {//当end减去strlen(str)的时候,也就是预留的给插入的长度小于strlen(str)时候,说明pos后面的数据移动完成,直接退出就行if (end - strlen(s) < 0)break;_str[end] = _str[end - strlen(s)];--end;}//插入数据strncpy(_str + pos, s, strlen(s));_size = total_size;return *this;}string &string::insert(size_t pos, size_t n, char c) {assert(pos < _size);size_t total_size = _size + n;if (total_size > _capacity) {reserve(total_size);}size_t end = total_size;//pos后面数据先后移,每个元素后移str._size,这里是相当于元素后移,这里end最后等于0while (end > pos) {if (end - n < 0)break;_str[end] = _str[end - n];--end;}//插入数据while (n--) {_str[pos++] = c;}_size = total_size;return *this;}string &string::erase(size_t pos, size_t len) {assert(pos < _size);if (len == std::string::npos || len + pos >= size()) {_str[pos] = '\0';//pos后面数据全部不要了_size = pos;} else {strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}size_t string::find(const string &str, size_t pos) const {assert(pos < _size);const char *ret = strstr(_str + pos, str._str);if (nullptr == ret) return std::string::npos;return ret - _str;}size_t string::find(const char *s, size_t pos) const {assert(pos < _size);const char *ret = strstr(_str + pos, s);if (nullptr == ret) return std::string::npos;return ret - _str;}size_t string::find(char c, size_t pos) const {assert(pos < _size);while (pos < _size) {if (_str[pos] == c) return pos;pos++;}//没找到return std::string::npos;}string string::substr(size_t pos, size_t len) const {assert(pos < _size);size_t end = pos + len;if (len == npos || end >= _size) {end = _size;}string str;str.reserve(end - pos);//开辟空间while (pos < end) {str += _str[pos++];}//把\0也带进去str._str[_size] = '\0';return str;}// 传统写法
    //    string &string::operator=(const string &str) {
    //        if (this != &str) {
    //            reserve(str._capacity);
    //            strcpy(_str, str._str);
    //            _size = str._size;
    //        }
    //
    //        return *this;
    //    }//  现代写法string &string::operator=(string str) {//这里不会改变赋值的值,这里str只是临时拷贝swap(str);return *this;}string &string::operator=(const char *s) {reserve(strlen(s));strcpy(_str, s);_size = strlen(s);return *this;}string &string::operator=(char c) {reserve(1);_str[0] = c;_str[1] = '\0';_size = 1;return *this;}ostream &operator<<(ostream &out, string &str) {for (auto e: str) {out << e;}return out;}istream &operator>>(istream &in, string &str) {str.clear();char buffer[128];//缓冲一下char c = in.get();int i = 0;while (c != ' ' && c != '\n') {buffer[i++] = c;if (i == 127) {buffer[i] = '\0';str += buffer;i = 0;//重置}c = in.get();}//提前读到' ' 或者 '\n'if (i > 0) {buffer[i] = '\0';str += buffer;}return in;}string::~string() {delete[] _str;_str = nullptr;_capacity = 0;_size = 0;}void test_string1() {string s1;cout << s1.c_str() << endl;string s2("hello world");cout << s2.c_str() << endl;string s3(s2);cout << s3.c_str() << endl;}void test_string2() {string s1;string s2("hello world");cout << s2.capacity() << endl;s2.reserve(2);cout << s2.capacity() << endl;s2.resize(15);cout << s2.capacity() << endl;s2.resize(7);cout << s2.capacity() << endl;cout << s2.c_str() << endl;}void test_string3() {string s1("hello world");const string s2("nihao liangzai");string::iterator it1 = s1.begin();while (it1 != s1.end()) {cout << *it1 << " ";++it1;}cout << endl;string::const_iterator it2 = s2.begin();while (it2 != s2.end()) {cout << *it2 << " ";++it2;}cout << endl;}void test_string4() {string s1("hello world");const string s2("nihao liangzai");//        s1.append(s2);
    //        s1.append("hh");
    //        s1 += s2;
    //        s1 += "hh";
    //        s1 += 'x';s1.push_back('v');cout << s1.c_str() << endl;}void test_string5() {string s1("hello world");const string s2("nihao liangzai");//        s1.insert(0, s2);
    //        s1.insert(2, "hh");s1.insert(11, 5, 'x');cout << s1.c_str() << endl;}void test_string6() {string s1("hello world");const string s2("nihao liangzai");s1.erase();cout << s1.c_str() << endl;}void test_string7() {string s1("hello world");string s2("nihao liangzai");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1.swap(s2);cout << s1.c_str() << endl;cout << s2.c_str() << endl;}void test_string8() {string s1("hello world");const string s2("wo");size_t pos1 = s1.find(s2);size_t pos2 = s1.find("d");size_t pos3 = s1.find("f");size_t pos4 = s1.find('o');cout << pos1 << endl;cout << pos2 << endl;cout << (int) pos3 << endl;cout << (int) pos4 << endl;}void test_string9() {string s1("hello world");string s2(s1.substr(5, 2));const string s3("nihao liangzai");string s4(s3.substr(2, 5));cout << s2.c_str() << endl;cout << s4.c_str() << endl;}void test_string10() {string s1("hello world");const string s2("nihao liangzai");cout << s1.c_str() << endl;s1 = s2;cout << s1.c_str() << endl;s1 = "woshixp";cout << s1.c_str() << endl;s1 = '1';cout << s1.c_str() << endl;}void test_string11() {string s;cin >> s;cout << s << endl;}void test_string12() {string s1("111");string s2(s1);cout << s1 << endl;cout << s2 << endl;string s3;s3 = s2;cout << s3 << endl;}}
    
  • string.h文件

    //
    // Created by 徐鹏 on 2023/11/29.
    //#include <cstring>
    #include <iostream>
    #include <assert.h>
    #include <vector>using namespace std;#ifndef DEMO_42_STRING_H
    #define DEMO_42_STRING_H#endif  DEMO_42_STRING_Hnamespace xp {class string {public://构造函数string() : _str(new char[1]), _size(0), _capacity(0) {_str[0] = '\0';//空字符串也包含一个\0}string(const char *s);//拷贝构造函数string(const string &str);//字符串大小size_t size() const {return _size;}//总容量size_t capacity() const {return _capacity;}//string转char*const char *c_str() const {return _str;}//要求string类对象的容量调整为计划好的容量void reserve(size_t n);//将有效字符的个数改成n个void resize(size_t n);//清空字符串void clear() {_str[0] = '\0';_size = 0;//只清空数据,不清空容量}//判断字符串是不是空字符串bool empty() {return _size == 0;}//下标访问char &operator[](size_t pos);const char &operator[](size_t pos) const;char &at(size_t pos);const char &at(size_t pos) const;const char &back() const {return _str[_size - 1];}const char &front() const {return _str[0];}//迭代器typedef char *iterator;typedef const char *const_iterator;iterator begin() {return _str;}iterator end() {return _str + _size;}const_iterator begin() const {return _str;}const_iterator end() const {return _str + _size;}//尾插字符或者字符串void append(const string &str);void append(const char *s);//尾插字符或者字符串string &operator+=(const string &str);string &operator+=(const char *s);string &operator+=(char c);//尾插字符void push_back(char c);//从某个位置前插字符string &insert(size_t pos, const string &str);string &insert(size_t pos, const char *s);string &insert(size_t pos, size_t n, char c);//从某个位置向后删除n个字符string &erase(size_t pos = 0, size_t len = std::string::npos);//交换void swap(string &str);//从某个位置开始查找字符、字符串、string对象位置size_t find(const string &str, size_t pos = 0) const;size_t find(const char *s, size_t pos = 0) const;size_t find(char c, size_t pos = 0) const;//取子串string substr(size_t pos = 0, size_t len = npos) const;//赋值string &operator=(string str);string &operator=(const char *s);string &operator=(char c);~string();private:char *_str;size_t _capacity;size_t _size;static const size_t npos = -1;};//重载流插入ostream &operator<<(ostream &out, string &str);//重载流提取istream &operator>>(istream &in, string &str);void test_string1();void test_string2();void test_string3();void test_string4();void test_string5();void test_string6();void test_string7();void test_string8();void test_string9();void test_string10();void test_string11();void test_string12();}
    

OKOK,C++ STL容器之string类就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/267275.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++提高编程】

C提高编程 C提高编程1 模板1.1 模板的概念1.2 函数模板1.2.1 函数模板语法1.2.2 函数模板注意事项1.2.3 函数模板案例1.2.4 普通函数与函数模板的区别1.2.5 普通函数与函数模板的调用规则1.2.6 模板的局限性 1.3 类模板1.3.1 类模板语法1.3.2 类模板与函数模板区别1.3.3 类模板…

Redis源码安装教程来喽~

一.下载 Index of /releases/ [rootserver ~]# wget --no-check-certificate http://download.redis.io/releases/redis-6.2.7.tar.gz二.解压 [rootserver ~]# tar xf redis-6.2.7.tar.gz -C /usr/local/ [rootserver ~]# cd /usr/local [rootserver local]# ll 总用量 44K …

黑马JavaWeb课程中安装vue脚手架出现的问题

1 安装node.js 要想前端工程化&#xff0c;必须安装node.js&#xff0c;前端工程化的环境。 在成功安装node.js后&#xff0c; 修改全局包安装路径为Node.js安装目录&#xff0c; 修改npm镜像源为淘宝镜像源&#xff0c;这里出现第一个问题&#xff0c;视频中给的淘宝镜像为&…

Find My扫地机器人|苹果Find My技术与机器人结合,智能防丢,全球定位

扫地机器人又称自动打扫机、智能吸尘、机器人吸尘器等&#xff0c;是智能家电的一种&#xff0c;能凭借人工智能&#xff0c;自动在房间内完成地板清理工作。一般采用刷扫和真空方式&#xff0c;将地面杂物先吸纳进入自身的垃圾收纳盒&#xff0c;从而完成地面清理的功能。现今…

Vue.js大师: 构建动态Web应用的全面指南

VUE ECMAScript介绍什么是ECMAScriptECMAScript 和 JavaScript 的关系ECMAScript 6 简介 ES6新特性let基本使用const不定参数箭头函数对象简写模块化导出导入a.jsb.jsmain.js Vue简介MVVM 模式的实现者——双向数据绑定模式 Vue环境搭建在页面引入vue的js文件即可。创建div元素…

计算机网络——22TCP拥塞

TCP拥塞 TCP拥塞控制机制 端到端的拥塞控制机制 路由器不向主机有关拥塞的反馈信息 路由器的负担较轻符合网络核心简单的TCP/IP架构原则 端系统根据自身得到的信息&#xff0c;判断是否发生拥塞&#xff0c;从而采取动作 拥塞控制的几个问题 如何检测拥塞 轻微拥塞拥塞 控…

戏说c第二十六篇: 测试完备性衡量(代码覆盖率)

前言 师弟&#xff1a;“师兄&#xff0c;我又被鄙视了。说我的系统太差&#xff0c;测试不过关。” 我&#xff1a;“怎么说&#xff1f;” 师弟&#xff1a;“每次发布版本给程夏&#xff0c;都被她发现一些bug&#xff0c;太丢人了。师兄&#xff0c;有什么方法来衡量测试的…

STM32USART串口数据包

文章目录 前言一、介绍部分数据包两种包装方式&#xff08;分割数据&#xff09;HEX数据包文本数据包 数据包的收发流程数据包的发送数据包的接收固定包长的hex数据包接收可变包长的文本数据包接收 二、实例部分固定包长的hex数据包接收连接线路代码实现 可变包长的文本数据包接…

存储过程基本了解

文章目录 介绍存储过程示例1. 目的2. 输入参数3. 输出参数4. 执行逻辑5. 返回值6. 示例用法7. 注意事项 存储过程的关键字有哪些简单实操 介绍 存储过程是一组预编译的SQL语句&#xff0c;以及流程控制语句&#xff0c;封装在数据库服务器中并可以被重复调用。它们可以接收参数…

css实现居中

基础代码&#xff1a; <div class"box"><div class"content"></div> </div> css实现居中的几种方式&#xff1a; 1、flex布局&#xff08;水平垂直&#xff09; .box {width: 200px;height: 200px;background-color: pink;disp…

C#,K中心问题(K-centers Problem)的算法与源代码

1 K中心问题&#xff08;K-centers Problem&#xff09; k-centers problem: 寻找k个半径越小越好的center以覆盖所有的点。 比如&#xff1a;给定n个城市和每对城市之间的距离&#xff0c;选择k个城市放置仓库&#xff08;或ATM或云服务器&#xff09;&#xff0c;以使城市…

c语言经典测试题8

在c语言经典测试题6的第一题&#xff0c;大家是否想过可不可以将递归参数改为s呢&#xff1f;或许有的人已经试过了&#xff0c;但是发现好像不会有结果&#xff0c;其实是因为s为后置&#xff0c;先试用后加1&#xff0c;然而我们这个是在s出了函数之后才会运行加1操作&#x…

sqllabs第五关floor报错注入

实验环境sqllabs第五关 floor()报错注入的原因是group by在向临时表插入数据时&#xff0c;由于rand()多次计算导致插入临时表时主键重复&#xff0c;从而报错&#xff0c;又因为报错前concat()中的SQL语句或函数被执行&#xff0c;所以该语句报错且被抛出的主键是SQL语句或函…

《求生之路2》服务器如何选择合适的内存和CPU核心数,以避免丢包和延迟高?

根据求生之路2服务器的实际案例分析选择合适的内存和CPU核心数以避免丢包和延迟高的问题&#xff0c;首先需要考虑游戏的类型和对服务器配置的具体要求。《求生之路2》作为一款多人在线射击游戏&#xff0c;其服务器和网络优化对于玩家体验至关重要。 首先&#xff0c;考虑到游…

AI时代,我们需要什么能力?

AI 时代&#xff0c;一定会重构很多行业&#xff0c;也会重构人民的生活工作方式&#xff0c;那么 AI 时代&#xff0c;我们需要培养什么能力呢&#xff1f; 我们应该去做那些 AI 做不了的事情&#xff01;让 AI 成为我们的工具&#xff0c;助力我们更高效的解决问题&#xff…

JS利用Worker多线程大文件切片上传

在做前端上传时&#xff0c;会遇到上传大文件&#xff0c;大文件就要进行分片上传&#xff0c;我们整理下思路&#xff0c;实现一个分片上传&#xff0c;最终我们要拿到每一个分片的hash值&#xff0c;index 分片索引&#xff0c;以及分片blob&#xff0c;如下&#xff1a; 一…

曾桂华:车载座舱音频体验探究与思考| 演讲嘉宾公布

智能车载音频 I 分论坛将于3月27日同期举办&#xff01; 我们正站在一个前所未有的科技革新的交汇点上&#xff0c;重塑我们出行体验的变革正在悄然发生。当人工智能的磅礴力量与车载音频相交融&#xff0c;智慧、便捷与未来的探索之旅正式扬帆起航。 在驾驶的旅途中&#xff0…

智慧治水丨计讯物联水利RTU助推小型水库出险加固工程建设与管理

日前&#xff0c;水利部印发《关于健全小型水库除险加固和运行管护机制的意见》&#xff08;以下简称《意见》&#xff09;&#xff0c;健全小型水库除险加固和运行管护常态化机制&#xff0c;提高小型水库安全管理水平。《意见》提出了“十四五”的两大管理机制&#xff0c;通…

基础小白快速入门c语言--

变量&#xff1a; 表面理解&#xff1a;在程序运行期间&#xff0c;可以改变数值的数据&#xff0c; 深层次含义&#xff1a;变量实质上代表了一块儿内存区域&#xff0c;我们可以将变量理解为一块儿内存区域的标识&#xff0c;当我们操作变量时&#xff0c;相当于操作了变量…

ad18学习笔记十六:如何放置精准焊盘到特定位置,捕抓功能的讲解

网上倒是一堆相关的指导 AD软件熟练度提升&#xff0c;如何设置板框捕捉&#xff1f;_哔哩哔哩_bilibili 关于Altium Designer 20 的捕抓功能的讲解_ad捕捉设置-CSDN博客 AD软件捕捉进阶实例&#xff0c;如何精确的放置布局元器件&#xff1f;_哔哩哔哩_bilibili AD绘制PCB…