文章目录
- 1:构造string类
- 1.1:方法
- 1.2:测试
- 2:size和length
- 2.1:用途
- 2.2:测试
- 3:capacity
- 3.1:用途
- 3.2:测试
- 4:clear
- 4.1:用途
- 4.2:测试
- 5:empty
- 5.1:用途
- 5.2:测试
- 6:reserve
- 6.1:用途
- 6.2:测试
- 7:resize
- 7.1:用途
- 7.2:测试
- 8:string的三种遍历
- 8.1:方法一 for循环和[]重载
- 8.2:方法二 迭代器
- 8.2.1:const迭代器
- 8.2.2:迭代器和[]的结论
- 8.3范围for
- 9:push_back
- 9.1:功能
- 9.2:测试
- 10:append
- 10.1:用法
- 10.2:测试
- 11:operator +=
- 11.1:用法
- 11.2:测试
- 12:字符串相加例题
- 13:reverse
- 13.1:用法
- 13.2:测试
- 14:find
- 14.1:用法
- 14.2:测试
- 15:rfind
- 15.1:用法
- 16:substr
- 16.1:用法
- 17:find_first_of
- 17.1:用法
- 17.2:测试
- 18:erase
- 18.1:用法
- 19:c_str
- 19.1:用法
- 19.2:测试
- 20:assign
- 20.1:用法
- 20.2:测试
- 21:replace
- 21.1:用法
- 21.2:测试
1:构造string类
1.1:方法
- string() :构造一个空字符串对象
- string(const char* str) :用C-String构造对象
- string(size_t n, char c):string类对象中包含n个c
- string(const string& str):拷贝构造对象
1.2:测试
string test1;//构造空的string类对象
string test2("abcd");//用c-string构造string类对象
string test3(test2);//用拷贝构造函数构造
2:size和length
2.1:用途
都是求字符串对象有效字符个数。
返回值是size_t
2.2:测试
string test4("hello world");
size_t size1 = test4.size();//有效字符长度 返回值是size_t
size_t size2 = test4.length();//有效字符长度 返回值是size_t
均为11,11位hello + 空格 + world的长度,不包含\0,而为什么会有length和size的名称差别呢,因为在数据结构中对于链表和顺序表的结构,length可以表明长度,但是在树等结构中用size可以更直观的表明大小。
3:capacity
3.1:用途
求字符串对象的容量
3.2:测试
string str1;string str2("abc");size_t c1 = str1.capacity();size_t c2 = str2.capacity();
4:clear
4.1:用途
清除字符串中的有效字符
4.2:测试
string str("abcdefg");str.clear();cout << str << endl;
什么也没有打印出来,那他的capacity有变化吗?
容量是没有变化的,还是15,因此clear只是清空string中有效字符,不改变底层空间大小。
5:empty
5.1:用途
判断字符串是否为空,空返回true,否则返回false。
5.2:测试
string str1("abcdefg");string str2;bool k1 = str1.empty();bool k2 = str2.empty();return 0;
6:reserve
6.1:用途
为string对象预留空间
6.2:测试
string str("abcd");
str.reserve(20);
size_t k = str.capacity();//不预留的话是15
容量变成了31,因此针对我们用c语言实现的数据结构中,涉及多次扩容的并且暂时知道数据容量多少的时候,先提前reserve好空间比较好。
7:resize
7.1:用途
将有效字符变成n个,查询cplusplus文档得知。
有2种用法,用空字符填充和用指定字符填充。
既然是更改字符的数量,那么肯定有3种情况。
- n在size和capacity中间 插入数据,闭区间
- n<size 删除数据
- n>capacity 扩容,补充数据
7.2:测试
string st1("hello wjw");st1.resize(5);cout << st1.size() << endl;cout << st1.capacity() << endl;cout << st1 << endl<<endl;string st2("hello wjw");st2.resize(15);cout << st2.size() << endl;cout << st2.capacity() << endl;cout << st2 << endl<<endl;string st3("hello wjw");st3.resize(15,'*');cout << st3.size() << endl;cout << st3.capacity() << endl;cout << st3 << endl<<endl;string st4("hello wjw");st4.resize(30,'*');cout << st4.size() << endl;cout << st4.capacity() << endl;cout << st4 << endl << endl;
st2和st3的resize差别是在于填充的字符是空字符和*的区别。
可以看到当n<size的时候,直接返回前n个字符。不修改容量
size<=n<=capacity的时候,插入数据,不修改容量
capacity<n的时候,扩容,再插入数据。
8:string的三种遍历
8.1:方法一 for循环和[]重载
for (size_t i = 0; i < str.size(); i++){cout << str[i] << endl;}
用[]重载
8.2:方法二 迭代器
string::iterator it = str.begin();while (it != str.end()){cout << *it << endl;}
c++中string类中存在迭代器。begin和end获取一个字符的迭代器,begin是字符串第一个字符,end是最后一个字符的下一个位置的迭代器。
同时还有反向迭代器,反向遍历。
string::reverse_iterator rit = str.rbegin();while (rit != str.rend()){cout << *rit << endl;}
在c++11中,可以直接使用auto关键词推导迭代器类型。
auto it = str.begin();while (it != str.end()){cout << *it << endl;}
8.2.1:const迭代器
注意以下情况,如果我们要求只读一个字符串的时候,如何使用迭代器?比如
void test(const string& str)
{string::iterator it = str.begin();while(it != str.end()){cout<<*it<<endl;}
}
编译器报错,说不能从const的迭代器转换到非const的迭代器。
查询文档得知。
设计了2种迭代器。
当我们只读的时候,应使用string::const_iterator的格式。
同样的针对第一种[]遍历,
也有2种,const和非const。
const string str("abcdefg");for (size_t i = 0; i < str.size(); i++){str[i] += 1;cout << str[i] << endl;}
当给定的是常量字符串对象,[]就会调用const类型的,如果试图修改字符串,就会报错。
8.2.2:迭代器和[]的结论
针对只读的功能函数,设计的时候提供const版本即可
针对只写的功能函数,设计的时候提供非const版本即可
针对读写的功能函数,设计的时候提供const和非const版本
8.3范围for
string str("abcd");for (auto ch : str){cout << ch;}
9:push_back
9.1:功能
尾插一个字符,会扩容
9.2:测试
string str("abcd");size_t k = str.capacity();for(size_t i = 0; i < 100; i++){str.push_back('a');if (k != str.capacity()){k = str.capacity();cout << "capacity changed:" << str.capacity() << endl << endl;}}}
每次大概是1.5倍的扩容,
10:append
10.1:用法
在字符串末尾添加字符串
10.2:测试
string str("abcd");str.append("hello");string str2("bit");str.append(str2);cout << str << endl;
可以追加一个字符串对象,也可以直接追加字符串。
11:operator +=
11.1:用法
追加字符串
11.2:测试
string str("abcd");
str += "hello bit";
string str2("abcd");
str += str2;
cout << str << endl;
12:字符串相加例题
class Solution {
public:string addStrings(string num1, string num2) {
int end1 = num1.size()-1;
int end2 = num2.size()-1;
string num3;
int carry = 0;
while(end1>=0||end2>=0)
{int sum1 = end1>=0?num1[end1]-'0':0;int sum2 = end2>=0?num2[end2]-'0':0;int ret = sum1 + sum2 + carry;carry = ret / 10;ret %= 10;num3 += ret+'0';--end1;--end2;
}
if(carry == 1)
{num3 += '1';
}
reverse(num3.begin(),num3.end());
return num3;
}
};
13:reverse
13.1:用法
逆置字符串
13.2:测试
string str("hello wjw");reverse(str.begin(), str.end());cout << str << endl;
是给2个迭代器,逆置2个迭代器范围内的数据。
14:find
14.1:用法
查找第一个符合的字符,并且返回他的下标。
如果没有查找到,返回npos
所以在查找的时候一般可以让查找值是否等于-1来判断是否找到。
14.2:测试
string str("hello wjw");size_t pos = str.find('j');if (pos != -1){cout << str[pos] << endl;}
string库实现的时候,给pos位置一个缺省值,因此如果我们只传对象的时候,默认是从下标0开始查找的。
那如何查找下一个字符呢?
string str("woshi woshi");size_t pos = str.find('w');while (pos != string::npos){cout << str[pos] << endl;pos = str.find('w', pos + 1);}
设置下一次查找的位置在第一次找到的pos之后一个位置即可。
15:rfind
15.1:用法
反向查找第一个符合的字符,并且返回其下标。
16:substr
16.1:用法
返回pos位置开始的后续的len个字符
如图len是给了缺省值npos的,npos是size_t类型,因此如果我们不传参len的话,是相当于直接返回pos开始直到字符串结束的所有字符。
因此比如我们想取一个文件的后缀名的时候,就可以使用这个
string file("test.cpp");size_t pos = file.rfind('.');string str = file.substr(pos);cout << str << endl;
17:find_first_of
17.1:用法
在string里面查找与给定的字符c或者字符串相符合的 string里面的第一个字符的下标。
17.2:测试
string str("wo ai ni ge chou sha bi");size_t pos = str.find_first_of("oie");while (pos != string::npos){str[pos] = '*';pos = str.find_first_of("oie", pos + 1);}cout << str << endl;
18:erase
18.1:用法
删除pos位置的字符
第一个是删除pos位置开始,如果不给len的长度就会删除从pos位置一直到字符串结束的所有字符。
第二个是给一个迭代器,删除这个位置的字符
第三个是给2个迭代器,删除2个迭代器范围内的所有字符。
string str("wo ai ni ge chou sha bi");//类似头删str.erase(0,1);cout << str << endl;string str("wo ai ni ge chou sha bi");str.erase(str.begin());cout << str << endl;string str("wo ai ni ge chou sha bi");str.erase(str.begin(), str.end());cout << str << endl;
在数据结构中顺序表我们学过,头删是要挪动数据的,因此我们尽量少用。时间复杂度为O(N^2)
19:c_str
19.1:用法
返回一个c语言中的数组,该数组为c字符串,包含\0
19.2:测试
string str("wo ai ni ge chou sha bi");
char* str1 = new char[str.size() + 1];
strcpy(str1, str.c_str());
cout << str1 << endl;
20:assign
20.1:用法
将字符串全部替换为另外一个字符串的前n个,如果没有定义n,n默认为npos,相当于先clear再+=。
20.2:测试
string str("wo ai ni ge chou sha bi");cout << str.capacity()<< endl;str.assign("abcd");cout << str.capacity() << endl;
如果是变小,容量不变
string str("wo ai ni ge chou sha bi");cout << str.capacity()<< endl;str.assign("abcdadsadasdsadasdsadsadsadasd123213123213213213123213213213");cout << str.capacity() << endl;
如果是变大,扩容。
assign相当于赋值拷贝
string str("wo ai ni ge chou sha bi");
21:replace
21.1:用法
从pos位置开始的len个字符替换成str
21.2:测试
string str("wo ai ni ge chou sha bi");str.replace(3, 2, "buai");cout << str << endl;
如图就是把从第一个a开始的2个字符替换成buai。