初始化
string s1(); // s1 = ""(变量 s1 只是定义但没有初始化,编译器会将默认值赋给 s1,默认值是“”,即为空字符串)
string s2("Hello"); // s2 = "Hello"(变量 s2 在定义的同时被初始化为“Hello”,与C风格的字符串不同,string 的结尾没有结束标志‘\0’)
想到了美团20240323的一道题:
string s3(4, 'K'); // s3 = "KKKK"(变量 s3 被初始化为由 4个'K'符组成的字符串"KKKK")
这个可以用于字符串截取
string s4("12345", 1, 3); //s4 = "234",即 "12345" 的从下标 1 开始,长度为 3 的子串
代码
结果
似乎还有点麻烦?😂 后面有方便的erase等操作可以方便的实现!
string的assign方法:
string s1("12345"), s2;
s3.assign(s1); // s3 = s1,string类对象拷贝
s2.assign(s1, 1, 2); // s2 = "23",即 s1 的子串(1, 2),取子串
s2.assign("abcde", 2, 3); // s2 = "cde",即 "abcde" 的子串(2, 3)
//这个里面assign的参数意思与string初始化时候一样
尝试一下
这样会报错
必须先声明,在使用方法
结果
发现这几种方法都相当于是拷贝了一份,不随a1而改变
在某些必要的时刻,string字符串转换为C风格的字符串
虽然 C++ 提供了 string 类来替代C语言中的字符串,但是在实际编程中,有时候必须要使用C风格的字符串(例如打开文件时的路径),为此,string 类为我们提供了一个转换函数 c_str(),该函数能够将 string 字符串转换为C风格的字符串,并返回该字符串的 const 指针(const char*)。请看下面的代码:
string path = "D:\\demo.txt";
FILE *fp = fopen(path.c_str(), "rt"); //为了使用C语言中的 fopen() 函数打开文件,必须将 string 字符串转换为C风格的字符串。
size()/length()
string字符串求字符串长度时,可以调用 string 类提供的 length() 或size()成员函数。
一些高深的的容器操作
capacity() 返回对象总空间大小
reserve(size_t n) 为字符串对象预留n字节空间
resize(size_t n,char c) 将有效字符串长度改为n,多出的位置用字符c填充(缺省默认使用‘\0’填充)
//例1
#include <iostream>
#include <string>
using namespace std;
void stringTest1()
{
string s("Hello World");
cout<<s.size()<<endl; // 11
cout<<s.length()<<endl; // 11
cout<<s.capacity()<<endl; // 15
cout<<s<<endl; //"Hello World"
s.clear(); //将s中的字符串清空
cout<<s.size()<<endl; // 0
cout<<s.capacity()<<endl; // 15
//所以clear只是改变s的有效字符串长度size,s的容量(底层空间)并没有改变
s.resize(10,'a');
cout<<s.size()<<endl; // 10
cout<<s.capacity()<<endl; // 15
cout<<s<<endl; //"aaaaaaaaaa"
s.resize(20);
cout<<s.size()<<endl; // 20
cout<<s.capacity()<<endl; // 30
cout<<s<<endl; //"aaaaaaaaaa"这里其实后面有10个'\0'作为填充
s.resize(5);
cout<<s.size()<<endl; // 5
cout<<s.capacity()<<endl; // 30
cout<<s<<endl; //"aaaaa"
//所以resize改变的是有效字符串的个数
//当n值增大时,可能会改变底容量大小,即底层空间增加
//而n值减少,则容量不变。
}
int main()
{
stringTest1();
return 0;
}
//例2
#include <iostream>
#include <string>
using namespace std;
void stringTest2()
{
string s;
s.reserve(100);
cout << s.size() << endl; //0
cout << s.capacity() << endl; //100
s.reserve(50);
cout << s.size() << endl; // 0
cout << s.capacity() << endl; //100
}
小结:
a.clear只是将string中有效字符串清空,不改变底层空间大小。
b.resize将字符串有效字符个数改变为n个,个数增多时,多余空间进行填充。
另外,resize将元素增多时,可能会改变底层容量的大小,而元素减少时,底层容量不变。
c.reserve为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。
除了for循环,str[i]遍历以外,还有迭代器!
如何取出迭代器的值?答案是用*
void stringTest3()
{
string s("hello world");
for(string::iterator it=s.begin();it!=s.end();it++)//正向迭代器
{
cout<<*it;
}
cout<<endl;
for(string::reverse_iterator rit=s.rend();rit>=s.rbegin();rit--)//反向迭代器
{
cout<<*rit;
}
cout<<endl;
}
说个笑话,这个报错半天没看出来
"iterator"迭代呀,
begin指向第一个字符
end指向最后一个字符的后一位
c++11才能用的auto,怪不得我用老报错
void stringTest4()
{
string s("hello world");
for(auto it:s)//通过auto自动推导
{
cout<<it<<endl;
}
}
下面是极其实用的修改string对象部分
插入
1.push_back 在尾部插入
void stringTest4()
{
string s("hello world");
s.push_back('!'); //尾部插入字符!
cout<<s<<endl; //“hello world!”
}
2.直接用加号连接 两个 ~
string 类可以使用 + 或 += 运算符来直接拼接字符串,再也不需要使用C语言中的 strcat()、strcpy()、malloc() 等函数来拼接字符串了,再也不用担心空间不够会溢出了。
用 + 来拼接字符串时,运算符的两边可以都是 string 字符串,也可以是一个 string 字符串和一个C风格的字符串,还可以是一个 string 字符串和一个字符数组,或者是一个 string 字符串和一个单独的字符。
分别对应下面四类:
#include <iostream>
#include <string>
using namespace std;
int main(){
string s1 = "first ";
string s2 = "second ";
char *s3 = "third ";
char s4[] = "fourth ";
char ch = '@';
string s5 = s1 + s2;
string s6 = s1 + s3;
string s7 = s1 + s4;
string s8 = s1 + ch;
cout<<s5<<endl<<s6<<endl<<s7<<endl<<s8<<endl;
return 0;
}
3.append(原来c++也有!我以为只有Python有呢) 在尾部插入
string 类还有 append 成员函数,可以用来向字符串后面添加内容。append 成员函数返回对象自身的引用。
他的参数意义同string
string s1("123"), s2("abc");
s1.append(s2); // s1 = "123abc"
s1.append(s2, 1, 2); // s1 = "123abcbc"
s1.append(3, 'K'); // s1 = "123abcbcKKK"
s1.append("ABCDE", 2, 3); // s1 = "123abcbcKKKCDE",添加 "ABCDE" 的子串(2, 3)
4.insert 在指定位置插入
作用: string 字符串中指定的位置插入另一个字符串(它可以是 string 字符串,也可以是C风格的字符串),返回值为对象自身的引用
string s1("Limitless"), s2("00");
s1.insert(2, "123"); //在下标 2 处插入字符串"123",s1 = "Li123mitless"
s1.insert(3, s2); //在下标 2 处插入 s2 , s1 = "Li10023mitless"
s1.insert(3, 5, 'X'); //在下标 3 处插入 5 个 'X',s1 = "Li1XXXXX0023mitless"
删除
1.pop_back 在尾部删除
只能删除尾部!要删除别的地方请看下一条
// string::pop_back
#include <iostream>
#include <string>
int main ()
{
std::string str ("hello world!");
str.pop_back(); //删除尾部字符!
std::cout << str << std::endl; //"hello world"
return 0;
}
2.erase 删除指定位置
erase() 函数可以删除 string 中的一个子字符串。
pos:要删除的子字符串的起始下标
len: 要删除子字符串的长度。如果不指明 len 的话,那么直接删除从 pos 到字符串结束处的所有字符(此时 len = str.length() - pos)。
string s1("Real Steel");
s1.erase(1, 3); //删除子串(1, 3),此后 s1 = "R Steel"3是len,不是下标!
s1.erase(5); //删除下标5及其后面的所有字符,此后 s1 = "R Ste"
std::string str ("This is an example sentence.");
std::cout << str << '\n'; // "This is an example sentence."
str.erase (10,8);
std::cout << str << '\n'; // "This is an sentence."
str.erase (str.begin()+9); // "This is a sentence."
str.erase (str.begin()+5, str.end()-9); // "This sentence."
std::cout << str << '\n';
【注意】可能有人认为,在 pos 参数没有越界的情况下, len 参数也可能会导致要删除的子字符串越界。但实际上这种情况不会发生,erase() 函数会从len和str.length() - pos两个值中取出最小的一个作为待删除子字符串的长度。
比较字符串
string对象的比较
方法一:比较运算符
用 <、<=、==、!=、>=、> 运算符比较 string 对象
方法二: compare() 成员函数
string 类还有 compare 成员函数,可用于比较字符串。
compare 成员函数有以下返回值:
小于 0 表示当前的字符串小;
等于 0 表示两个字符串相等;
大于 0 表示另一个字符串小。
string s1("hello"), s2("hello, world");
int n = s1.compare(s2);
n = s1.compare(1, 2, s2, 0, 3); //比较s1的子串 (1,2) 和s2的子串 (0,3)参数博大精深参数还是参数
n = s1.compare(0, 2, s2); // 比较s1的子串 (0,2) 和 s2
n = s1.compare("Hello");
n = s1.compare(1, 2, "Hello"); //比较 s1 的子串(1,2)和"Hello”
n = s1.compare(1, 2, "Hello", 1, 2); //比较 s1 的子串(1,2)和 "Hello" 的子串(1,2)
string 对象的子串
【substr()成员函数】
substr 成员函数可以用于求pos开始,长度为len的子串。
调用时,如果省略len或len超过了字符串的长度,则子串就是从pos开始直到字符串结束的部分。
string s1 = "this is ok";
string s2 = s1.substr(2, 4); // s2 = "is i"
s2 = s1.substr(2); // s2 = "is is ok"
交换两个string对象的内容【swap()函数】
swap 成员函数可以交换两个 string 对象的内容。例如:
string s1("West”), s2("East");
s1.swap(s2); // s1 = "East",s2 = "West"
查找和逆向查找,暂时贴个代码,下次再详细讲讲
查找子串和字符【find()函数】
string 类有一些查找子串和字符的成员函数,它们的返回值都是子串或字符在 string 对象字符串中的位置(即下标)。如果查不到,则返回 string::npos。string: :npos 是在 string 类中定义的一个静态常量。这些函数如下:
find:从前往后查找子串或字符出现的位置。
rfind:从后往前查找子串或字符出现的位置。
find_first_of:从前往后查找何处出现另一个字符串中包含的字符。例如:
s1.find_first_of("abc"); //查找s1中第一次出现"abc"中任一字符的位置
find_last_of:从后往前查找何处出现另一个字符串中包含的字符。
find_first_not_of:从前往后查找何处出现另一个字符串中没有包含的字符。
find_last_not_of:从后往前查找何处出现另一个字符串中没有包含的字符。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1("Source Code");
int n;
if ((n = s1.find('u')) != string::npos) //查找 u 出现的位置
cout << "1) " << n << "," << s1.substr(n) << endl;//输出 l)2,urce Code
if ((n = s1.find("Source", 3)) == string::npos)//从下标3开始查找"Source",找不到
cout << "2) " << "Not Found" << endl; //输出 2) Not Found
if ((n = s1.find("Co")) != string::npos)//查找子串"Co"。能找到,返回"Co"的位置
cout << "3) " << n << ", " << s1.substr(n) << endl;//输出 3) 7, Code
if ((n = s1.find_first_of("ceo")) != string::npos)//查找第一次出现或 'c'、'e'或'o'的位置
cout << "4) " << n << ", " << s1.substr(n) << endl;//输出 4) l, ource Code
if ((n = s1.find_last_of('e')) != string::npos)//查找最后一个 'e' 的位置
cout << "5) " << n << ", " << s1.substr(n) << endl; //输出 5) 10, e
if ((n = s1.find_first_not_of("eou", 1)) != string::npos)
//从下标1开始查找第一次出现非 'e'、'o' 或 'u' 字符的位置
cout << "6) " << n << ", " << s1.substr(n) << endl; //输出 6) 3, rce Code
return 0;
}
替换子串【replace()成员函数】
replace 成员函数可以对 string 对象中的子串进行替换,返回值为对象自身的引用。
示例如下:
string s1("Real Steel");
s1.replace(1, 3, "123456", 2, 4); //用 "123456" 的子串(2,4) 替换 s1 的子串(1,3)
cout << s1 << endl; //输出 R3456 Steel
string s2("Harry Potter");
s2.replace(2, 3, 5, '0'); //用 5 个 '0' 替换子串(2,3)
cout << s2 << endl; //输出 HaOOOOO Potter
int n = s2.find("OOOOO"); //查找子串 "00000" 的位置,n=2
s2.replace(n, 5, "XXX"); //将子串(n,5)替换为"XXX"
cout << s2 < < endl; //输出 HaXXX Potter