[C++/STL]string类

  • string类的常用接口

  1. string类对象的常见构造

  • 构造空的string类对象,即字符串:string()

  • 用C语言的字符串来构造string类对象:string(const char* str)

  • 用n个字符c来构造string类对象:string(size_t n, char c)

  • 拷贝构造函数:string(const string&s)

  • 区间构造:string(first,last),其中STL规定:所有的区间都是左闭右开[first,last)

函数名称

功能说明

string()

构造空的string类

string(const char* str)

用C语言字符串构造string类

string(size_t n, char c)

用n个字符c构造string类

string(const string&s)

拷贝构造函数

string(first,last)

区间构造

void TestString1()
{
    string s1;//空string类对象
    string s2("hello");//用C字符串构造
    string s3(6, 'a');//用5个字符a构造
    string s4(s3);//拷贝构造

    const char* str = "hello world";
    string s5(str, str + 8);//区间构造

    cout << s1 << ' ' << s2 << ' ' << s3 << ' ' << s4 << ' ' << s5 << endl;
    //cin和cout支持string类对象的输入与输出
    cin >> s1;
    cout << s1 << endl;
}
  1. string类的容量操作

函数名称

功能说明

size()

返回字符串有效字符长度

length()

返回字符串有效字符长度

capacity()

返回空间总大小

empty()

检测字符串是否为空串:空返回true,不空返回false

clear()

将有效元素清空(不修改空间总大小)

reserve(size_t newcapacity)

为字符串预留空间(修改capacity)

resize(size_t n,char c)

resize(size_t n)

将有效元素个数修改到n个,

多余的字符用c(\0)填充

void TestString2()
{
    string s1("hello string");
    cout << s1.size() << endl;//返回字符串有效字符长度
    cout << s1.length() << endl;//返回字符串有效字符长度
    cout << s1.capacity() << endl;//返回空间总大小
    if (s1.empty())//检测字符串是否为空:空返回true,不空返回false
    {
        cout << "s1 is empty" << endl;
    }
    else
    {
        cout << "s1 is not empty" << endl;
    }
    s1.clear();//将有效元素清空
    cout << s1.size() << endl;
    if (s1.empty())//检测字符串是否为空:空返回true,不空返回false
    {
        cout << "s1 is empty" << endl;
    }
    else
    {
        cout << "s1 is not empty" << endl;
    }
}
  • reserve() 和resize() 详解

(1)reserve(size_t newcapacity):该函数扩容的是capacity(容量)

newcapacity > oldcapacity 时将会进行扩容;

newcapacity < oldcapacity && newcapacity >= 16时会忽略本次操作;

newcapacity < 16 && 有效元素数量小于16时,会将空间大小缩小为15

👉为什么是缩小到15的原因:

在VS2022使用的STL版本是PJ版本:string对象内部包含了一个固定大小的数组:char buff[16]

绝大多数情况下的字符串中的有效元素个数都是小于16,这时直接使用固定大小的数组比从堆上开辟空间的效率更高;当有效元素的个数超过16个时,string类才需要真正从堆上开辟空间,开辟空间有时间消耗,所以string类从堆上开辟空间成功之后一般不在将空间缩小

void TestString3()
{
    string s1("hello world");

    //通过reserve()将s1底层空间扩大
    //如果newcapacity > oldcapacity 将会扩容 
    s1.reserve(20);
    s1.reserve(50);
    s1.reserve(80);
    s1.reserve(100);
    s1.reserve(120);

    //通过reserve()将s1底层空间缩小
    //如果newcapacity < oldcapacity && newcapacity >= 16时
    //reserve()会忽略此次操作,即不会缩小空间
    s1.reserve(100);
    s1.reserve(90);
    s1.reserve(80);
    s1.reserve(16);
    //newcapacity < 16 && 有效元素数量小于16时,reserve()才会将空间缩小为15
    s1.reserve(15);
    s1.reserve(12);

}

newcapacity > oldcapacity :

newcapacity < oldcapacity && newcapacity >= 16:

(2)resize(size_t n,char c):

当扩大有效元素个数时不够的用字符c填充;

当n小于有效元素个数时将有效元素个数缩小到n个时不会改变capacity

void TestString4()
{
    string s1("hello world");
    //当扩大有效元素个数时不够的用字符填充
    s1.resize(10, 'A');
    s1.resize(20, 'B');
    s1.resize(30, 'C');
    //当n小于有效元素个数时将有效元素个数缩小到n个时不会改变capacity
    s1.resize(30);
    s1.resize(20);
    s1.resize(17);
    s1.resize(10);
    s1.resize(5);

}

扩大有效元素个数:

缩小有效元素个数:

  1. string类的访问和遍历操作

函数名称

功能说明

operator[]

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

begin() / end()

begin()获取的是第一个字符的迭代器,end()获取的是最后一个字符下一个位置的迭代器

rbegin() / rend()

反向迭代器

范围for

更简洁的遍历方式

  • operator[] 与 at() 越界访问时的报错区别

operator[]:当用下标访问符来访问元素时越界是assert断言出的问题

at():当用at()函数访问时越界是通过抛出out_of_range来进行报错的

  • 迭代器:begin() 与 end()

begin():

返回的是首元素的位置

end():

返回的是最后一个有效元素的下一个位置

定义迭代器:string::iterator it = s1.begin();也可以使用 auto it = s1.begin();

迭代器使用:

void TestString13()
{
    string s1("1234567890");
    cout << s1 << endl;
    reverse(s1.begin(), s1.end());
    cout << s1 << endl;
    sort(s1.begin(), s1.end());//默认排升序
    cout << s1 << endl;
}

  1. string类对象的修改操作

函数名称

功能说明

push_back()

在字符串后尾插字符c(只能插入单个字符)

operator+=

在字符串后面追加字符串str

append()

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

c_str()

返回C格式的字符串

find() / npos

从pos的位置开始查找,返回第一次查找到的字符,如果没有找到则返回npos

rfind()

从pos的位置开始反向查找,返回第一次查找到的字符,如果没有找到则返回npos

substr()

从pos位置开始截取子串

insert()

在任意位置插入

erase()

在任意位置删除

push_back() / operator+=()

void TestString6()
{
    string s1("hello string");
    //在字符串后面尾插字符c
    s1.push_back('!');
    cout << s1 << endl;
    //拼接c格式的字符串
    s1 += "!!!!!";
    cout << s1 << endl;
    //拼接string类对象
    string s2(" hello world");
    s1 += s2;
    cout << s1 << endl;

}

append():

void TestString7()
{
    string s1("hello");
    //string& append (size_t n, char c);
    //在s1后尾插1个字符' '
    s1.append(1, ' ');//s1.push_back(' ') || s += ' '; 
    cout << s1 << endl;
    //string& append (const char* s);
    //在s1后追加字符串" world"
    s1.append("world");//s1 += " world";
    cout << s1 << endl;
    //string& append(const string & str);
    //在s1后面拼接s2(string类对象)
    string s2(" string");
    s1.append(s2);
    cout << s1 << endl;
    //string& append (const string& str, size_t subpos, size_t sublen);
    //在s1对象后面拼接s3对象从第2个位置开始,拼接长度为3
    string s3("1234567");
    s1.append(s3, 2, 3);
    cout << s1 << endl;
}

insert():

void TestString8()
{
    string s1("hello");
    //string& insert(size_t pos, size_t n, char c);
    //在0号位置插入3个字符A
    s1.insert(0,3, 'A');
    cout << s1 << endl;
    //string& insert (size_t pos, const char* s);
    //在0号位置插入C格式的字符串
    s1.insert(0, "string");
    cout << s1 << endl;
    //string& insert (size_t pos, const string& str);
    //在13号位置之后,在14号位置之前,插入string类对象s2
    string s2("HELLO");
    s1.insert(14, s2);
    cout << s1 << endl;
    //void insert (iterator p, InputIterator first, InputIterator last);
    //在s1对象的0号位置之前插入s3对象的一段区间(0号位置到最后一个位置)
    string s3("BBBB");
    s1.insert(s1.begin(), s3.begin(), s3.end());
    cout << s1 << endl;
}

erase():

void TestString9()
{
    string s1("hello string");
    //string& erase(size_t pos = 0, size_t len = npos);
    //删除s1对象的0号位置到6号位置
    s1.erase(0, 6);//删除“hello ”
    cout << s1 << endl;
    //删除从s1对象的0号位置开始,在向后加2的位置
    s1.erase(s1.begin() + 2);//删除“r”
    cout << s1 << endl;
    //删除s1对象的一个区间[s1.begin(),s1.end())
    s1.erase(s1.begin(), s1.end());//删除所有
    cout << s1 << endl;
}

c_str():

void TestString14()
{
    string s1("12345");
    //c_str():返回C格式的字符串const char*
    int ret = atoi(s1.c_str());
    cout << ret << endl;
}

find():

void TestString15()
{
    string s1("123142153115");
    size_t pos = 0;
    //找到所有的1将其替换成0
    while (true)
    {
        //size_t find (char c, size_t pos = 0) const;
        //从pos位置开始查找字符'1',返回第一次找到的位置
        pos = s1.find('1',pos);
        if (pos == string::npos)
            break;
        s1[pos] = '0';
        pos += 1;
    }
    cout << s1 << endl;
}

rfind()、substr()

void TestString16()
{
    //获取文件最后一个点之后的内容
    string s1("123.txt.cpp");
    size_t pos = s1.rfind(".") + 1;
    //string substr (size_t pos = 0, size_t len = npos) const;
    //从pos位置开始截取n个字符,n没有传递表示从开始截取到末尾
    string postfix = s1.substr(pos);
    cout << postfix << endl;
}

  • 在VS2022下string类的扩容机制

在vs2022版本下,string类的以1.5倍的方式扩容的,vs2022是PJ版本

void TestString10()
{
    string s1;
    size_t cap = 0;
    for (size_t i = 0; i < 100; i++)
    {
        s1.push_back('A');
        if (cap != s1.capacity())
        {
            cap = s1.capacity();
            cout << cap << endl;
        }
    }
}

在linux下:SGI版本STL的string是按照2倍的方式扩容的

  • 范围for:更简洁的遍历方式

void TestString11()
{
    string s1("1234567890");
    for (auto e : s1)//范围for
    {
        cout << e;
    }
    cout << endl;
}

auto :auto是一个占位符,系统可以根据后面的值来推测出用auto定义的变量的类型

使用条件: 1.for循环的范围必须是确定的

2.迭代的对象需要实现++和==的操作

  • reverse():反转字符串函数

void reverse(iterator begin(),iterator end());

void TestString12()
{
    string s1("hello string");
    cout << s1 << endl;
    reverse(s1.begin(), s1.end());
    cout << s1 << endl;
}
  1. string类的非成员函数

函数名称

功能说明

getline()

获取一行字符串

operator+

尽量少用,因为传值返回导致深拷贝效率低

relational operator

大小比较

getline():

cin是以空白字符来进行分割的,cin不能接收空白字符

getline()是接收一行的字符串

  • string类大小比较

从最高位开始比,ASCII码更大的字符串更大,如果相等,比次高位,以此类推。

所以在string中9>89,因为最高位9>8;如果每个数字都相等,位数更大的显然更大,例如:

99999>9999。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值