目录
前言
一、string类对象的常见构造
二、string类对象的访问及遍历
1.下标+【】(底层operator【】函数)
编辑
2.迭代器
3.范围for
4.at
5.back和front
三、string类对象的容量操作
1.size 和 length
2.capacity
3.empty
4.clear
5.resize(调整当前字符串的大小)
6.reserve(改变当前容量的大小)
7.shrink_to_fit(缩容)
四、string类对象的修改操作
1.operator+=(尾部追加)
2.append(拼接)
3.push_back(尾插)
4.insert(插入)
5.erase(删除)
6.replace(替换)
7.swap(交换)
五、string的查找
1.find(左闭右开区间,正向查找)
2.rfind(反向查找)
六、string的截取
substr:左闭右开
七、string与字符串的转化
1.字符串转化为string
2.string转为字符串
八、非成员函数重载
1.operator<<和operator>>(输入输出运算符重载)
2.relational operators (string)
前言
好了,老铁们,前面我们对C++的一些基础语法以及一些注意事项都有了一定的了解!那么接下来我们将要进入一个崭新的世界,就是对STL库的学习!对于STL的学习核心有三点:熟用、明理(底层实现)、扩展!下面先来看看string类
- 通过文档可以看出string是表示字符串的字符串类
- 底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>stirng;
- 使用string类时,必须包含#include头文件以及using namespace std;
如果想要了解更多,关于string类的说明,大家可以参照这个文档:string类
一、string类对象的常见构造
string(); //构造一个空字符串,长度为0(默认构造) string (const string& str); //拷贝构造 string (const char* s); //复制s所指向的字符序列 string (const char* s, size_t n); //复制所指向的字符序列的前n个字符 string (size_t n, char c); //复制n个字符C string (const string& str, size_t pos, size_t len = npos); //复制str中从字符位置pos开始并跨越len个字符的部分(如果str太短或len为string::npos,则复制到str的末尾)
示例:
string s0; //构造空串 string s1("is string"); //复制is string const char* s = "hello string"; string s2(s); //复制"hello string" string s3(s, 3); //复制"hello string"前3个字符 string s4(10, '#'); //复制10个# string s5(s1, 0, 5); //从s1中的位置0开始跨越5个字符的部分,左闭右开区间 cout << s0 << endl; cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; cout << s4 << endl; cout << s5 << endl;
二、string类对象的访问及遍历
1.下标+【】(底层operator【】函数)
string s1("hello string");
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << ' ';
//底层写法:cout << s1.operator[](i) << endl;
}
2.迭代器
- 正向迭代器(begin+end)
begin函数:返回一个指向字符串第一个字符的迭代器
end函数:返回一个指向字符串最后一个字符的下一个位置(即为'\0')的迭代器
这里要注意到,迭代器的函数都会有两个形式一个是非const,一个是const!会根据对象类型的不同去选择不同的函数!
示例:
string s1("hello string"); string::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << ' '; it++; }
const string s2("hello string"); string::const_iterator it = s2.begin(); while (it != s2.end()) { cout << *it << ' '; it++; } // const对象返回的是const迭代器,所以不能用普通迭代器去接受
- 反向迭代器(rbegin+rend)
rbegin函数:返回一个指向字符串最后一个字符的反向迭代器
rend函数:返回一个指向字符串第一个字符前理论元素的反向迭代器(被认为是反向端)
示例:
string::reverse_iterator it1 = s1.rbegin(); while (it1 != s1.rend()) { cout << *it1 << ' '; it1++; }
可以看出,其实就是反向输出!但是要注意它是反向++的
3.范围for
for (auto a : s1) { cout << a << ' '; }
其实,范围for底层就是个迭代器!!!
4.at
for (int i = 0; i<s.length(); ++i) { cout << s.at(i) << " "; }
注意:这里是at(),不是方括号[],和第一个operator功能类似,但是唯一的不同在于,两者对于越界的处理不同!
5.back和front
cout << s.back() << endl;;//访问到最后一个字符 cout << s.front();//访问第一个字符
注意:它访问到的同时,还可以进行修改!
s.back() = 'A';//最后一个元素变为A s.front() = 'B';//第一个变为B cout << s.back() << ' '; cout << s.front();
三、string类对象的容量操作
1.size 和 length
string s1("hello string"); cout << s1.size() << endl; cout << s1.length() << endl;//返回字符串有效长度
size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。他们得到的结果并不一定等于capacity!
2.capacity
s1.capacity();//返回总空间的大小
3.empty
s1.empty();//检测字符串是否为空,为空就返回true,否则返回false
4.clear
s1.clear();//擦除字符串内容,使其变为空字符串,并不改变底层空间的大小
5.resize(调整当前字符串的大小)
会出现以下两种情况:
①如果n小于当前字符串的长度,那么他就会将当前长度缩短到n个字符的长度,并将第n个字符以外的其他部分全部删除!
②如果n大于当前字符的长度,那么就会将大小扩大到n,扩大的部分如果有字符c,那就拿字符C填充,没有就拿字符'\0'补充!
6.reserve(改变当前容量的大小)
规则如下:
- 如果n大于当前的容量,那么容量就会扩充到n甚至更大
- 如果n小于当前容量,那就什么都不做
- 这个函数不会影响字符串的长度,也不会改变其内容
7.shrink_to_fit(缩容)
规则:调整其capacity以适应它的size
四、string类对象的修改操作
1.operator+=(尾部追加)
如上图,有常见的三种重载形式,功能就是:通过在当前字符串的末尾附加额外字符来扩展字符串
string s("hello string"); s += " "; s += "!!!!!!"; cout << s << endl; string s2 = (" ggggg "); s += s2; cout << s << endl;
2.append(拼接)
这个函数的功能:也是上面的一样,追加,额……但是重载函数有很多,但是常用的就三种:
string& append(const string& str);
string& append(const char*s);
string& append(size_t n,char c);
string s("hello string"); s.append(" "); s.append("sjda"); s.append(10, 'A'); cout << s << endl;
3.push_back(尾插)
功能:将字符c追加到字符串的末尾,使其长度增加1。
s.push_back('A');
4.insert(插入)
额……还是有点多,其实常用的就一个:在pos位置前插入字符串
string& insert(size_t pos,const char *s);
int main() { string s("hello string"); s.insert(5, "hhhhhe");//在第五个位置前,插入字符串“hhhhhe” cout << s << endl; return 0; }
5.erase(删除)
规则:擦除字符串中从字符位置pos开始并跨越len字符的部分(如果内容太短或len为string::npos,则擦除直到字符串末尾)。
s.erase(0, 5);//删除从第0个位置开始的5个字符 cout << s << endl; //迭代器 s.erase(s.begin() + 1); cout << s << endl;//删除第二个位置的值 //删除区间的元素,区间为左闭右开[first,last) s.erase(s.begin() + 1, s.end() - 1); cout << s << endl;
6.replace(替换)
其实也有很多个,hh,大家想看完整的可以自己点进链接,下面两种是最常用的
- String& replace (size_t pos, size_t len, const char* s);
cout << s.size() << endl; s.replace(0, 4, "AAAAAAAAA");//从0位置开始的4个字符替换成特定字符串, //但是有一点需要注意,字符串的内容的长度可以任意,随之大小也会改变 cout << s << endl; cout << s.size() << endl;
- String& replace (size_t pos, size_t len, size_t n, char c);
cout << s.size() << endl; cout << s.capacity() << endl; s.replace(0, 4, 100, 'V');//从0位置开始的4个字符替换为100个字符‘V’ cout << s << endl; cout << s.size() << endl; cout << s.capacity() << endl;
编译器会按照自己特定的方式进行扩容,在LInux下又是另外的扩容方式!!
需要注意:
①上面的尾部追加字符s.append(1,c) / s.push_back(c) /s+='c'其实实现的差不多,但是实际应用中使用+=比较多,它不仅仅可以连接字符,还可以连接字符串
②实际上insert/erase/replace,但数据很大时,需要挪动大量的数据,效率太低,能少用就尽量少用!!!
③对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
7.swap(交换)
对于这个交换函数,其实在STL库里面有两个,一个是作为string类的成员函数,一个是全局的函数,谁都可以用的!
int main() { string s1("hello s1"); string s2("hello s2"); //用string里面的交换函数 s1.swap(s2); cout << s1 << endl; cout << s2 << endl; cout << endl; //全局的swap swap(s1, s2); cout << s1 << endl; cout << s2 << endl; return 0; }
五、string类的查找
1.find(左闭右开区间,正向查找)
功能:从字符串pos位置(不写默认是0)开始往后找字符c,返回的是第一个匹配的第一个字符的位置。
如果没有找到匹配项,函数返回string::npos(-1)。(npos是一个静态成员常量值,具有size_t类型元素的最大可能值。)注意:他们都是const成员函数,就是说可读不可写,仅仅只是查找,遍历访问操作它是可以改变值的,也就是可读可写!
int main() { string s("http://baidu.com/"); string s2("bai"); //find(string,pos)返回第一个匹配的位置,也就是b的位置 size_t pos1= s.find(s2); cout << pos1 << endl; //find(str,pos) size_t pos2 = s.find("com"); cout << pos2 << endl; //find(字符,pos) size_t pos3 = s.find('u'); cout << pos3 << endl; return 0; }
这里没有演示第三个重载函数,因为它其实和第二个重复了,直接用第二个就好了!
2.rfind(反向查找)
功能:从pos位置(默认是npos位置)开始向前查找字符串或者字符,找到就返回它的位置,这个位置是从前先后数的;如果没有找到就返回npos(换个方向理解就是:找到最后一次匹配的第一个字符的位置)
注意:这里的第三个重载函数其实和find的情况是一样的,重复了第二个,感觉有点多余(个人吐槽)
六、string类的截取
substr:左闭右开
功能:从pos位置开始,截取n个字符,返回的结果是一个新的字符串对象,这个新对象的内容就是使用截取到子字符串去初始化!
所以这个实际上可以和find去结合使用
七、string类与一些类型的转化
1.字符串转化为string
这个很简单,其实就是第一部分的常见构造的方式!!
string s1("hello string"); char str[] = "hello string"; string s2(str);
2.string转为字符串
这个可以使用string类中的c_str或者date
c_str: const char *c_str() const;
data: const char *data() const;
区别:在C++98中,C_str转化过来的,在末尾会加上"\0",但是data不会!在C++11中,两者都会加!
string s("https://cplusplus.com/reference/string/string/rfind/"); const char* str1 = s.c_str(); const char* str2 = s.data(); cout << str1 << endl; cout << str2 << endl;
3.内置类型转化为string
double d = 40.25; string s1 = to_string(d);
还可以是其他的内置类型哦!!!!!
4.string转化为内置类型
string s1("45.630"); double d = stod(s1);
八、非成员函数重载
1.operator<<和operator>>(输入输出运算符重载)
Istream& operator>> (Istream& is, string& str);输入运算符重载
Ostream& operator<< (Ostream& os, const string& str);输出运算符重载
string s; cin>>s; cout<<s<<endl;
因为有了这个重载函数,所以可以使用cin和cout输入输出string类!
2.relational operators (string)(大小比较)
这是string类的关系操作符,包括==,!=,<,<=,>,>=。重载的函数,支持string类和string类、string类和字符串之间的比较!
int main() { string s1("hello"); string s2("hikklkl"); //string 和string cout << (s1 == s2) << endl; cout << (s1 != s2) << endl; cout << (s1 < s2) << endl; cout << (s1 <= s2) << endl; cout << (s1 > s2) << endl; cout << (s1 >= s2) << endl; cout << endl; //string和字符串 const char* s3 = "hella"; cout << (s1 == s3) << endl; cout << (s1 != s3) << endl; cout << (s1 < s3) << endl; cout << (s1 <= s3) << endl; cout << (s1 > s3) << endl; cout << (s1 >= s3) << endl; return 0; }
十分的爽!
3.getline(获取一行字符串)
这个函数的存在,其实就是因为cin和scanf的一点小缺陷,看代码
发现了什么,明明输入的A B,可是出来的却是A,其实就是因为cin和scanf在遇到空格时就会停止读取后面的字符,而后面的字符实际上放在缓冲区里!在读取一次看看
此时,A B才能完全输出!有了getline就很方便!
这个函数也是有两个用法的:
①如果有界定符,那就读取到界定符为止,后面的字符直接丢弃!
string s; getline(cin, s,'r');//读到分隔符‘r’为止 cout << s << endl;
②如果没有,那就是默认到‘\0’
好了,感谢大家的阅读!这部分内容有点小多,大家如果想要查看原文档可以点击string文档!
其实实际上用到不多!!题中见分晓!