引言:
现在是北京时间2023年6月22日的早上8点。又是一年端午,时光如梭。这一年来发生的变化太多了,遥想去年此时,我还沉浸在被大学录取的喜悦中,转眼间大一就过去了。这里我也衷心的祝愿您和您的家人端午安康!
关于元素访问的成员函数
上回介绍了下标访问操作符的运算符重载,这里我就不再介绍。第一个接口我们介绍的是at()接口。at和下标访问操作符的运算符重载使用起来是没什么区别的。但是,在对于越界操作的处理方式两者有些不同。at()对于越界访问是抛出异常。而下标访问操作符是直接assert暴力处理。
#include <iostream>
#include <string>
using namespace std;
int main()
{
try {
string s1("hello world");
s1.at(0) = 'x';
cout << s1 << endl;
//s1[15]; // 暴力处理
s1.at(15); // 温和的错误处理
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
front()接口和back()接口就是访问第一个和访问最后一个元素。这里也就不过多介绍了。需要注意的是这两个接口是c++11标准所支持的,在centOS7下的g++编译器下需要指定相关标准,简单演示一下。
g++ test.cpp -std=c++11
关于修改的成员函数
首先介绍的是insert()接口,insert()用于将字符/字符串/string类对象的内容插入到pos位置中。(1)在pos位置后插入一个string类对象。(2)在pos位置后,插入一个长度为sublen的string类对象的子串。(3)在pos位置后插入一个c字符串。(4)在pos位置后插入一个c字符串的前n个字符。(5)在pos位置后插入n个字符。(6)支持使用迭代器插入字符。(7)支持插入一个string类迭代器的区间。
接着介绍一下erase()接口,erase()接口用于删除string类对象的内容。(1)删除从pos位置开始len个字符(默认删除整个串)。当然可以利用缺省参数删除pos位置后的所有内容。(2)删除迭代器指向的字符。(3)删除迭代器区间的内容。
最后介绍一下replace()接口,replace()接口用新内容替换字符串中从字符pos开始并跨越len字符的部分。(1)从pos位置长度为len的部分替换成str类对象。(2)将pos位置长度为len的部分替换成str类对象的子串。(3)从pos位置长度为len的部分替换成c字符串。(4)从pos位置长度为len的部分替换c字符串的前n个字符。(5)从pos位置长度为len的部分替换c字符串的n个字符。(6)将迭代器i1-i2区间内的部分替换成first-last的内容。
小结:在学习了前面的顺序表部分内容后,是可以理解string类对象这些修改接口在底层大概是怎么实现的。由此也可以更加理解使用string类修改接口的一些效率上的差距。对于顺序表,从头部或pos位置删除或者插入都是比较麻烦的,因为要涉及遍历数据,删除/插入数据,以及挪动数据。效率上是非常差的。频繁的调用这些接口并不是很好的选择,当然这里也仅仅是介绍这些接口的使用方式。
字符串操作类函数
首先介绍c_str()接口,返回一个指针指向string类对象的首字符的地址。用于用于一些特殊场景,如调用c的库,就可以用c_str()将string类对象转化成c字符串。
下面介绍一下find()接口,find接口可以在字符串中搜索由其参数指定的内容第一次出现的下标位置。当指定pos时,搜索只包括位置pos或位置pos之后的字符,忽略任何可能出现的包含位置pos之前字符的字符。注意,与find_first_of()接口不同,每当搜索多个字符时,仅匹配其中一个字符是不够的,整个序列必须匹配。
下面介绍一下substr()接口,这个接口会返回一个用从pos位置长度为len的字串构造的string类。
下面就以截取一个URL的协议、域名、资源的问题进行演示。
介绍一下热find()接口,和find()功能类似,不同的是从string类的尾部往前遍历。可以用于查问指定后缀文件等场景。
find_first_of()接口在字符串中搜索与参数中指定的任何字符匹配的第一个字符。可以用循环遍历整个string类对象,用find_first_of()指定要访问的的内容的下标。
针对字符串操作类函数就暂且介绍这么多吧,百看不如一试,下来之后可以尝试用一用。下面进入oj部分的讲解。
string类OJ
字符串相加
本题解题思路如下,取字符串的末尾的数据并减去字符’0’后的整型值相加。若和大于10,就将和/10进1位。然后再讲和取余数尾插到string中。知道遍历完两个字符串后将整体逆置后返回。
//参考代码
class Solution {
public:
string addStrings(string num1, string num2)
{
string strRet;
int end1 = num1.size()-1;
int end2 = num2.size()-1;
//用来标记进位
int carry = 0;
//从后向前遍历字符串,两个都结束才结束
while(end1 >= 0 || end2 >= 0)
{
//根据与字符'0'的差相加
int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
int ret = val1+val2+carry;
//判断进位,并取余数尾插
carry = ret / 10;
ret %= 10;
//插入数据
strRet += '0'+ret;
//迭代
end1--;
end2--;
}
//判断是否还有没进的位
if(carry == 1)
{
strRet += '1';
}
//整体逆置
reverse(strRet.begin(),strRet.end());
return strRet;
}
};
字符串转化成整数
解题思路如下,首先倒着遍历字符串。一旦遇到非数字字符就直接return 0,若是数字字符就将其插入string类对象中。在第0位置处特殊判断一下若是’-'就将其表示为-1指存入整型变量中。然后逆置字符串。然后用除模取余的方式将string类对象的每一个字符都转化成对应为的整型值。最后将整型值*上特殊标记的整型变量返回。
class Solution {
public:
int StrToInt(string str) {
string strRet;
int val = 0;
//用于标记正负
int flag = 1;
int end = (str.size())-1;
//遍历string类对象
while(end >= 0)
{
if(str[end] >= '0' && str[end] <= '9')
{
val = str[end] - '0';
}
else if(end == 0 && (str[end] == '-' || str[end] == '+' ))
{
if(str[end] == '-')
flag = -1;
break;
}
else
{
return 0;
}
strRet += '0'+val;
end--;
}
//逆置
reverse(strRet.begin(),strRet.end());
int sz = strRet.size();
int ret = 0;
int n = 0;
while(sz)
{
//把对应位的值*位的权值后,加起来求和
int tmp = (strRet[sz-1] - '0') * pow(10,n++);
ret += tmp;
sz--;
}
return ret*flag;
}
};
字符串最后一个单词的长度
本题主要主要就是应用rfind()和getline()接口。由于是io型的OJ所以要用getline()输入数据,rfind()倒着遍历string类对象。反向查询最后一个空格所在位置,从而确定最后一个单词。循环遍历string类对象,用’ '出现的位置减去size+1即为最后一个单词长度。本题难点为cin不能接收空格或换行符就会停止读取,并将内容放到缓冲区。所以只能用getline()进行读取数据。getline()为非成员函数。
#include <iostream>
using namespace std;
int main()
{
string s1;
//cin不能读取空格和换行,不能用
getline(cin,s1);
size_t wpos = s1.rfind(' ');
if(wpos != string::npos)
{
//左闭右开-1就得到长度
cout << s1.size() - wpos - 1 << endl;
}
else
{
cout << s1.size() << endl;
}
return 0;
}