文章目录
关于 string
更加详细的介绍,可自行查阅 cppreference
:https://en.cppreference.com/w/cpp/string/basic_string
1.概述
在 C 语言中,一般使用字符数组 char s[]
来存放字符串。但是,使用字符数组操作麻烦,而且容易因经验不足而产生一些错误。
C++ 在 STL 中加入了 string
类型,对字符串常用的需求功能进行了封装,操作方便且不易出错。
C++ 的 string
和 C 语言的 char *
有什么区别呢?
-
string
是一个类,char *
是指向字符的指针。 -
string
封装了char *
来管理字符串,string
是一个char *
类型的容器。 -
string
不用考虑内存释放和数组越界。 -
string
提供了一系列的字符串操作函数。
2.string的定义与初始化
头文件 #include <string>
。
定义 string
的方式与基本数据类型相同,只需要在 string
后跟上变量名即可。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1; // 通过无参默认构造函数将s1初始化为空串
string s2("hello world"); // 通过构造函数初始化
string s3 = "hello world"; // 通过构造函数初始化
string s4(s2); // 通过拷贝构造函数初始化
string s5 = s2; // 通过拷贝构造函数初始化
string s6(10, 'a'); // 通过构造函数将s6初始化为连续的10个'a'
return 0;
}
上面代码在 Visual Studio 中反汇编的结果如下:
string s1; // 通过无参默认构造函数将s1初始化为空串
lea rcx,[s1]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C61578h)
nop
string s2("hello world"); // 通过构造函数初始化
lea rdx,[string "hello world" (07FF738C6F568h)]
lea rcx,[s2]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C6125Dh)
nop
string s3 = "hello world"; // 通过构造函数初始化
lea rdx,[string "hello world" (07FF738C6F568h)]
lea rcx,[s3]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C6125Dh)
nop
string s4(s2); // 通过拷贝构造函数初始化
lea rdx,[s2]
lea rcx,[s4]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C610CDh)
nop
string s5 = s2; // 通过拷贝构造函数初始化
lea rdx,[s2]
lea rcx,[s5]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C610CDh)
nop
string s6(10, 'a'); // 通过构造函数将s6初始化为连续的10个'a'
mov r8b,61h
mov edx,0Ah
lea rcx,[s6]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (07FF738C61316h)
3.string的赋值
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
s1.assign("hello");
string s2;
s2 = "hello"; // 拷贝赋值运算符
string s3;
s3 = s1; // 拷贝赋值运算符
return 0;
}
上面代码在 Visual Studio 中反汇编的结果如下:
string s1;
lea ecx,[s1]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0401334h)
mov dword ptr [ebp-4],0
s1.assign("hello");
push offset string "hello" (040BBF0h)
lea ecx,[s1]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (0401474h)
string s2;
lea ecx,[s2]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0401334h)
mov byte ptr [ebp-4],1
s2 = "hello"; // 拷贝赋值运算符
push offset string "hello" (040BBF0h)
lea ecx,[s2]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator= (0401375h)
string s3;
lea ecx,[s3]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0401334h)
mov byte ptr [ebp-4],2
s3 = s1; // 拷贝赋值运算符
lea eax,[s1]
push eax
lea ecx,[s3]
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator= (0401145h)
4.string的读写
如果要读入和输出 string,则只能使用 cin 和 cout。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cin >> str;
cout << str;
return 0;
}
5.string的长度
length()
或 size()
函数返回 string 的长度,即存放的字符数,时间复杂度为
O
(
1
)
O(1)
O(1)。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "I Love China!";
cout << s1.length() << endl; // 13
return 0;
}
6.string的遍历
6.1 [ ] 运算符
与数组相同,通过 []
运算符访问元素内容。但是,如果出现越界或者其他错误,不会抛出异常。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str("hello world!");
for (int i = 0; i < str.length(); i++)
{
cout << str[i] << endl;
}
return 0;
}
6.2 at()
at()
方法根据索引取出元素内容,如果出现越界或其他错误,会抛出异常。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str("hello world!");
for (int i = 0; i < str.length(); i++)
{
cout << str.at(i) << endl;
}
return 0;
}
6.3 迭代器
迭代器可以看作是一个字符的指针,*it
就表示当前的字符。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str("hello world!");
for (string::iterator it = str.begin(); it != str.end(); it++)
{
cout << *it << endl;
}
return 0;
}
6.4 范围for
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "I Love China!";
for (auto c : s1)
{
cout << c;
}
cout << endl;
for (auto &c : s1)
{
c = toupper(c);
}
cout << s1 << endl;
return 0;
}
7.string 与 char * 的转换
可以使用 c_str()
将 string 对象转化成字符数组 const char*
。
c_str()
函数返回一个以 '\0'
结尾的字符数组。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1("hello world!");
const char* p = s1.c_str();
string s2 = p;
cout << s2 << endl;
return 0;
}
8.string的拼接
8.1 + 运算符
string 对 +
运算符进行了重载,可以直接相加。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "hello";
string s2 = "world";
string s3 = "123" + "abc"; // 错误
string s4 = s1 + s2; // 正确
string s5 = s1 + "123" + "abc"; // 正确
string s6 = "123" + s1 + "abc"; // 正确
string s7 = "123" + "abc" + s1; // 错误
return 0;
}
8.2 append()
string 提供了成员函数 append()
供我们拼接字符串。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "hello";
string s2 = "world";
string s3 = s1.append(s2);
return 0;
}
9.string的字典序比较
字典序:两个字符串 a
和 b
,从前向后一个字符一个字符比较。遇到第 i
个不相同时,结果就是 a[i]
和 b[i]
的大小关系。如果一直相等,若有一个字符串结束,则长的大;若一样长,则两个字符串相等。
9.1 compare()
s1.compare(s2)
的含义如下:
-
s1
和s2
相等时,返回 0; -
s1
字典序小于s2
时,返回值小于 0; -
s1
字典序大于s2
时,返回值大于 0。
9.2 比较运算符
string 类对运算符 >
、<
、==
、>=
、<=
进行了重载,可以直接比较两个字符串的字典序大小。
10.string的子串
substr(pos, len)
:返回从 pos
号位开始、长度为 len
的子串,即返回子串 [pos, pos + len)
。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "abcdefg";
string s2 = s1.substr(0, 3);
cout << s2 << endl; // abc
return 0;
}
11.string的查找
string 类提供了 find()
函数,用来查找字符串中指定的字符。
str.find(str2)
:当 str2
是 str
的子串时,返回其在 str
中第一次出现的位置;如果 str2
不是 str
的子串,那么返回 string::npos
。
str.find(str2, pos)
:从 str
的 pos
号位开始匹配 str2
,返回值与上面相同。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "abc123def";
if (str.find("234") == string::npos)
{
cout << "no" << endl;
}
else
{
cout << "yes" << endl;
}
return 0;
}
string::npos
是一个静态成员常量 static const size_type npos = -1
,其本身的值为 -1
,但由于是 unsigned int 类型,因此也可以认为是 unsigned int 的最大值 4294967295
(在 32 位的编译器上)。该值表示“直到字符串结尾”,用以作为 find() 函数失配时的返回值。
#include <iostream>
#include <string>
using namespace std;
int main()
{
if (string::npos == -1)
{
cout << "-1 is true" << endl;
}
if (string::npos == 4294967295)
{
cout << "4294967295 is true" << endl;
}
return 0;
}
举例1:求 “hello” 出现的次数以及对应的下标。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "world hello hello hello hello hello 1234 7876";
int cnt = 0;
string::size_type idx = s1.find("hello", 0);
while (idx != string::npos)
{
cout << "索引:" << idx << endl;
cnt++;
idx++;
idx = s1.find("hello", idx);
}
return 0;
}
举例2:把 “hello” 替换成 “welcome”。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1 = "world hello hello hello hello hello 1234 7876";
size_t idx = s1.find("hello", 0);
while (idx != string::npos)
{
s1.replace(idx, strlen("hello"), "welcome");
idx += strlen("welcome");
idx = s1.find("hello", idx);
}
cout << "替换后的字符串:" << s1 << endl;
return 0;
}