一、string类介绍

以下讲解内容均围绕该文档:string介绍文档
string:管理字符串的类(其底层还是模板)
需要包头文件:< string >

#include <iostream>
#include <string>
using namespace std;
int main()
{

	return 0;
}

常用接口:
1、构造
2、[]重载
3、容量操作
4、访问与遍历
5、修改

二、string构造

在这里插入图片描述
string类的构造函数C++98中有以下7种,其中常用的有三种:无参构造,带参构造,拷贝构造。
在这里插入图片描述
注:string类重载了流插入、流提取,可以直接输入输出。

1、常用3种构造(对应文档1、2、4)

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s1;//无参构造
	string s2("hello world");//带参构造
	string s3(s2);//拷贝构造
	//cin >> s1;
	//cout<<s2<<endl;

	string s4(s2,6,5);//从s2的下标为6的位置开始拷贝,拷贝5个字符存放到s4中。
	
	cout<<s4<<endl;//打印结果为world
	return 0;
}

2、子字符串构造函数

在这里插入图片描述
用法介绍:
在这里插入图片描述
在这里插入图片描述
其中,npos为size_t的最大值。
在这里插入图片描述

int main()
{
	string s2("hello world");//4带参构造
	//用法1:
	string s4(s2,6,5);//从s2的下标为6的位置开始拷贝,拷贝5个字符存放到s4中。
	//用法2:
	string s5(s2,6,15);//复制的长度为15,越界了,但string会自动从下标6开始拷贝到字符串末尾
	//用法3:
	string s6(s2,6);//第三个参数len有缺省值npos,根据用法2,仍然是自动从下标6开始拷贝到字符串末尾
	cout<<s4<<endl;//打印结果为world
	return 0;
}

3、拷贝前n个构造

在这里插入图片描述
在这里插入图片描述

拷贝字符串s的前n个字符,给该字符数组初始化。

int main()
{
	string s("hello world",5);//拷贝字符串的前5个字符,赋值给s
	cout<<s<<endl;//结果为hello
	return 0;
}

4、填充构造

在这里插入图片描述
在这里插入图片描述
用n个字符c来填充,初始化该字符数组。

int main()
{
	string s(5,'a');//用5个'a'来初始化s
	cout<<s<<endl;//结果为aaaaa
	return 0;
}

三、operator[ ]重载

在这里插入图片描述
重载[ ]之后,我们可以直接通过[]来修改字符数组中的对应字符。能直接检查出来下标的越界。

int main()
{
	string s("hello world");
	s[0] = 'x';
	//s[15] 会越界报错
	cout<<s<<endl;//结果为xello world
	return 0;
}

四、string类对象的容量操作

在这里插入图片描述

1、size、length

size和length的作用基本上没有区别,均为获取字符数组的长度
在这里插入图片描述
在这里插入图片描述

int main()
{
	string s("hello world");
	cout<<s.size()<<endl;//结果为11
	//或 cout<<s.length()<<endl;
	return 0;
}

2、max_size

获取最大长度,这个接口没啥意义。了解即可

3、capacity

获取空间总大小。编译器为str开了16(15+1)个空间,其中有一个为‘\0’,(capacity返回的容量大小不包含‘\0’)
在这里插入图片描述

4、reserver

为字符串预留空间(第一次开的空间大小会大于等于预留的空间)所开的空间中默认不包含‘\0’

提前开空间,提高效率

在这里插入图片描述
vs中开空间比预留的大:
在这里插入图片描述
情况分析:

reserve(n)
n < size
size < n < capacity
n > capacity

(以VS编译器为例)

void test01()
{
	string s("hello worldxxxxxxxxxxx");
	cout << "初始:" << endl;
	cout << "size:" << s.size() << endl;		//22
	cout << "capacity:" << s.capacity() << endl;//31
	cout << endl;

	cout << "n<size时:" << endl;
	s.reserve(10);//n=10
	cout << "size:" << s.size() << endl;		//22
	cout << "capacity:" << s.capacity() << endl;//31
	cout << endl;

	cout << "size<n<capacity时:" << endl;
	s.reserve(25);//n=25
	cout << "size:" << s.size() << endl;		//22
	cout << "capacity:" << s.capacity() << endl;//31
	cout << endl;

	cout << "n>capacity时:" << endl;
	s.reserve(100);//n=100
	cout << "size:" << s.size() << endl;		//22
	cout << "capacity:" << s.capacity() << endl;//111
}

在这里插入图片描述

由上可知,在VS编译器下,当n>capacity时,才会进行扩容,其它情况时,容量不变。
在g++下,其它情况时,容量会缩小至n

5、clear

清空有效字符,不会清除容量。
在这里插入图片描述

void test02()
{
	string s("hello world");
	cout << "size:" << s.size() << endl;
	cout << "capacity:" << s.capacity() << endl;
	s.clear();
	cout << "size:" << s.size() << endl;		
	cout << "capacity:" << s.capacity() << endl;
}

在这里插入图片描述

6、empty

检测字符串是否为空串,是返回true,不是返回false
在这里插入图片描述

7、shrink_to_fit

将多余的容量去除,缩小容量至size
在这里插入图片描述

五、string类对象的访问及遍历(迭代器)

迭代器分为正向迭代器和反向迭代器。
顾名思义,正向迭代器是正向地从首元素开始迭代。反向迭代器是反向地从末元素开始迭代。

简单来说,迭代器是像指针一样的东西,但又不是指针。所有的容器都可以用它来访问!
迭代器的指向范围是左闭右开
vector < int >::iterator 其中,vector为容器名
string相关迭代器:
在这里插入图片描述

1、正向迭代器iterator

begin、end为例:

在这里插入图片描述
返回第一个位置的迭代器
在这里插入图片描述
返回最后一个元素的下一个位置的迭代器

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it;
		++it;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

2、反向迭代器reverse_iterator

这里以rbegin、rend为例,写法:

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str("abcdefg");
	string::reverse_iterator rit = 	str.rbegin();
	while (rit != str.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	return 0;
}

在这里插入图片描述

3、const迭代器const_iterator

特点:只读,不能修改
begin和end支持const类型(begin和end支持const和非const,而cbegin、cend只返回const迭代器)
在这里插入图片描述

const string str("abcdefg");
string::const_iterator cit = str.begin();
//或 auto cit = str.begin(); 使用auto自动推导类型
while(cit != str.end())
{
	cout<< *cit << " ";
	++cit;
}

4、const反向迭代器const_reverse_iterator

rbegin、rend支持const类型(crbegin、crend确定返回const迭代器)
在这里插入图片描述

const string str("abcdefg");
string::const_reverse_iterator rcit = str.rbegin();
//或 auto rcit = str.rbegin();  使用auto自动推导类型
while(rcit != str.rend())
{
	cout<< *rcit << " ";
	++rcit;
}

六、string类对象的访问及遍历(auto和范围for)

1、auto

  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
  • auto不能直接用来声明数组

2、范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。
  • for循环后的括号由冒号":"分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围自动迭代,自动取数据,自动判断结束
  • 范围for可以作用到数组容器对象上进行遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器。

所有的容器都支持迭代器,迭代器支持范围for,即所有的容器都支持范围for

3、结合使用

当我们需要遍历字符串时,使用auto和范围for非常方便:

(1)遍历字符串

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("hello world");
	//auto用来判断ch的类型,ch : s 是将s中的每一个元素存入ch中,然后通过cout打印每一个元素
	for (auto ch : s)
	{
		cout << ch << " " ;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

(2)遍历数组

#include <iostream>
#include <string>
using namespace std;
int main()
{
	//遍历数组
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	for (auto e : arr)
	{
		cout << e << " ";
	}
	return 0;
}

在这里插入图片描述

七、练习

1、仅仅反转字母

题目链接:仅仅反转字母
在这里插入图片描述

class Solution {
public:
    //判断是否为字母
    bool isChar(char a)
    {
        if((a>='a'&&a<= 'z')||(a>='A'&&a<='Z'))
            return true;
        else
            return false;
    }
    string reverseOnlyLetters(string s) {
        //前后指针
        int left = 0,right=s.size()-1;
        while(left<right)
        {
            while(left<right && !isChar(s[left]))
                left++;
            while(left<right && !isChar(s[right]))
                right--;
            swap(s[left++],s[right--]);
        }
        return s;
    }
};

2、字符串中的第一个唯一字符

题目链接:字符串中的第一个唯一字符
在这里插入图片描述

class Solution {
public:
    int firstUniqChar(string s) {
        //记录出现次数
        int count[26]={0};
        //遍历,统计次数
        for(auto ch : s)
        {
            count[ch-'a']++;//相对位置的count值++
        }
        //返回下标
        for(int i=0;i<s.size();i++)
        {
            //s[i]-'a'为该字符在count数组中的相对位置
            if(count[s[i]-'a']==1)
                return i;
        }
        return -1;//未找到
    }
};

3、字符串相加

题目链接:字符串相加
在这里插入图片描述

方法1:尾插,O(n)

在这里插入图片描述

reverse用法
reverse 封装在< algorithm >中,参数为begin()迭代器和end()迭代器,左闭右开
作用:将该字符串进行逆置

在这里插入图片描述

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size()-1,end2 = num2.size()-1;
        string str;//存放加完后的字符串
        //进位
        int next = 0;
        while(end1>=0 || end2>=0)//当两个字符串都结束时,才结束
        {
            
            int val1=end1>=0 ? num1[end1--]-'0' : 0; //当该字符串结束时,对应位 置为0,后进行相加
            int val2=end2>=0 ? num2[end2--]-'0' : 0;
            //和
            int ret = val1+val2+next;
            next = ret/10;//进位
            ret %= 10;//对应位应放的值
            //尾插
            str+=(ret+'0');
           
        }
        //处理最高位进位
        if(next==1)
        str+='1';
        //逆置
        reverse(str.begin(),str.end());
        return str;
    }
};

方法2:头插,O(N^2)

该方法的大致思路与尾插相似,只是结果插入str时进行的是头插,最终结果不必进行逆置

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size()-1,end2 = num2.size()-1;
        string str;//存放加完后的字符串
        //进位
        int next = 0;
        while(end1>=0 || end2>=0)//当两个字符串都结束时,才结束
        {
            
            int val1=end1>=0 ? num1[end1--]-'0' : 0; //当该字符串结束时,对应位 置为0,后进行相加
            int val2=end2>=0 ? num2[end2--]-'0' : 0;
            //和
            int ret = val1+val2+next;
            next = ret/10;//进位
            ret %= 10;//对应位应放的值
            //头插
            str.insert(str.begin(),ret+'0');
           
        }
        //处理最高位进位
        if(next==1)
        str.insert(str.begin(),'1');
        return str;
    }
};

在这里插入图片描述

八、谢谢观看!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐