C++的标准库中,提供了一种用来表示字符串的数据类型string,这种类型能够表示长度可变的字符序列,不用担心赋值越界和取值越界等。
string 是C++风格的字符串,而 string 本质上是一个类,类内部封装了 char* ,管理这个字符串。
string类型也定义在命名空间std中,使用它必须包含string头文件。
#include<string>
using namespace std;
初始化和赋值字符串
我们已经接触过C++中几种不同的初始化方式,string也是一个标准库类型,它的初始化与vector非常相似。
// 默认初始化,空字符串
string s1;
const char* str1 = "hello world"; // c_string风格,类比于string
// 用另一个字符串变量,做拷贝初始化
string s2 = str1; // 注意只是将s1中的字符串拷贝给s2,以后操作s1,对s2无影响
string s2(str1); // 也可以调用拷贝构造函数
string str2;
str2 = 'a';
// string str2 = 'a' 这样是不对的!
// 用一个字符串字面值,做拷贝初始化
string s3 = "Hello World!";
// 用一个字符串字面值,做直接初始化
string s4("hello world");
// 定义字符和重复的次数,做直接初始化,得到 hhhhhhhh
string s5(8, 'h');
// 通过str.assign()赋值
string str4;
str4.assign("hello c++"); // 直接赋值
string str5;
str5.assign("hello c++",3); // str5 = “hel”
string str6;
str6.assign(str5); // str6 = "hel"
string str7;
str7.assign(5, 'x'); // str7 = "xxxxx"
操作字符串
string str = "hello world";
// 获取第3个字符
cout << "str[2] = " << str[2] << endl;
// 将第1个字符改为'H'
str[0] = 'H';
// str[i] 和 str.at(i) 同理
// 将最后一个字符改为'D'
str[str.size() - 1] = 'D';
cout << "str = " << str << endl;
// 使用string方法
// 查找
string str1 = "abcdefgde";
int pos = str1.find("de");
int pos1 = str1.rfind("de");
// pos = 3; pos1 = 7;
// 替换
str1.replace(1, 3, "1111");
// str1 = "a1111efgde";
// 插入
str.insert(1, "111");
// str = "H111ello worlD"
// 删除
str.erase(1, 3); //从1号位置开始3个字符
// str = "Hello worlD"
// 获取子串
string subStr = str.substr(1, 3);
// subStr = "ell"
总结:
- find查找是从左往后,rfind从右往左
- 找到字符串后返回查找的第一个字符位置,找不到返回-1
注意:不能越界访问;如果直接越界访问并赋值,有可能导致非常严重的后果,出现安全问题
对于拷贝可能出现的问题:
例如:遍历所有字符,将小写字母换成大写:
// 遍历字符串中字符,将小写字母变成大写
for (int i = 0; i < str.size(); i++)
{
str[i] = toupper(str[i]);// string的一个函数toupper,可以把传入的字符转换成大写并返回
}
//以下是错误代码:
for (int i = 0; i < s.length(); i++)
{
s1[i] = toupper(s[i]);
}
错误代码无法将s中的字符全部转换为大写字母并赋值给s1字符串的原因是,s1字符串在循环中访问索引i的时候是无效的,s1[i]访问索引i的操作将导致未定义行为,因为s1的大小为0,没有有效的索引。
在C++中,std::string
是一个可变长度的字符序列,可以通过push_back()
或+=
运算符来添加字符。
字符串相加(拼接)
string本身的长度是不定的,可以通过“相加”的方式扩展一个字符串。
// 字符串相加(拼接)
string str1 = "hello", str2("world");
string str3 = str1 + str2; // str3 = "helloworld"
string str4 = str1 + ", " + str2 + "!"; // str4 = "hello, world!"
//string str5 = "hello, " + "world!"; // 错误,不能将两个字符串字面值相加
string str6 = "I";
str6.append(" love ");
str6.append("game abcde", 4); // str6 = "I love game"
//str6.append(str); 可以追加字面量或者字符串变量
str6.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
比较字符串
string类还提供几种用来做字符串比较的运算符,“==”和“!=”用来判断两个字符串是否完全一样;而“<”“>”“<=”“>=”则用来比较两个字符串的大小。这些都是关系型运算符的重载。
str1 = "hello";
str2 = "hello world!";
str3 = "hehehe";
str1 == str2; // false
str1 < str2; // true
str1 >= str3; // true
// int ret = str1.compare(str2) 同理可以用string方法比较
字符串比较的规则为:
- 如果两个字符串长度相同,每个位置包含的字符也都相同,那么两者“相等”;否则“不相等”;
- 如果两个字符串长度不同,而较短的字符串每个字符都跟较长字符串对应位置字符相同,那么较短字符串“小于”较长字符串;
- 如果两个字符串在某一位置上开始不同,那么就比较这两个字符的ASCII码,比较结果就代表两个字符串的大小关系