文章目录
前言
这个栏目是对我算法学习过程的同步记录,我也希望能够通过这个专栏加深自己对编程的理解以及帮助到更多像我一样想从零学习算法并参加竞赛的同学。在这个专栏的文章中我会结合在编程过程中遇到的各种问题并提出相应的解决方案。当然,如果屏幕前的你有更好的想法或者发现的错误也欢迎交流和指出!不喜勿喷!不喜勿喷!不喜勿喷!那么事不宜迟,我们马上开始吧!
一、我们为什么要使用string类型?
我们已经知道,用char a[5];的数组表示方法可以表示字符串,那我们为什么还要使用string类型来表示字符串呢?原因就在于string类型可以说是为处理字符串应运而生的C++标准库重要成员。不同于char[]类型的揭示本质作用,string类型实现了高度的封装,可以更加方便地实现各种字符串的操作,如拼接、截取和匹配等。使用string类型,能极大节省我们的时间和精力。
二、string的声明和初始化
1.string类型存放在哪?
我们可以写下面一段有问题的代码,并且在Visual Studio 2022中编译一下,看看编译器的报错信息,也许里面就有意想不到的惊喜。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
int main()
{
int a;
string s;
return 0;
}
底下的输出栏目中会报错:error C2065: “string”: 未声明的标识符 但是int a;这一句却并没有报错,那么我们不妨再修改一下。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a;
string s;
scanf("%d", s);
return 0;
}
底下的输出栏目会报错: warning C4477: “scanf”: 格式字符串“%d”需要类型“int *”的参数,但可变参数 1 拥有了类型“std::string” 问题又来了:string类型和我们写的using namespace std之间有什么关系呢? 原来C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。而string类型又是C++标准库的重要成员,那么一切就解释的通了。namespace指的是标识符的各种可见范围。实际上不写这一句也行,但是我们在接下来的语句中必须以如下格式书写:
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
int main()
{
int a;
std::string s = "hello";
std::cout << s << std::endl;
return 0;
}
这样的话就不会报错了。
当然你也可以使用自己的namespace,但是这会极大降低代码的可移植性,感兴趣的朋友可以自行了解,这里省去十万八千字。
2.具体操作实例
下面我们通过一段代码来了解吧!
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str1;//声明并初始化一个字符串
cout << str1 << endl;// ""
string str2 = "hello world";//直接赋值来初始化字符串
string str3 = str2;//通过另一个std::string对象来赋值并初始化
//使用部分字符串初始化字符串
string str4 = str2.substr(0, 7);//0是起始位置,5是长度,结果是hello w
//使用字符数组初始化字符串
const char* a = "hello";//这里不加const的话会报错
string str5(a);
//使用重复字符初始化字符串
string str6(3, 'B'); //BBB
return 0;
}
三、string类型的基本操作
1.string类型的输出
我们可以试试,若将string类型直接放在printf函数中输出,会出现如下的报错信息:
E0413 不存在从 "std::string" 到 "const char *" 的适当转换函数
这就需要我们使用std::string类的成员函数c_str()将string类型转换为const char*类型。通过下面一段代码,我们来学习一下c_str()的用法吧!
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);//去除同步流,加速
char a[5];//临时变量,用于输入
scanf("%s", a);
string str(a);
printf("str = ", str.c_str());
return 0;
}
当然,也可以这样进行输入输出:
string str;
str.resize(5); //预先分配空间
scanf("%s", &str[0]); //hello
printf("str = ", str.c_str()); //hello
想获得完整的输入(避免因为回车和空格而接受不到),我们可以使用getline()函数。
string a;
getline(cin, a); //hello world
cout << a << endl; //hello world
2.获取字符串的长度(length/size)
string str = "Hello World";
int length = str.length();//或者是 int length = str.size();
3.拼接字符串(+或append)
string str1 = "Hello";
string str2 = "World";
string str3 = str1 + ", " + str2;
//或者string str3 = str1.append(", ").append(str2);
4.字符串查找(find)
string str = "Hello, World";
size_t pos = str.find("World");
if(pos != string::npos)
{
cout << "Substring found at the position:" << pos << endl;
}
else
{
cout << "Substring not found." << endl;
}
pos返回的是被查找字符串首字符的下标,示例代码返回的是7
5.字符串替换(replace)
string str = "Hello, World!";
str.replace(7, 3, "C++");
cout << str << endl; //Hello, C++!
7是子串的起始位置,5是子串的长度
6.提取子字符串(substr)
string str = "Hello, World!";
string substr = str.substr(7, 5);
cout << substr << endl; //World
7是位置,5是长度,注意不要越界
7.字符串比较(compare)
string类型重载了不等号,可以直接使用 a < b 的方式比较string的大小,比较的规则是按照字典序比较(从小到大一个一个比较),一旦遇到不相等的字符便确定大小关系。
如:azzz < ba
可以使用compare函数进行比较:
string str1 = "Hello";
string str2 = "World";
int res = str1.compare(str2);
if(res == 0){
cout << "equal" << endl;
}else if(res < 0){
cout << "str1 < str2" << endl;
}else{
cout << "str1 > str2" << endl;
}
也可以直接用不等号进行比较,个人更推荐第二种。
8.遍历string
string类型的遍历有两种方法:循环枚举下标、auto枚举,这里介绍第二种。代码如下:
string str = "Hello";
for(int i = 0;i < str.length;++i)cout << str[i];//通过下标遍历string类型
cout << endl;
for(auto i : str)
{
cout << i;
i = 'a'; //此处的修改无效,是值传递
}
cout << endl; //此时str = "Hello"
for(&i : str)
{
cout << i;
i = 'a'; //址传递,str = "aaaaa"
}
cout << endl;
cout << str << endl;
总结
我也从没想过string类型的字符串还有这么多的花样。总而言之,如果你觉得这篇文章还不错,劳烦多多支持一下!码字不易,感谢你的观看!