赞
踩
目录
在C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
为了弥补这些C语言中的部分设计缺陷,C++研发出了string类,更好的服务于程序员。
重点:
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。为了找到好Offer,熟练掌握string类是我们C艹程序员的必要工作。
string类的文档链接:https://cplusplus.com/reference/string/string/
同时,使用string类大多数情况还需要头文件#include<string>
string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。
String类的常用初始化
函数名称(红色为重点) | 功能说明 |
string s() | 构造空的string类对象,即空字符串 |
string s(const char* s) | 用C-string来构造string类对象 |
string s(size_t n, char c) | string类对象中包含n个字符c |
string s(const string&s) | 拷贝构造函数 |
如:
- //常用构造函数
- #include<iostream>
- //用string类的话需要包含头文件#include<string>
- using namespace std;
- int main()
- {
- string s1;
- string s2("abcdefg");
- string s3(99, 'a');
- string s4(s2);
-
- cout << s2 << endl;
- cout << s3 << endl;
- cout << s4 << endl;
- return 0;
- }
代码结果为:
函数名称(红色为重点) | 功能说明 |
size() | 返回字符串有效字符长度,(有效空间) |
length() | 返回字符串有效字符长度,(有效空间) |
capacity() | 返回空间总大小 |
empty() | 检测字符串释放为空串,是返回true,否则返回false |
clear() | 清空有效字符 |
reserve(size_t n=0) | 为字符串预留空间 |
resize(size_t n,char c) | 将有效字符的个数该成n个,多出的空间用字符c填充 |
如:
- //容量操作
- #include<iostream>
- using namespace std;
-
- // size()函数
- int main()
- {
- string s1(99, 'a');
- cout << s1.size() << endl;
- return 0;
- }
代码结果为:
- //容量操作
- #include<iostream>
- using namespace std;
-
- //length()函数
- int main()
- {
- string s1(99, 'a');
- cout << s1.length() << endl;
- return 0;
- }
代码结果为:
注意:
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。(这个属于C++的早期设计缺陷)
- //容量操作
- #include<iostream>
- using namespace std;
-
- //capacity()函数
- int main()
- {
- string s1(10,'a');
- cout << s1.capacity() << endl;
-
- return 0;
- }
代码结果为:
根据vs 开辟空间的规则,创建string类时初始分配十五个字节的总空间,但实际上这里的有效空间为10。
我们可以用size求出s1的有效空间 如:
- #include<iostream>
- using namespace std;
-
- //capacity()函数
- int main()
- {
-
- string s1(10,'a');
- cout << s1.capacity() << endl;
- cout << s1.size() << endl;`
- return 0;
- }
- //容量操作
- #include<iostream>
- using namespace std;
-
- // empty()函数
- int main()
- {
- string s1;
- string s2("12345");
- cout << s1.empty() << endl;
- cout << s2.empty() << endl;
- return 0;
- }
代码结果为:
一.resize() 重新规划string的大小,但是注意,这里实际上规划的是有效空间的大小。
通过前边的知识,我们可以用size()求出有效空间的大小,用resize进行重新规划。
如:
- //容量操作
- #include<iostream>
- using namespace std;
-
- //resize()函数和reserve()函数
- int main()
- {
- string s1("Hello World");
-
- cout << s1.size() << endl;
- cout << s1.capacity() << endl;
-
- s1.resize(5);//通过resize把有效空间改为5
-
- cout << s1.size() << endl;
- cout << s1.capacity() << endl;
-
- cout << s1 << endl;
- return 0;
- }
输出结果为:
这时候就分两种情况
1.缩小有效空间:
这种情况下,容器中长度在n之外的部分会被截取掉,只保留n长度内的元素,但是容器的容量却没有改变,更不会出现扩容的状况,上段代码体现了这一点。
2.扩大有效空间:
这种情况下,容器为了能够放的下更多的元素,会发生扩容,扩容之后,其容量会比原来大,这时候就会出现没有用过的有效空间,此时我们通过函数的第二个元素 c 进行剩余空间的初始化。
也就是说,当扩容时,扩容的空间内存放的元素全都是第二个元素 C。如果没有指定第二个元素c,那就用string的默认初始化了,这种情况下,容器一定是分配了内存并全部发生了初始化的。
如:
- //容量操作
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello World");
-
- cout << s1 << endl;
- cout << s1.size() << endl;
- cout << s1.capacity() << endl;
- s1.resize(20, 'x');
-
- cout << s1 << endl;
- cout << s1.size() << endl;
- cout << s1.capacity() << endl;
-
- return 0;
- }
代码结果为:
注意:有效空间的变化可能会影响最大空间的变化,最大空间的变化也可能影响有效空间的变化。
二.reserve() 函数改变最大空间。
- 容量操作
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello World");
-
- cout << s1.capacity() << endl;
- s1.reserve(20);
-
- cout << s1.capacity() << endl;
-
- return 0;
- }
代码结果为:
注意:这里代码结果不同预想也是因为VS 的容量规则
- 容量操作
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello World");
-
- cout << s1.size() << endl;
- s1.clear();
-
- cout << s1.size() << endl;
- cout << s1.capacity() << endl;
-
- return 0;
- }
代码结果为:
注意:clear()只是将string中有效字符清空,不改变底层空间大小。
函数名称 (重点为红色) | 功能说明 |
[] (operator[]) | 返回pos位置的字符,const string类对象调用 |
begin() | 获取第一个字符位置的迭代器 |
end() | 获取最后一个字符下一个位置的迭代器 |
rbegin() | 获取最后一个元素的反向迭代器 |
rend() | 获取第一个位置之前一个位置的反向迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
实际上就是数组的[],可以随机访问元素,底层是操作符重载(不讲)。
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- // []
- int main()
- {
- string s1("abcde");
- cout << s1[0] << endl;
- cout << s1[s1.size()-1] << endl;
- cout << s1[2] << endl;
- return 0;
- }
代码结果为:
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- //begin()和end()
- int main()
- {
- string s1("12345");
- string::iterator it = s1.begin();
- while (it != s1.end())
- {
- cout << *it << endl;
- it++;
- }
- return 0;
- }
代码结果为:
两图解迭代器原理(狗头保命):
C++中,迭代器就是一个类似于指针的对象,它能够用来遍历C++标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。
但在string中,我们最常用的还是数组的下标访问,故不在多描述。
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- //rbegin()和rend()
- int main()
- {
- string s1("12345");
- string::reverse_iterator it = s1.rbegin();
- while (it != s1.rend())
- {
- cout << *it << endl;
- it++;
- }
- return 0;
- }
结果为:
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
-
- //for(auto )
- int main()
- {
- string s1("12345");
- for (auto it : s1)
- {
- cout << it << endl;
- }
- return 0;
- }
代码结果为:
是不是看起来很高端:
一图解范围for:
函数名称 | 功能说明 |
push_back(c) | 在字符串后尾插字符c |
append(s) | 在字符串后追加一个字符串 |
+=(operator+= ) | 在字符串后追加字符串str |
c_str | 返回C格式字符串 |
find + npos | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
类似于链表的尾插
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello ");
-
- cout << s1 << endl;
- s1.push_back('W');
- s1.push_back('o');
- s1.push_back('r');
- s1.push_back('l');
- s1.push_back('d');
-
- cout << s1 << endl;
- return 0;
- }
结果为:
也类似于链表的尾插,但是插入的是一个字符串。
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello ");
- cout << s1 << endl;
- s1.append("World");
- cout << s1 << endl;
- return 0;
- }
结果为:
本质上是一个符号重载,依旧类似于链表的尾插。
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello ");
- cout << s1 << endl;
- s1 += "World";
- cout << s1 << endl;
- return 0;
- }
结果为:
注意:
在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
在C语言中,字符串是以'\0'结尾的一些字符的集合。但在C++中,string类不以'\0'结尾,而是根据有效空间的大小结束。
这个函数的本质作用是:将 const string* 类型 转化为 const char* 类型
find有很多函数重载,我们只学一种就好了。
size_t find (const string &s,int pos=0);
s是需要查找的字符串,pos是从哪个位置查找 , 如果未查找到则返回npos(size_t 的最大值)。
如:
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("fghasdabc");
- cout << s1.find('a') << endl;
-
- string s2("abc");
- cout << s1.find(s2) << endl;
- cout << s1.find('e') << endl;
- return 0;
- }
代码结果为:
同样,rfind()和find()只有一个往前找,一个像后找的区别:
size_t find (const string &s,int pos=npos);
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("fghasdabc");
- cout << s1.rfind('a') << endl;
-
- string s2("abc");
- cout << s1.rfind(s2) << endl;
- cout << s1.rfind('e') << endl;
- return 0;
- }
此时 第一个打印结果就会发生变化:
函数定义为: string substr(size_t pos=0,size_t len=npos) const;
作用为:在string的pos位置截取n个字符,然后返回
- //string类对象的访问及遍历操作函数
- #include<iostream>
- using namespace std;
-
- int main()
- {
- string s1("Hello World");
-
- cout << s1 << endl;
- string s2(s1.substr(0, 5));
-
- cout << s1 << endl;
-
- cout << s2 << endl;
- return 0;
- }
结果为:
函数名字 (红色为重点) | 作用说明 |
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>> | 输入运算符重载 |
operator<< | 输出运算符重载 |
getline | 获取一行字符串 |
relational operators | 字符串大小比较 |
这个大家根据 + 和 +=的特性 ,再结合类的知识点,自己推一下为什么效率低(绝对不是因为我懒!!!)。
重载输入输出。
函数定义为:
istream& getline (istream & is,string& str);
注意:
cin输入会自动吃点前置换行和空格,即cin输入得到的不可能是空串。而getline不会吃掉换行符号和空格,可能会使得输入出现意料之外的错误。
比如说:
- #include<iostream>
- #include<string>//需要头文件
- using namespace std;
-
- int main()
- {
- string s1;//输入个Hello World 看看
- cin >> s1;
- cout <<endl<< s1 << endl;
- //string s2;
- //getline(cin, s2);
- //cout << endl << s2 << endl;
-
- return 0;
- }
代码结果为:
可见,cin遇见空格就结束了,可能会使得输入出现意料之外的错误。
正确的做法是使用getline();
- //string类对象的访问及遍历操作函数
- #include<iostream>
- #include<string>//需要头文件
- using namespace std;
-
- int main()
- {
- //string s1;//输入个Hello World 看看
- //cin >> s1;
- //cout <<endl<< s1 << endl;
- string s2;
- getline(cin, s2);
- cout << endl << s2 << endl;
-
- return 0;
- }
就是符号重载了关系运算符;
使得>=,<=等运算符可以用于字符串比较
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。