个人主页: :✨✨✨初阶牛✨✨✨
推荐专栏1: C语言初阶
推荐专栏2: C语言进阶
个人信条: 知行合一
本篇简介:>:讲解C++中有关string类的使用,从构造函数到容量操作,到遍历以及增删查改和最后的运算符重载.
string
库的学习:传送门
在库中我们可以看到,string
类的构造函数是很丰富的.
重点掌握牛牛框起来的四个哦,其他的忘记了咱可以查文档.
构造函数使用演示:
void test1()
{
//无参构造 string();
string s1;
cout << "s1= " << s1 << endl;
//拷贝构造, string (const string& str);
s1 += "HELLO CSDN!!!";//下面讲,这里是为了s1里面有数据,方便拷贝构造
string s2(s1);
cout << "s2= " << s2 << endl;
//用另一个string类的字串初始化 string (const string& str, size_t pos, size_t len = npos);
string s3(s1, 6,4);
cout << "s3= " << s3 << endl;
//使用字符串进行初始化 string (const char* s);
string s4("CJN Rush Rush Rush");
cout << "s4= " << s4 << endl;
//string(const char* s, size_t n);
string s5("CJN Rush Rush Rush",7);//不常用
cout << "s5= " << s5 << endl;
//string(size_t n, char c);
string s6(5, 'X');//不常用
cout << "s6= " << s6 << endl;
}
运行结果:
s1=
s2= HELLO CSDN!!!
s3= CSDN
s4= CJN Rush Rush Rush
s5= CJN Rus
s6= XXXXX
capacity
)相关的操作其实size()
和length()
并没有本质区别.
都是用于返回string
中字符串的有效字符长度.
但是,由于string实现的比较早,当时设计的是length()
,后来STL出来以后,为了统一,增加了size()
接口.
string s1;
string s2("hello");
//size和length并没有什么区别.
cout << s1.size() << " " << s1.length() << endl;
cout << s2.size() << " " << s2.length() << endl;
0 0
5 5
resize()
用于改变字符串的有效字符长度.不够的地方用第二个参数填充.
string s3("HELLO CSDN!!!");
s3.resize(5); //将字符串的有效字符长度改为5
cout << s3 << endl;
string s4("HELLO CSDN!!!");
s4.resize(25,'x'); //将字符串的有效字符长度改为25,不够的地方用字符'x'填充
cout << s4 << endl;
运行结果:
HELLO
HELLO CSDN!!!xxxxxxxxxxxx
resize()
的改变会影响capacity
(容量)吗?
string s5("HELLO CSDN!!!");
cout << "s5.capacity=" << s5.capacity() << endl;
s5.resize(25, 'x');
cout << "s5.capacity=" << s5.capacity() << endl;
s5.resize(5, 'x');
cout << "s5.capacity=" << s5.capacity() << endl;//并没有缩容
运行结果:
s5.capacity=15
s5.capacity=31
s5.capacity=31
当然,如果容量太小,不足以存储有效字符,必然是会扩容的!
扩容选择:(扩容方式是未定义的)
扩容是按有效字符长度扩容.
按之前容量的1.5倍扩容,更或者是2倍扩容.
reserve()
:请求改变容量的大小.
string s6("HELLO CSDN!!!");
cout << "s6.capacity=" << s6.capacity() << endl;
s6.reserve(50);
cout << "s6.capacity=" << s6.capacity() << endl;
s6.reserve(30);
cout << "s6.capacity=" << s6.capacity() << endl;//并没有缩容
//一般都是不缩容的,缩容行为是未定义的.
s6.clear();
s6.reserve(0);
cout << "s6.capacity=" << s6.capacity() << endl;//这里缩容了
s6.capacity=15
s6.capacity=63
s6.capacity=63
s6.capacity=15
是否缩容是未定义行为,取决于编译器,这里如果不清楚数据,直接将reserve(0)
,依旧不会缩容.
string s7;
cout << s7.empty() << endl;
s7 += "HELLO";
cout << s7.empty() << endl;
cout << "s7.size=" << s7.size() << endl;
cout << "s7.capacity" << s7.capacity() << endl;
s7.clear();
cout << "s7.size=" << s7.size() << endl;
cout << "s7.capacity" << s7.capacity() << endl;
运行结果:
1
0
s7.size=5
s7.capacity15
s7.size=0
s7.capacity15
显然clear
只是清除有效字符,将字符清零,并不会影响capacity
容量.
(4)小结:
size()
和length()
底层实现原理是一样的,都是返回有效的字符个数.只是为了STL
的接口相统一.
resize(size_t n)
与 resize(size_t n, char c)
都是将字符串中有效字符个数改变到n
个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)
用字符c
来填充多出的元素空间。
注意:resize
在改变元素个数时.
(1)如果是将元素个数增多,可能会改变底层容量的大小,不然存储不了那么多有效字符.
(2)如果是将元素个数减少,底层空间总大小不变。
reserve((size_t res_arg=0)
)函数是请求改变string的容量.
(1)当res_arg
大于当前的容量的时候,会进行扩容.
(1)当res_arg
小于当前的容量的时候,一般不会缩容.
clear
只是清除有效字符,将字符清零,并不会影响capacity
容量.
正向迭代器与反向迭代器:(这里对C++11的用法暂时不介绍)
void test3()
{
string s1("This is a little boy");
string::iterator it = s1.begin(); //s1.begin()会返回有效字符串中第个元素的位置
while (it != s1.end()) //s1.end()会返回有效字符串最后一个元素的位置的后一个位置
{
cout << *it ;
it++;
}
cout << endl;
string::reverse_iterator rit = s1.rbegin();//反向迭代器
while (rit != s1.rend()) //s1.end()会返回有效字符串最后一个元素的位置的后一个位置
{
cout << *rit;
rit++;
}
cout << endl;
cout << "s1.begin=" << *(s1.begin()) << endl;
cout << "s1.end=" << *(s1.end()-1) << endl; //不可直接访问s1.end(),因为不是有效字符,而是最后一个有效字符的下一个位置.
cout << "s1.rbegin=" << *(s1.rbegin()) << endl;
cout << "s1.rend=" << *(s1.rend()-1) << endl; //这里为什么是+1而不是-1,留在后面的专门反向迭代器讲解
//可以像数组一样用下标直接访问
cout << s1[0] << endl;
cout << s1[3] << endl;
cout << s1[8] << endl;
}
void test4()
{
string s1("hello C");
cout << "s1=" << s1 << endl;
//尾插一个字符
s1.push_back('S');
s1.push_back('D');
s1.push_back('N');
cout << "s1=" << s1 << endl;
cout << "----------------------------------" << endl;
string s2("hello C");
cout << "s2=" << s2 << endl;
s2.append("SDN"); //追加字符串
cout << "s2=" << s2 << endl;
cout << "----------------------------------" << endl;
string s3("hello C");
cout << "s3=" << s3 << endl;
s3 += "SDN"; //最喜欢使用这个,易读也简单
cout << "s3=" << s3 << endl;
}
个人感想:
push_back
一次插入一个字符太麻烦了,append
虽然可以追加字符串,但是终究是没有+=
来的香.
其它的以assign
为例,一般用不到(因为实现的有些冗余,可以用别的函数代替),实在要用查库即可:
void test5()
{
string str("This is a little boy");
string s1,s2,s3;
s1.assign(str);
s2.assign(str, 8, string::npos);
s3.assign(5, 'c');
cout << "s1=" << s1 << endl;
cout << "s2=" << s2 << endl;
cout << "s3=" << s3 << endl;
}
运行结果:
s1=This is a little boy
s2=a little boy
s3=ccccc
find
)/切割(substr
)c_str
:为了与C
语言兼容,返回C
形式的常量字符串.
find
:可以查找目标字符/字符串.
string substr (size_t pos = 0, size_t len = npos) const
:从pos
往后len
个字符,返回这段被切割的字符串的副本.
void test6()
{
string s1("This is a little boy");
const char* arr = s1.c_str(); //返回C形式的常量字符串
cout << "arr=" << arr << endl;
string s2("This is a little boy");
cout << s2.find('i') << endl; //查找目标字符
cout << s2.find("little") << endl; //查找目标字符串
string s3("[email protected]");
int pos1 = s3.find('@');
int pos2 = s3.find(".com");
string s4, s5, s6;
s4 = s3.substr(0, pos1-1); //从0位置开始,往后pos-1个字符
s5 = s3.substr(pos1, s3.size() - pos2 - 1);
s6 = s3.substr(pos2); //第二个参数为往后的字符个数,不写,默认为npos
cout << "s4= " << s4 << endl;
cout << "s5= " << s5 << endl;
cout << "s6= " << s6 << endl;
}
运行结果:
arr=This is a little boy
2
10
s4= 321xxxxxx
s5= @qq
s6= .com
小知识点:
npos是-1,只不过类型是const size_t
,所以是整数的最大值,通常表示字符串的结尾或无效位置。npos
定义在std
命名空间中,通常用于字符串的查找操作。
+
运算符重载与getline()
void test7()
{
string s1("HELLO ");
string s2("CSDN");
string s3;
s3 = s1 + s2; //因为是传值返回,所以效率不高,建议少用
cout << s3 << endl;
string name;
cout << "Please, enter your full name: ";
getline(cin, name);
cout << "Hello, " << name << "!\n";
}
比较运算符这里就不一 一介绍了,字符串按ASCII
码值进行比较.
string
类的使用还是需要多多练习,可以试着写一下相关的oj
题练一下手,后续会模拟实现string
类,加深对string
类的理解.
string相关习题1