前⾯介绍了通过字符数组保存字符串,然后对字符数组中的字符串做各种操作为了更加方便,使字符串的操作更加简便并且强大,在C++中,又增加了 string 来处理字符串。
文章目录
一、string的概念
string 字符串其实是⼀种更加高级的封装, 符串的操作变得更加简单。 string 字符串中包含大量的方法,这些方法使得字 string 使用的好,慢慢你就不想使用字符数组来存放字符串了。
那到底什么是string呢?
而C++中将字符串直接作为⼀种类型,也就是 string 类型,使用 C++的字符串。 string 类型创建的对象就是C++的字符串。
string s1; //空字符串
string s2 = "abc";
使⽤C++中提供的 string 时,必须添加头文件<string>
二、string的常见操作
我们想要具体了解的话,可以打开string - C++ 参考https://legacy.cplusplus.com/reference/string/string/
1.创建字符串
string s1; //创建空字符串
string s2 = "hello world"; //创建字符串(常用)
代码展示:
#include <iostream>
#include <string>//添加string头⽂件
using namespace std;
int main()
{
string s1;
string s2 = "hello world";
cout << "s1:" << s1 << endl;
cout << "s2:" << s2 << endl;
return 0;
}
运行结果:
string s1 表示创建空字符串,相当于创建整型 int a ,但未给 a ⼀个初始值。
string s2 = "hello world" 表⽰创建⼀个字符串s2,它的内容是" hello world ",要注意 s2 中的字符串不再以 \0 作为结束标志了。(C语言中的字符串是以 \0 作为结束标志的)。
简单的示意图是这样的:
值得注意的是:
上面这个图,仅仅是字符串s2的示意图,实际上 string 类型的字符串比这个要复杂的多, 更多的知识得学习C++的类和对象的知识才能明白。
当然C++中string创建的字符串和char类型数组所表示的字符串还有一个区别,string类型的字符串对象可以直接复制,比如:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1("hello world");
string s2("hehe");
s2 = s1;
cout << s2 << endl;
return 0;
}
运行结果如下:
2.string字符串的输入
1.cin的输入方式
可以直接用cin给string类型的字符串输入一个字符串类型的数据。
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;//输⼊
cin >> s;//输出
cout << s << endl;
return 0;
}
输入不带空格的字符串:
输入带空格的字符串:
这里我们可以发现,其实 cin 的方式给 string 类型的字符串中输入数据的时候,可以输入不带空格的字符串。但是如果带有空格,遇到空格也就读取结束了,没有办法正常读取,那怎么办呢?解决 办法就是使用getline 。
2.getline 的方式
getline 是C++标准库中的⼀个函数,用于从输入流中读取一行文本,并将其存储为字符串。 getline 函数有两种不同的形式,分别对应着字符串的结束方式。
1. istream& getline (istream& is, string& str);
2. istream& getline (istream& is, string& str, char delim);
注意:getline 函数是输入流中读取一行文本信息,所有如果是在标准输入流(键盘)中读取数据,就可以传 cin 给第⼀个参数。
• 第⼀种 getline 函数以换行符( '\n' )作为字符串的结束标志,它的⼀般格式是:
getline(cin, string str)
//cin -- 表⽰从输⼊流中读取信息
//str -- 是存放读取到的信息的字符串
这种形式的getline函数输入流中读取文本,直到换行符(‘/n’)为止,然后读取到文本(不包括换行符)存储到指定string类型的变量str中。
代码如下:
#include<iostream>
#include <string>
using namespace std;
int main()
{
string name;
getline(cin, name);
cout << name << endl;
return 0;
}
运行结果如下:
• 第⼆种 getline 函数允许用户自定义结束标志,它的⼀般格式是:
getline(cin, string str, char delim)
//cin -- 表⽰从输⼊流中读取信息
//str -- 是存放读取到的信息的字符串
//delim -- 是⾃定义的结束标志
这种形式的getline函数从输入流中读取文本,直到读到用户定义的指定字符(delim)结束,然后将读取到的文本(不包括结束标志字符)存储到指定的string类型的变量str中。
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str;
getline(cin, str, 'q');
cout << str << endl;
return 0;
}
运行结果如下:
我们可以发现,计算机在读取数据的时候,读到我们自定义的字符时,计算机会自动结束,并且不会读入我们定义的字符。
3.size()
string 中提供了 size() 函数用于获取字符串长度。
在C++中关于字符串的操作函数都是包含在string中的,所以调用和这些函数时,通常用 . 点运算符。
使用代码展示:
#include <iostream>
#include <string> //添加string头⽂件
using namespace std;
int main()
{
string s;
string s1 = "hello";
string s2 = "hello world";
string s3 = "12ab!~ ";
cout << "s:" << s.size() << endl;
cout << "s1:" << s1.size() << endl;
cout << "s2:" << s2.size() << endl;
cout << "s3:" << s3.size() << endl;
return 0;
}
运行截图如下:
✅小提示: 前面我们学到的像,char 、 int 、 double 等内置类型的数据在操作的时候,不会使用 . 操作符的。
string 是C++提供的⼀种更加复杂的封装类型,在 string 类型的变量中加⼊了操作这 个字符串的各种方法(函数),比如求字符串长度、字符串末尾插⼊⼀个字符等操作。所以要对 string 类型的变量进行各种操作,就可以使用 . 操作符来使用这些函数。 我们可以看下面的例子,大家要仔细体会。
通过 size() 能获得字符串的长度,顺便就可以使用这个长度遍历字符串的,注意 string 类型的字符串是可以通过下标访问的,比如:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdef";
int i = 0;
for (i = 0; i < s.size(); i++)
{
cout << s[i] << " ";
}
return 0;
}
4.迭代器(iterator)
迭代器是⼀种对象,它可以用来遍历容器(比如我们现在学习的 string )中的元素,迭代器的作用类似于指针,或者数组下标。
这里要注意:访问迭代器指向的值,需要解引用(*)。
C++中的 string 提供了多种迭代器,用于遍历和操作字符串中的内容。这里给大家介绍⼀种最常 用的迭代器。
1.begin( )和end( )
- begin() :返回指向字符串第⼀个字符的迭代器,需要⼀个迭代器的变量来接收。
- end():返回指向字符串最后⼀个字符的下⼀个位置的迭代器(该位置不属于字符串)。
- string中begin()和end()返回的迭代器的类型是 string :: iterator 。
string s = "abcdef";
小提示:
- 迭代器是可以进行大小比较,也可以进行 + 或者 - 整数运算的。 比如: it++ ,就是让迭代器前进⼀步, it-- 就是让迭代器退后⼀步。
- 同⼀个容器的两个迭代器也可以相减,相减结果的绝对值,是两个迭代器中间元素的个数。
代码演示如下:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "abcdef";
string::iterator it1 = s.begin();
string::iterator it2 = s.end();
cout << (it1 < it2) << endl;
cout << it1 - it2 << endl;
return 0;
}
运行结果如下:
我们可以发现,begin()对应的下标确实比end()对应的下标小,所以结果显示1为真。
正序遍历
迭代器通常用于遍历字符串的,可以正序遍历,也可以逆序遍历。
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdef";
for (string::iterator it = s.begin();it != s.end();it++) {
cout << *it << ' ';
}
return 0;
}
运行结果如下:
当我们不知道It的返回类型的时候用auto运行起来也是一样的。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdef";
/*for (string::iterator it = s.begin();it != s.end();it++) {
cout << *it << ' ';
}*/
for (auto it = s.begin();it != s.end();it++) {
cout << *it << ' ';
}
return 0;
}
逆序遍历
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdef";
for (string::iterator it = s.end() - 1; it >= s.begin(); --it)
{
cout << *it << ' ';
}
return 0;
}
运行结果如下:
这里要注意一点:通过迭代器找到元素后,改变迭代器指向的元素,是可以直接改变字符串内容的。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "abcdef";
cout << str << endl;
for (string::iterator it = str.begin(); it != str.end(); ++it)
{
*it = 'x';
}
cout << str << endl;
return 0;
}
运行结果如下:
5.push_back()
push_back() 用于在字符串尾部插⼀个字符。
例如:
代码演示:
#include <iostream>
#include<string> //添加string头⽂件
using namespace std;
int main()
{
//向空字符串中尾插字符
string s;
s.push_back('h');
s.push_back('e');
s.push_back('l');
s.push_back('l');
s.push_back('o');
cout << s << endl;
//向非空字符串中尾插字符
string s1 = "hello ";
s1.push_back('w');
s1.push_back('o');
s1.push_back('r');
s1.push_back('l');
s1.push_back('d');
cout << s1 << endl;
////批量插⼊字符
string s2;
for (char c = 'a'; c <= 'f'; c++)
{
s2.push_back(c);
}
cout << s2 << endl;
return 0;
}
运行结果如下:
6.pop_back()
pop_back() 用于删除字符串中尾部的⼀个字符。这个成员函数是在 C++11 标准中引用的,部分编译器可能不支持。
pop_back() 的作用是用于删除字符串最后一个字符。
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "hello";
cout << "s:" << s << endl;
//尾删
s.pop_back();
cout << "s:" << s << endl;
//尾删
s.pop_back();
cout << "s:" << s << endl;
return 0;
}
运行结果如下:
值得注意的是:当字符串中没有存储字符即为空字符串时,使用 pop_back() 可能会报错,会出现程序崩溃的问题。
如何解决这个问题呢?
来看接下来这段代码:
#include <iostream>
#include<string> //添加头文件<string>
using namespace std;
int main()
{
string s = "abc";
{
while (s.size() > 0) //通过size()函数来控制字符串的⻓度
{
s.pop_back();
}
return 0;
}
我们调用s.size()函数来解决空字符问题,防止报错。
7.insert
如果我们需要在字符串中间的某个位置插入一个字符串,怎么办呢?这时候我们得掌握⼀个函数就是 insert
函数原型如下:
1.string& insert (size_t pos, const string& str); //pos位置前⾯插⼊⼀个string字符串
2.string& insert (size_t pos, const char* s); //pos位置前⾯插⼊⼀个C⻛格的字符串
3.string& insert (size_t pos, size_t n, char c);//pos位置前⾯插⼊n个字符c
代码演示如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdefghi";
string str = "xxx";
cout << s << endl;
s.insert(3, str);
cout << s << endl;
return 0;
}
运行结果如下:
代码还可以这样写:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdefghi";
cout << s << endl;
s.insert(3, "xxx");
cout << s << endl;
return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "abcdefghi";
cout << s << endl;
s.insert(3, 3, 'x');
cout << s << endl;
return 0;
}
前一个3代表的是下标的位置,第二个3代表的是插入几个‘x’字符。
8.find()
find() 函数用于查找字符串中指定子串/字符,并返回子串/字符在字符串中第⼀次出现的位置。
例如要找一个字符串 'lo' ,在字符串 'hello world hello C++' 中第一个 'lo'出现的位置是下标为2的位置,所以返回值就是2。
1.size_t find (const string& str, size_t pos = 0) const;
//查找string类型的字符串str,默认是从头开始查找,pos可以指定位置开始
2.size_t find (const char* s, size_t pos = 0) const;
//查找C⻛格的字符串s,默认是从头开始查找,pos可以指定位置开始
3.size_t find (const char* s, size_t pos, size_t n) const;
//在字符串的pos这个位置开始查找C⻛格的字符串s中的前n个字符
4.size_t find (char c, size_t pos = 0) const;
//查找字符c,默认是从头开始,pos可以指定位置开始
返回值:
- 若找到,返回子串/字符在字符串中第⼀次出现的起始下标位置。
- 若未找到。返回⼀个整数值 的返回值是否等于 npos 。通常判断 find()函数返回值是否等于 npos 就能知道是否查找到子串或者字符。
代码如下:
#include <iostream>
#include <string>
using namespace std;
//添加string头⽂件
int main()
{
string s = "hello world hello everyone";
string str = "llo";
//查找string类型的字符串
size_t n = s.find(str);
cout << n << endl;
n = s.find(str, n + 1); //从n + 1这个指定位置开始查找
cout << n << endl;
//查找C⻛格的字符串
n = s.find("llo");
cout << n << endl;
n = s.find("llo", n + 1); //从n + 1这个指定位置开始查找
cout << n << endl;
return 0;
}
运行结果如下:
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "hello world hello everyone";
size_t n = s.find("word", 0, 3); //在s中,0这个指定位置开始查找"word"中的前3个字符
cout << n << endl;
n = s.find("everyday", n + 1, 5);
cout << n << endl;
return 0;
}
运行结果如下:
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "hello world hello everyone";
size_t n = s.find('o');
cout << n << endl;
n = s.find('o', n + 1);
cout << n << endl;
return 0;
}
运行结果如下:
当然也有找不到的情况:
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "hello world hello everyone";
string str = "bit";
size_t n = s.find(str);
cout << n << endl;
if (n != string::npos)
cout << "找到了,位置是:" << n << endl;
else
cout << "没有找到" << endl;
return 0;
}
运行结果如下:
我们发现有一个很大的数值,这个就是nops默认的值。
9.substr()
substr() 函数用于截取字符串中指定位置指定长度的子串。函数原型如下:
1.string substr (size_t pos = 0, size_t len = npos) const;
2.//pos 的默认值是0,也就是从下标为0的位置开始截取
3.//len 的默认值是npos,意思是⼀直截取到字符串的末尾
substr() :如果函数不传参数,就是从下标为0的位置开始截取,直到结尾,得到的是整个字符串;
substr(pos) :从指定下标 pos 位置开始截取子串,直到结尾;
substr(pos, len) :从指定下标 pos 位置开始截取⻓度为 len 的子串。
如图所示
返回值类型: string ,返回的是截取到的字符串,可以使用 string 类型的字符串接收。
代码如下:
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s = "hello world hello everyone";
string s1 = s.substr(7);
cout << s1 << endl;
string s2 = s.substr(7, 6);
cout << s2 << endl;
return 0;
}
运行结果如下:
注意,substr()函数经常和find()函数配合使用,find()负责找到具体位置,substr()负责从这个位置向后获得字符串。
代码如下:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "hello world hello everyone";
size_t n = s.find("world");
string s2 = s.substr(n, 10);
cout << s2 << endl;
return 0;
}
运行结果如下:
10.和string相关的函数
1.stoi/stol
stoi是将字符串转成int类型的值
stol是将字符串转long int类型的值
这两个函数非常类型,这里以 stoi 为例讲解⼀下这⾥函数的使用方式。
stoi 函数其实可以将⼀个 string 类型的字符串,转化为整型,函数原型如下:
1. int stoi (const string& str, size_t* idx = 0, int base = 10);
2. long stol (const string& str, size_t* idx = 0, int base = 10);
参数的解读:
- str 表示被转换的 string 类型的字符
- idx 是⼀个输出型参数,也就是这个通过这个参数会带回⼀个值。idx 是⼀个指针,需要在外边创建⼀个 size_t 类型的值,传递它的地址给 idx ,这个参数将会带回 str 中无法正确匹配数字的第⼀个字符的位置。
- base 表示被解析的字符串中数字的进制值,可能是2,8,10,16或者0.
默认情况下这个值是 10 ,表示 10 进制数字
如果传递的是 2 ,表示被解析的字符串中是 2 进制的数字,最终会转换成 10 进制
如果传递的是 8 ,表示被解析的字符串中是 8 进制的数字,最终会转换成 10 进制
如果传递的是 16 ,表示被解析的字符串中是 16 进制的数字,最终会转换成 10 进制
如果传递的是 0 ,会根据字符串的内容的信息自动推导进制,比如:字符串中有0x,就认为是 16 进制,, 0 开头会被认为是 8 进制,最终会转换成 10 进制。
代码演示:
#include <iostream>
#include<string>
using namespace std;
int main()
{
size_t pos = 0;
string s1 = "11x34";
int ret1 = stoi(s1, &pos, 16);
cout << ret1 << endl;
cout << "pos:" << pos << endl;
string s2 = "11x34";
int ret2 = stoi(s2, &pos, 2);
cout << ret2 << endl;
cout << "pos:" << pos << endl;
string s3 = "0x11x34";
int ret3 = stoi(s3, &pos, 0);
cout << ret3 << endl;
cout << "pos:" << pos << endl;
return 0;
}
运行结果:
2.stod/stof
stod 是将字符串转换成 double 类型的值,函数原型如下,和 stoi 函数的比较的话,少了描述字符串中数字进制的参数,其他参数⼀致。stof 是将字符串转换成 flaot 类型的值。
函数原型如下:
1 double stod (const string& str, size_t* idx = 0);
2 float stof (const string& str, size_t* idx = 0);
代码如下:
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s = "3.14x456";
double ret = stod(s, NULL);
cout << ret << endl;
return 0;
}
运行结果如下:
11.string的+=和+运算
前面讲的push_back() 是用于在字符串后添加⼀个字符,然而部分情况下我们需要向原有的字符串后继续添加字符串。
其实 string 类型的字符串是支持 + 和 += 运算的。这里的本质是 string 中重载了operator+= 这个操作符。
例如:hello 后面要添加 world 这个单词。
我们用具体的代码实现一下:
代码如下:
运行结果如下:
总结
感谢各位的观看与借鉴,这是总结的关于string常用的一些功能,学会这些功能,对字符串的理解就更深了,祝愿我们共同进步。
这里文章就讲完啦,记得点赞 + 关注哦 ❤。