C++ string类用法详解
C++ string 类基础介绍
在 C++ 中,string
类定义在 <string>
头文件中,它提供了一种方便的方式来处理字符串。与传统的 C 风格字符串(以 '\0'
结尾的字符数组)相比,string
类具有诸多优势,例如自动管理内存,提供丰富的成员函数来操作字符串等。
在使用 string
类之前,必须包含 <string>
头文件:
#include <string>
1. 定义和初始化
-
默认初始化:
std::string s1;
这会创建一个空的
string
对象。 -
使用字符串字面量初始化:
std::string s2 = "Hello, World!"; std::string s3("Hello, again");
这两种方式都使用字符串字面量初始化了
string
对象。 -
使用其他
string
对象初始化:std::string s4 = s2; std::string s5(s3);
这里
s4
和s5
分别通过拷贝s2
和s3
进行初始化。 -
使用部分字符串初始化:
std::string s6(s2, 0, 5); // 从 s2 的第 0 个位置开始,取 5 个字符,s6 为 "Hello"
-
使用字符重复初始化:
std::string s7(5, 'a'); // s7 为 "aaaaa"
2. 基本操作
字符串连接
-
使用
+
运算符:std::string s1 = "Hello"; std::string s2 = " World"; std::string s3 = s1 + s2; // s3 为 "Hello World"
也可以将
string
对象与字符串字面量连接:std::string s4 = s1 + " from C++"; // s4 为 "Hello from C++"
-
使用
+=
运算符:std::string s5 = "Goodbye"; s5 += " cruel world"; // s5 为 "Goodbye cruel world"
字符串比较
- 使用
==
、!=
、<
、>
、<=
、>=
运算符:
这些运算符按照字典序比较字符串。std::string s1 = "apple"; std::string s2 = "banana"; if (s1 < s2) { std::cout << s1 << " comes before " << s2 << std::endl; }
获取字符串长度
length()
或 size()
成员函数可以获取 string
对象中字符的个数:
std::string s = "example";
std::cout << "Length of s: " << s.length() << std::endl;
std::cout << "Size of s: " << s.size() << std::endl;
length()
和 size()
在功能上是等效的。
访问字符
-
使用
[]
运算符:std::string s = "programming"; std::cout << "The first character: " << s[0] << std::endl;
可以通过
[]
运算符访问string
对象中的单个字符,索引从 0 开始。但是这种方式不会进行越界检查,如果访问越界,行为是未定义的。 -
使用
at()
成员函数:std::string s = "example"; try { std::cout << "The 10th character: " << s.at(9) << std::endl; } catch (const std::out_of_range& e) { std::cerr << "Out of range error: " << e.what() << std::endl; }
at()
函数会进行越界检查,如果访问越界,会抛出std::out_of_range
异常。
3. 字符串修改
插入字符或字符串
-
在指定位置插入单个字符:
std::string s = "hello"; s.insert(1, 'x'); // s 变为 "hxello"
第一个参数是插入位置的索引,第二个参数是要插入的字符。
-
在指定位置插入字符串:
std::string s1 = "world"; std::string s2 = "hello "; s1.insert(0, s2); // s1 变为 "hello world"
这里在
s1
的开头(索引 0 处)插入了s2
。
删除字符或字符串
-
删除指定位置的单个字符:
std::string s = "hello"; s.erase(1, 1); // s 变为 "hllo",从索引 1 处删除 1 个字符
第一个参数是起始位置索引,第二个参数是要删除的字符个数。
-
删除指定范围的字符:
std::string s1 = "programming"; s1.erase(3, 4); // s1 变为 "progming",从索引 3 处开始删除 4 个字符
替换字符或字符串
-
替换指定范围的字符:
std::string s = "hello world"; s.replace(6, 5, "C++"); // s 变为 "hello C++",从索引 6 处开始,用 "C++" 替换 5 个字符
第一个参数是起始位置索引,第二个参数是要替换的字符个数,第三个参数是用于替换的字符串。
-
使用另一个字符串的部分进行替换:
std::string s1 = "goodbye"; std::string s2 = "hello world"; s1.replace(0, 7, s2, 6, 5); // s1 变为 "world",用 s2 从索引 6 处开始的 5 个字符替换 s1 从索引 0 处开始的 7 个字符
4. 查找子字符串和字符
查找子字符串
-
find()
函数:std::string s = "hello world"; size_t pos = s.find("world"); if (pos != std::string::npos) { std::cout << "Substring found at position: " << pos << std::endl; } else { std::cout << "Substring not found" << std::endl; }
find()
函数从字符串开头开始查找子字符串,返回子字符串首次出现的位置。如果未找到,返回std::string::npos
,这是一个表示不存在位置的特殊值。 -
rfind()
函数:std::string s1 = "banana"; size_t pos1 = s1.rfind("na"); if (pos1 != std::string::npos) { std::cout << "Substring found at position (rfind): " << pos1 << std::endl; }
rfind()
函数从字符串末尾开始查找子字符串,返回子字符串最后一次出现的位置。
查找字符
-
find_first_of()
函数:std::string s = "hello world"; size_t pos2 = s.find_first_of('o'); if (pos2 != std::string::npos) { std::cout << "Character 'o' found at position: " << pos2 << std::endl; }
find_first_of()
函数查找字符串中首次出现的指定字符,返回字符首次出现的位置。 -
find_last_of()
函数:std::string s2 = "hello world"; size_t pos3 = s2.find_last_of('o'); if (pos3 != std::string::npos) { std::cout << "Character 'o' found at position (last): " << pos3 << std::endl; }
find_last_of()
函数查找字符串中最后一次出现的指定字符,返回字符最后出现的位置。
5. 字符串流操作
<sstream>
头文件提供了 stringstream
类,用于在字符串和其他数据类型之间进行转换。
字符串到数值的转换
#include <sstream>
#include <iostream>
int main() {
std::string str = "123";
int num;
std::stringstream ss(str);
ss >> num;
std::cout << "Converted number: " << num << std::endl;
return 0;
}
这里使用 stringstream
将字符串 "123"
转换为整数 123
。
数值到字符串的转换
#include <sstream>
#include <iostream>
int main() {
int num = 456;
std::stringstream ss;
ss << num;
std::string str = ss.str();
std::cout << "Converted string: " << str << std::endl;
return 0;
}
此代码将整数 456
转换为字符串 "456"
。
6. C 风格字符串的转换
string
转 C 风格字符串
c_str()
函数:std::string s = "example"; const char* cstr = s.c_str();
c_str()
函数返回一个指向以'\0'
结尾的 C 风格字符串的指针。注意返回的指针指向的内存是string
对象内部管理的,并且只要string
对象存在,该指针就有效。
C 风格字符串转 string
const char* cstr = "hello";
std::string s(cstr);
直接使用 C 风格字符串作为 string
构造函数的参数即可完成转换。
7. 迭代器
string
类支持迭代器,这使得可以像处理其他容器一样遍历字符串。
正向迭代
std::string s = "hello";
for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
这里使用 begin()
获取指向字符串开头的迭代器,end()
获取指向字符串末尾(但不包含末尾字符)的迭代器。
反向迭代
std::string s1 = "world";
for (std::string::reverse_iterator rit = s1.rbegin(); rit != s1.rend(); ++rit) {
std::cout << *rit;
}
std::cout << std::endl;
rbegin()
获取指向字符串末尾的反向迭代器,rend()
获取指向字符串开头之前的反向迭代器,从而实现反向遍历。
8. 内存管理和性能
string
类在内部管理字符串的内存。当字符串内容发生变化时,string
类会根据需要重新分配内存。
容量和预留
- 容量(capacity):
capacity()
函数返回当前string
对象分配的内存空间能够容纳的字符数(不包括结尾的'\0'
)。std::string s = "hello"; std::cout << "Capacity of s: " << s.capacity() << std::endl;
- 预留(reserve):
reserve()
函数可以预先分配一定大小的内存,以避免频繁的内存重新分配。
这会为std::string s1; s1.reserve(100);
s1
预留至少能容纳 100 个字符的内存空间。
收缩到合适大小
shrink_to_fit()
函数可以将 string
对象的容量调整为实际使用的大小,释放多余的内存:
std::string s2 = "example";
s2.reserve(100);
// 做一些操作后
s2.shrink_to_fit();
9. 本地化和多字节字符串
在处理不同语言和字符编码时,string
类也有一定的支持。
宽字符字符串
C++ 提供了 wstring
类来处理宽字符字符串,定义在 <string>
头文件中。宽字符通常用于表示非 ASCII 字符,例如中文、日文等。
#include <iostream>
#include <string>
int main() {
std::wstring ws = L"你好,世界";
std::wcout << ws << std::endl;
return 0;
}
这里使用 L
前缀来表示宽字符字符串字面量。wcout
用于输出宽字符字符串。
多字节字符串处理
在处理多字节字符编码(如 UTF - 8)时,string
类本身按字节处理字符串。对于更复杂的多字节字符串操作,可以使用一些库,如 iconv
库(在 Unix - like 系统上)来进行编码转换。例如,将 UTF - 8 编码的字符串转换为其他编码:
#include <iostream>
#include <string>
#include <iconv.h>
std::string convertEncoding(const std::string& input, const char* fromCode, const char* toCode) {
iconv_t cd = iconv_open(toCode, fromCode);
if (cd == (iconv_t)-1) {
std::cerr << "Failed to open conversion" << std::endl;
return "";
}
std::string output;
const char* inbuf = input.c_str();
size_t inbytesleft = input.size();
char outbuf[1024];
char* outptr = outbuf;
size_t outbytesleft = sizeof(outbuf);
while (inbytesleft > 0) {
size_t result = iconv(cd, &inbuf, &inbytesleft, &outptr, &outbytesleft);
if (result == (size_t)-1) {
std::cerr << "Conversion error" << std::endl;
iconv_close(cd);
return "";
}
output.append(outbuf, sizeof(outbuf) - outbytesleft);
outptr = outbuf;
outbytesleft = sizeof(outbuf);
}
iconv_close(cd);
return output;
}
int main() {
std::string utf8Str = "你好";
std::string gb2312Str = convertEncoding(utf8Str, "UTF - 8", "GB2312");
std::cout << "Converted string: " << gb2312Str << std::endl;
return 0;
}
此代码示例展示了如何使用 iconv
库将 UTF - 8 编码的字符串转换为 GB2312 编码的字符串。实际应用中,需要根据具体需求处理错误和优化代码。
10. 与其他库的结合使用
string
类在与其他 C++ 库结合使用时也非常方便。
与 STL 算法结合
STL(标准模板库)提供了丰富的算法,string
类可以很好地与这些算法配合。例如,使用 std::find
算法查找字符串中的字符:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string s = "hello world";
auto it = std::find(s.begin(), s.end(), 'o');
if (it != s.end()) {
std::cout << "Character 'o' found at position: " << std::distance(s.begin(), it) << std::endl;
}
return 0;
}
这里使用 std::find
算法在 string
对象 s
中查找字符 'o'
。
与文件操作结合
在文件读写操作中,string
类可以方便地处理读取和写入的字符串内容。例如,从文件中读取一行内容到 string
对象:
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::ifstream file("test.txt");
std::string line;
if (file.is_open()) {
std::getline(file, line);
std::cout << "Read line: " << line << std::endl;
file.close();
} else {
std::cerr << "Could not open file" << std::endl;
}
return 0;
}
此代码从名为 test.txt
的文件中读取一行内容并存储到 string
对象 line
中。同样,也可以将 string
对象的内容写入文件:
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::ofstream file("output.txt");
std::string content = "This is some content to write";
if (file.is_open()) {
file << content << std::endl;
file.close();
} else {
std::cerr << "Could not open file" << std::endl;
}
return 0;
}
这里将 string
对象 content
的内容写入名为 output.txt
的文件中。
通过以上详细的介绍和丰富的代码示例,希望你对 C++ 中 string
类的用法有了更深入全面的理解,能够在实际编程中灵活高效地使用 string
类来处理各种字符串相关的任务。无论是简单的文本处理,还是复杂的国际化应用开发,string
类都能提供强大而便捷的功能支持。