文章目录
前言
- 🚄 输入是学习的本质,输出是学习的手段。
- 🔖 分享每一次的学习,期待你我都有收获。
- 🎇 欢迎🔎关注👍点赞⭐️收藏✉评论,共同进步!
- 🌊 “要足够优秀,才能接住上天给的惊喜和机会”
- 💬 博主水平有限,如若有误,望斧正,万分感谢!
☁️string类
旨在理解掌握string类的常见使用
为了方便后面string类的学习,先要了解一下string::npos,
npos是string类里的一个静态成员函数,在string类成员函数中经常作为缺省参数出现
这是npos的定义。其中size_t说明npos是一个无符号整型,因此,这里npos = -1,
npos的实际值是整型最大值,即42亿+。
☁️string类构造函数
string()
string(const char* a)
string(size_t n,char c) //初始化为n个字符c.
string(const string& a)
void Test1()
{
string s1;
cout << s1 << endl;
string s2("hello world");
cout << s2 << endl;
string s3(s2);
cout << s3 << endl;
string s4(10, 'x'); //初始化为10个字符x
cout << s4 << endl;
}
☁️String类的容量操作
size() //返回有效数据的个数(个数不包含\0)
capacity() //返回当前容量
clear() //清空有效字符,但容量不一定会清空
resize(size_t n,char c)
//从0开始,只给n个位置数据,多删少补。
//(多删:可能原本对象中的有效数据个数 >n ,则只留前n个数据,size修改为n,不会改变容量大小)
//(少补:补字符c,不传字符参数,默认补\0,size修改为n,容量不够时,会扩容)
//也就意味着会影响size,也会影响capacity(容量不够的时候)
//但是如果原来位置有值且在n范围内,不会覆盖原来位置的值。
reserve(size_t n = 0) //扩容,为对象预留空间,size不变。当 n< 当前对象空间,不会改变容量大小。
☁️String类对象的访问和遍历
☁️operator[ ]
operator[]
//[]重载,数组怎么用,这个就这么用
☁️迭代器
原理类似指针,这里只讲用法,模拟实现后面单独写
- 正向迭代器
string::iterator t = s1.begin(); //t变量名可随意取
string::const_iterator t = s1.begin(); //const修饰的对象要用这个const修饰的迭代器
begin() //获取string类对象第一个字符的位置
end() //获取string类对象最后一个位置的 下一个位置
注意:这里我们利用 begin和end ,得到的是一个左闭右开的区间
样例1:
int main()
{
string s1("hello world");
string::iterator t = s1.begin();
while (t != s1.end()) //注:这里写作 t < s1.end(),结果也一样,但是不规范。务必一定用!=
{
cout << *t;
// *t = 'P'; //正确,不是const修饰的迭代器,所以可读可写。
t++;
}
cout << endl;
return 0;
}
样例2:
int main()
{
string s1("hello world");
string::const_iterator t = s1.begin();
while (t != s1.end()) //注:这里写作 t < s1.end(),结果也一样,这是因为它是一块连续的空间,如果遇到像list等等不连续的空间,还是得用!=,为了统一写法,最好用!=
{
cout << *t;
// *t = 'P'; //错误,const修饰的迭代器,只读,不具有写的权限
t++;
}
cout << endl;
return 0;
}
- 反向迭代器
string::reverse_reiterator po = s1.begin(); //po变量名可随意取
string::const_reverse_iterator po = s1.begin(); //const修饰的对象要用这个const修饰的迭代器
rbegin() //获取string类对象第一个字符的位置
rend() //获取string类对象最后一个位置的 下一个位置
注意和正向迭代器区分
样例:
int main()
{
string s1("hello world");
string::reverse_iterator t = s1.rbegin();
while (t != s1.rend())
{
cout << *t;
t++;
}
cout << endl;
return 0;
}
最后再用一张图帮助理解一下迭代器
☁️范围for
要讲清楚范围for,要先理解auto类型
对于auto类型,编译器会自动根据右操作数,推导出auto定义的对象的类型。
void Test5()
{
string s1 = "hello world";
for (auto t : s1)
{
cout << t;
}
cout << endl;
}
这段代码的意思是,将s1的值一个一个取出赋给t,然后打印t。
此时改变t的值,不会改变s1的值,如果要改变s1的值,需加引用。
范围for最终会被编译器替换成迭代器形式,
所以也可以认为其底层实现是依靠迭代器的。
☁️string类对象的修改操作
push_bach(char c) //对对象尾插字符c
append(const string& str) //追加字符串str ,还有其他多种追加方式,详见官网标准库
operator+= //追加字符或字符串 ,最常用的追加方式,一目了然
☁️c_str
c_str //返回c格式字符串
直接说可能体会不到这个意思,我们看一段代码
void Test6()
{
string s1 = "hello world";
s1.resize(20);
s1 += "!!!";
cout << s1 << endl << endl;
cout << s1.c_str() << endl;
}
先是用resize修改了string类对象的size。前面说过,resize多删少补,默认补"\0"
正常string类的遍历是按照size的个数来进行的,也就是size是多少就会访问多少个字符,
**就算是遇到了\0,也不会停止访问,**只是我们看不到它输出\0,所以可能会以为它是遇到\0就停下。
以范围for遍历string对象来印证这一观点
void Test6()
{
string s1 = "hello world";
size_t count = 0; //计数,既然看不到输出\0,观察计数就好
cout << "resize 前:" << endl;
cout << "s1.size = " << s1.size() << endl;
for (auto t : s1) //遍历
{
cout << t;
count++;
}
cout << endl << "count = " << count << endl;
cout << endl << "resize 后:" << endl;
count = 0; //重置为0
s1.resize(20);
cout << "s1.size = " << s1.size() << endl;
for (auto t : s1)
{
cout << t;
count++;
}
cout << endl << "count = " << count << endl;
}
由此可以确定,string类对象的遍历:
其依据是size的大小,即使是遇到了\0,也不会停下。
因为当还没访问完size个数的数据时,它不知道 \0 后面是否还存在有效数据,
如果自己直接停下,会不会导致有效数据没有访问到,所以它不会停下。
但是c语言中,访问字符串遇到\0就会停下
至此,大家大概就能明白 c_str() 的作用了吧。
void Test7()
{
string s1 = "hello world";
cout << s1 << endl;
cout << s1.c_str() << endl;
s1.resize(20);
s1 += "!!!";
cout << s1 << endl;
cout << s1[11] << " " << s1[12] << endl;
cout << s1.c_str() << endl; //返回c语言格式字符串
}
☁️find
size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
从pos位置开始,往后寻找字符或字符串,并返回位置,如果没找到,返回npos
☁️rfind
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
从pos位置开始,往后寻找字符或字符串,并返回位置,如果没找到,返回npos。
pos给的缺省值是npos,如果pos大于字符串长度或者等于npos,都是从字符串最后一个字符开始往前找。
☁️substr
string substr (size_t pos = 0, size_t len = npos) const;
从pos位置开始,截取len个字符,并返回。
☁️getline
用string定义字符串,
如果输入字符串用 cin>> ,它和scanf有一样的问题:
会把空格或回车当做是两个字符串之间的分隔。
所以要用getline输入字符串。
int main()
{
string s;
//cin>>s;
getline(cin,s);
cout<<s<<endl;
}