精通C++ STL(一):解开string类的面纱与高效应用
目录
string的定义方式
string()
:默认构造函数,创建一个空字符串。
string (const string& str)
:拷贝构造函数,创建一个新的字符串对象,它是给定字符串str
的一个副本。
string (const string& str, size_t pos, size_t len = npos)
:从已存在的字符串str
中提取子串构造新字符串。pos
是开始位置的索引,len
是要提取的字符数;如果省略或设为npos
,则提取从pos
到字符串末尾的所有字符。
string (const char* s)
:从C风格字符串s
构造字符串对象。
string (const char* s, size_t n)
:从C风格字符串s
的前n
个字符构造字符串对象。
string (size_t n, char c)
:创建一个长度为n
,每个字符都为c
的字符串。
template <class InputIterator> string (InputIterator first, InputIterator last)
:这是一个模板构造函数,它接受一对迭代器(first
和last
),在这对迭代器所指定的范围内构造字符串。这使得可以从任何支持迭代访问的对象(如数组、容器等)中构造字符串。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
// 1. 默认构造函数
string strDefault;
cout << strDefault << endl;
// 2. 拷贝构造函数
string strCopy("Hello");
string strCopied(strCopy);
cout << strCopied << endl;
// 3. 从已有字符串提取子串构造
string strSubstr("HelloWorld", 6);
cout << strSubstr << endl;
// 4. 从C风格字符串构造
string strFromCStr("World");
cout << strFromCStr << endl;
// 5. 从C风格字符串的部分构造
const char* partCStr = "HelloWorld";
string strPartCStr(partCStr, 5);
cout << strPartCStr << endl;
// 6. 创建指定长度和字符的字符串
string strCharRepeat(5, 'A');
cout << strCharRepeat << endl;
// 7. 使用迭代器构造
char arr[] = { 'H', 'e', 'l', 'l', 'o' };
string strFromIter(arr, arr + sizeof(arr) - 1);
cout << strFromIter << endl;
return 0;
}
代码结果:
string的插入
使用push_back进行尾插
void push_back(char ch);
功能说明:
- 参数:
ch
- 要添加到字符串末尾的字符。- 返回值:此函数没有返回值,它直接修改调用它的字符串对象,在其末尾增加给定的字符。
- 扩容:如果添加字符导致字符串超出当前容量,
std::string
会自动进行内存管理,包括重新分配内存和复制现有内容到新位置,以容纳新增的字符,这个过程对用户透明。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, ";
str.push_back('W');
str.push_back('o');
str.push_back('r');
str.push_back('l');
str.push_back('d');
str.push_back('!');
cout << str << endl; // 输出: Hello, World!
return 0;
}
代码结果:
使用insert插入
插入单个字符:
string& insert(size_type pos, char ch);
- 参数:
pos
- 插入字符的位置(基于0的索引)。ch
- 要插入的字符。- 返回值:返回对字符串自身的引用,允许链式调用。
插入字符串:
string& insert(size_t pos, const string& str); string& insert(size_t pos, const string& str, size_t subpos, size_t sublen = npos);
- 第一种形式直接在
pos
位置插入整个字符串str
。- 第二种形式从字符串
str
的subpos
位置开始,插入sublen
个字符到pos
位置。如果sublen
被省略或设置为npos
,则插入从subpos
到str
末尾的所有字符。
插入字符数量:
string& insert(size_t pos, size_t count, char ch);
- 在
pos
位置插入count
个字符ch
。
插入迭代器范围:
template <class Iterator> string& insert(size_t pos, Iterator first, Iterator last);
- 插入由迭代器
first
和last
指定的范围内所有字符到pos
位置。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello";
// 在索引2的位置插入字符'a'
str.insert(2, "a");
cout << str << endl; // 输出: Helalo
// 在末尾插入字符串" World"
str.insert(str.size(), " World");
cout << str << endl; // 输出: Hela World
// 插入重复字符'e'三次
str.insert(1, 3, 'e');
cout << str << endl; // 输出: Heeele World
return 0;
}
代码结果:
string的拼接
使用append函数完成string的拼接
追加字符串:
string& append(const string& str);
- 将整个字符串
str
追加到当前字符串末尾。
追加子串:
string& append(const string& str, size_t pos, size_t n = npos);
- 从字符串
str
的pos
位置开始追加n
个字符到当前字符串末尾。如果n
等于npos
,则追加从pos
到str
末尾的所有字符。
追加字符数量:
string& append(size_t n, char c);
- 在字符串末尾追加
n
个字符c
。
追加字符数组:
string& append(const char* s); string& append(const char* s, size_t n);
- 第一种形式追加C风格字符串
s
直到遇到空字符\0
。- 第二种形式追加C风格字符串
s
的前n
个字符。
追加迭代器范围:
template <class Iterator> string& append(Iterator first, Iterator last);
- 追加由迭代器
first
和last
指定的范围内所有字符。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello";
// 追加字符串" World"
str.append(" World");
cout << str << endl; // 输出: Hello World
// 追加三个字符'a'
str.append(3, '!');
cout << str << endl; // 输出: Hello World!!!
// 从"C-style String"中追加前4个字符
const char* cs = "C-style String";
str.append(cs, 4);
cout << str << endl; // 输出: Hello World!!!C-st
return 0;
}
代码结果:
string的删除
使用pop_back进行尾删
void pop_back();
功能说明:
- 此函数没有返回值,它直接修改调用它的字符串对象,移除其末尾的字符。
- 如果字符串为空,调用
pop_back
函数是未定义行为。实践中,一些实现可能会抛出异常或忽略此操作,但最好避免在空字符串上调用此函数。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main() {
std::string str = "Hello, World!";
// 删除末尾的感叹号
str.pop_back();
cout << str << endl; // 输出: Hello, World
// 再次删除,这次是'd'
str.pop_back();
cout << str << endl; // 输出: Hello, Worl
// 继续删除,直至字符串为空
while ( !str.empty() )
{
str.pop_back();
}
cout << (str.empty() ? "Now the string is empty." : "String still has characters.") << endl; // 输出: Now the string is empty.
return 0;
}
代码结果:
使用erase删除
删除单个字符:
iterator erase(iterator position);
- 删除指针
position
所指向的字符,并返回下一个字符的迭代器。
删除指定范围内的字符:
iterator erase(iterator first, iterator last);
- 删除从迭代器
first
到last
之间(不包括last
)的所有字符,并返回last
之后的第一个字符的迭代器。
删除指定位置及其后的若干字符:
string& erase(size_t pos = 0, size_t n = npos);
- 删除从索引
pos
开始的n
个字符。如果n
等于npos
,则删除从pos
到字符串末尾的所有字符。返回修改后的字符串的引用。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, World!";
// 删除第7个字符(逗号)
str.erase(6, 1);
cout << str << endl; // 输出: Hello World!
// 删除从位置3到5的字符("lo")
str.erase(3, 2);
cout << str << endl; // 输出: HelWorld!
// 使用迭代器删除"World"之后的所有字符
auto it = str.find("World");
if (it != string::npos)
{
it += 5; // 移动到"World"之后
str.erase(it, str.end());
}
cout << str << endl; // 输出: HelWorld
return 0;
}
代码结果:
string的查找
使用find函数正向搜索第一个匹配项
查找子串:
size_t find(const string& str, size_t pos = 0) const;
- 在字符串中查找子串
str
首次出现的位置,搜索从索引pos
开始。默认情况下,pos
为0,即从字符串开头开始搜索。
查找单个字符:
size_t find(char c, size_t pos = 0) const;
- 查找字符
c
首次出现的位置,搜索同样从索引pos
开始。
查找子串并指定结束搜索位置:
size_t find(const string& str, size_t pos, size_t n) const;
- 查找子串
str
的前n
个字符首次出现的位置,搜索从索引pos
开始。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, this is a test string.";
// 查找子串"test"
size_t pos1 = str.find("test");
if (pos1 != string::npos)
{
cout << "Found 'test' at position: " << pos1 << endl;
}
else
{
cout << "'test' not found." << endl;
}
// 查找字符'a',从位置10开始
size_t pos2 = str.find('a', 0);
cout << "Found 'a' after position 0 at: " << pos2 << endl;
// 尝试查找不存在的子串
size_t pos3 = str.find("notfound");
if (pos3 == std::string::npos)
{
cout << "'notfound' not found in the string." << endl;
}
return 0;
}
代码结果:
使用rfind函数反向搜索第一个匹配项
查找子串:
size_t rfind(const string& str, size_t pos = npos) const;
- 从字符串末尾开始查找子串
str
首次出现的位置,可以指定搜索的起始位置pos
为npos
来从字符串的末尾开始搜索,默认也是这样。
查找单个字符:
size_t rfind(char c, size_t pos = npos) const;
- 从字符串末尾开始查找字符
c
首次出现的位置,同样可以指定搜索的起始位置。
查找子串并指定结束搜索位置:
size_t rfind(const string& str, size_t pos, size_t n) const;
- 从字符串末尾开始查找子串
str
的前n
个字符首次出现的位置,搜索从索引pos
开始。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, this is a test. Testing, 1, 2, test.";
// 从后往前查找子串"test"
size_t pos1 = str.rfind("test");
if (pos1 != string::npos)
{
cout << "Found 'test' from end at position: " << pos1 << endl;
}
else
{
cout << "'test' not found from end." << endl;
}
// 查找字符't',限制搜索范围
size_t pos2 = str.rfind('t', 20);
cout << "Last 't' before position 20 found at: " << pos2 << endl;
// 尝试查找不存在的子串
size_t pos3 = str.rfind("notfound");
if (pos3 == std::string::npos)
{
cout << "'notfound' not found from end in the string." << endl;
}
return 0;
}
代码结果:
string的比较
使用compare函数完成比较
函数原型及返回值意义:
int compare(const string& str) const; int compare(size_t pos1, size_t n1, const string& str) const; int compare(size_t pos1, size_t n1, const string& str, size_t pos2, size_t n2 = npos) const; int compare(const char* s) const; int compare(size_t pos1, size_t n1, const char* s) const; int compare(size_t pos1, size_t n1, const char* s, size_t n2) const;
返回值解释:
- 如果当前字符串小于比较的字符串,则返回负整数。
- 如果两者相等,则返回0。
- 如果当前字符串大于比较的字符串,则返回正整数。
比较整个字符串:
std::string str1 = "apple"; std::string str2 = "banana"; int result = str1.compare(str2);
如果
result < 0
,说明str1
在字典顺序上小于str2
;如果result > 0
,则str1
大于str2
;若result == 0
,两者相等。
比较子串:
std::string str1 = "pineapple"; std::string str2 = "apple"; int result = str1.compare(4, 5, str2); // 从str1的第4个字符开始,比较5个字符
这里比较的是"apple"与"apple",由于它们相等,返回值将是0。
比较与C风格字符串:
std::string str = "hello"; int result = str.compare("world");
比较"hello"与"world"。
指定长度的比较:
std::string str1 = "abcdef"; std::string str2 = "abcxyz"; int result = str1.compare(0, 3, str2, 0, 3); // 比较前3个字符
比较"abc"与"abc",结果为0,因为两者相同。
string的替换
使用replace函数完成string的替换
替换单个范围的子串:
string& replace(size_t pos, size_t len, const string& str);
- 从位置
pos
开始,替换长度为len
的子字符串为str
。
使用子串替换另一子串:
string& replace(size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);
- 同样从位置
pos
开始,替换长度为len
的子字符串,但是使用str
中的从subpos
开始长度为sublen
的子串进行替换。
用单个字符替换:
string& replace(size_t pos, size_t len, size_t n, char c);
- 从位置
pos
开始,替换长度为len
的子字符串为n
个字符c
。
迭代器范围替换:
string& replace(iterator i1, iterator i2, const string& str); string& replace(iterator i1, iterator i2, size_t n, char c);
- 使用迭代器
i1
和i2
指定的范围内的字符被str
或n
个字符c
替换。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, world! Welcome to the programming world.";
// 替换"world"为"universe"
size_t pos = str.find("world");
if (pos != string::npos)
{
str.replace(pos, 5, "universe");
}
cout << str << endl; // 输出: Hello, universe! Welcome to the programming world.
// 使用子串替换
pos = str.find("programming", pos);
if (pos != string::npos)
{
str.replace(pos, 11, "coding", 4, 4); // 取"coding"的前4个字符
}
cout << str << endl; // 输出: Hello, universe! Welcome to the coding world.
// 用字符替换
str.replace(0, 7, 5, '-');
cout << str << endl; // 输出: ----- universe! Welcome to the coding world.
return 0;
}
代码结果:
string的交换
使用swap函数完成两个string类的交换
函数原型:
void swap(string& other);
用法:
这个函数接受一个引用到另一个
std::string
对象作为参数,并直接交换两个字符串的内部数据结构,包括它们的字符缓冲区。交换后,两个字符串对象将包含对方之前的字符内容,但它们的容量和其它属性(如分配的内存大小)也会相应交换。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 = "Hello, World!";
string str2 = "Goodbye, World!";
cout << "Before swapping:\nstr1 = " << str1 << "\nstr2 = " << str2 << endl;
// 使用swap函数交换两个字符串的内容
str1.swap(str2);
cout << "After swapping:\nstr1 = " << str1 << "\nstr2 = " << str2 << endl;
return 0;
}
代码结果:
string的大小和容量
使用size函数或length函数获取当前有效字符的个数
size()函数:
- 原型:
size_t size() const;
- 功能:返回字符串中字符的数量。
- 备注:作为STL容器通用接口的一部分,它符合容器类的一般使用习惯。
length()函数:
- 原型:
size_t length() const;
- 功能:同样返回字符串中字符的数量。
- 备注:这个函数主要是为了兼容传统的C语言风格的字符串处理,如
strlen
函数,使得C++程序员在使用std::string
时能有熟悉的感觉。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
// 初始化一个字符串
string greeting = "Hello, World!";
// 使用size()函数获取字符串长度
cout << "The length of the string using size() is: " << greeting.size() << endl;
// 使用length()函数获取字符串长度
cout << "The length of the string using length() is: " << greeting.length() << endl;
return 0;
}
代码结果:
使用max_size函数获取string对象对多可包含的字符数
函数原型:
size_t max_size() const;
功能解释:
- 返回值:
max_size
函数返回size_type
类型的值,表示当前系统环境下std::string
对象理论上能存储的最大字符数量。size_type
是一个无符号整型,足以存储任何可能的字符串长度。- 用途:虽然通常情况下不会达到这个极限值,但它可以用来做边界检查,比如在动态分配或调整字符串大小之前,确保操作不会超出可能的容量限制。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cout << "The maximum size of a string on this system can be: " << str.max_size() << " characters." << endl;
return 0;
}
代码结果:
使用capacity函数获取当前对象所分配的存储空间的大小
函数原型:
size_type capacity() const noexcept;
功能说明:
- 返回值:返回当前字符串对象已分配的存储空间大小,以字符数量为单位。
size_type
是一个无符号整型,确保可以表示任何可能的容量值。- 目的:提供关于字符串内部存储管理的信息,帮助优化字符串操作,比如通过预先调整容量(
reserve()
函数)来避免自动增长导致的多次内存重分配。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str("Hello");
cout << "Current string: \"" << str << "\"\n";
cout << "Current capacity: " << str.capacity() << endl;
// 添加字符直到触发自动增长
while (str.capacity() == str.size())
{ // 这里仅为示例,实际上不会进入循环,因为capacity通常大于size
str += 'a';
cout << "Added a character. New capacity: " << str.capacity() << endl;
}
return 0;
}
代码结果:
使用resize改变当前对象的有效字符的个数
函数原型:
void resize(size_type n, char c = '\0');
参数说明:
n
:指定新的字符串长度。如果这个值大于当前长度,则字符串会被扩展,新添加的位置会被字符c
填充;如果这个值小于当前长度,则字符串会被截断到指定长度。c
:可选参数,默认值为\0
(空字符)。当扩展字符串时,如果指定了这个参数,新增的位置将被此字符填充;如果不指定或值为默认,则默认使用空字符填充。功能描述:
- 扩展字符串:如果
n
大于当前字符串的长度,resize
函数会在字符串末尾添加足够数量的字符c
,直到字符串长度达到n
。- 缩短字符串:如果
n
小于当前字符串的长度,resize
会直接截断字符串,从原字符串末尾移除多出的字符,直到长度为n
。- 调整容量:
resize
操作可能会影响到字符串的容量(即分配给字符串的内存空间),特别是当扩展字符串时,可能需要重新分配内存以容纳更多的字符。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello";
// 扩展字符串并在末尾填充'a'
str.resize(10, 'a');
cout << "After resizing to 10 with 'a': " << str << endl; // 输出: Helloaaaaaa
// 缩短字符串
str.resize(3);
cout << "After resizing to 3: " << str << endl; // 输出: Hel
return 0;
}
代码结果:
使用reserve改变当前对象的容量大小
函数原型:
void reserve(size_type n);
参数说明:
n
:指定要求的最小容量,即至少能存储n
个字符的内存空间。如果n
小于或等于当前的容量,则函数什么也不做。如果n
大于当前的容量,那么string
对象将尝试重新分配内存以满足新的容量需求。功能描述:
- 预防内存重分配:通过预先分配足够的内存,当后续通过插入操作增加字符串长度时,只要增加的长度不超过预留的容量,就不会发生内存重分配,从而提高了程序的效率。
- 不改变字符串内容:
reserve()
调用不会改变字符串的实际内容或长度,只影响其容量。- 内存分配策略:实现可能会根据特定的内存管理策略(如分配多于请求的内存以应对未来增长)来决定实际分配的内存大小,但这保证至少能满足
n
个字符的存储需求。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
// 预先分配能容纳100个字符的内存空间
str.reserve(100);
cout << "Initial capacity: " << str.capacity() << endl; // 显示初始容量
// 接着可以安全地执行一系列的插入操作,而不会频繁触发内存重分配
for (int i = 0; i < 100; ++i)
{
str.push_back('A' + (i % 26)); // 填充字母
}
cout << "After inserting characters, capacity: " << str.capacity() << endl; // 显示调整后的容量
cout << "Size after insertions: " << str.size() << endl; // 显示实际大小
return 0;
}
代码结果:
使用clear删除对象的内容,删除后对象变为空字符串
函数原型:
void clear() noexcept;
功能描述:
- 清空内容:调用
clear()
后,字符串中的所有字符都将被移除,字符串长度变为0。- 保留容量:虽然字符串变得为空,但它所占用的内存容量(即可以存储的字符数量而无需重新分配内存)通常保持不变。这意味着,再次添加字符时,直到达到原有容量之前,不会触发新的内存分配。
- 性能优势:由于不需要重新分配内存,对于频繁需要清空并重新填充内容的场景,使用
clear()
比反复创建新的字符串对象更为高效。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, World!";
cout << "Before clear: \"" << str << "\", Size: " << str.size() << ", Capacity: " << str.capacity() << endl;
str.clear();
cout << "After clear: \"" << str << "\", Size: " << str.size() << ", Capacity: " << str.capacity() << endl;
return 0;
}
代码结果:
使用empty判断对象是否为空
函数原型:
bool empty() const noexcept;
功能描述:
- 检查字符串状态:
empty()
函数不接受任何参数,它检查调用该函数的字符串对象是否为空。- 返回值:如果字符串长度为0,表示字符串为空,则返回
true
;如果字符串包含至少一个字符,则返回false
。- 常量成员函数:由于它被声明为
const
,这意味着它不会修改字符串对象的状态,只读取信息。
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 = "";
string str2 = "Hello";
if (str1.empty())
{
cout << "str1 is empty." << endl;
}
else
{
cout << "str1 is not empty." << endl;
}
if (str2.empty())
{
cout << "str2 is empty." << endl;
}
else
{
cout << "str2 is not empty." << endl;
}
return 0;
}
代码结果:
string中元素的访问
[ ]+下标
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "Hello, World!";
// 访问第一个字符
char firstChar = str[0];
cout << "First character: " << firstChar << endl; // 输出 H
// 访问最后一个字符
char lastChar = str[str.size() - 1];
cout << "Last character: " << lastChar << endl; // 输出 !
}
代码结果:
使用at访问对象中的元素
代码演示:
#include <iostream>
#include <string>
#include <stdexcept> // 引入此头文件以处理std::out_of_range异常
int main()
{
try {
std::string str = "Hello, World!";
// 安全地访问第一个字符
char firstChar = str.at(0);
std::cout << "First character: " << firstChar << std::endl; // 输出 H
// 尝试访问超出范围的字符,这将抛出异常
char invalidAccess = str.at(20); // 假设字符串没有这么长
std::cout << "Invalid access character: " << invalidAccess << std::endl;
}
catch (const std::out_of_range& e)
{
std::cerr << "Caught an out_of_range exception: " << e.what() << std::endl;
}
return 0;
}
代码结果:
使用范围for访问对象中的元素
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 使用范围for循环遍历字符串中的每个字符
for (char ch : str)
{
std::cout << ch << std::endl; // 分别打印每个字符
}
// 或者,如果你想在一行中打印整个字符串,不换行
std::cout << "Printing the string in one line: ";
for (char ch : str)
{
std::cout << ch;
}
std::cout << std::endl; // 在所有字符打印完成后换行
return 0;
}
代码结果:
使用迭代器访问对象中的元素
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 使用迭代器遍历字符串
for (std::string::iterator it = str.begin(); it != str.end(); ++it)
{
std::cout << *it << std::endl; // 打印每个字符
}
// 使用const_iterator进行只读遍历
for (std::string::const_iterator cit = str.cbegin(); cit != str.cend(); ++cit)
{
std::cout << *cit; // 同样打印每个字符,但明确表示不修改
}
std::cout << std::endl; // 在所有字符打印完成后换行
return 0;
}
代码结果:
string中运算符的使用
operator=
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
string s2("CSDN");
//支持string类的赋值
s1 = s2;
cout << s1 << endl; //CSDN
//支持字符串的赋值
s1 = "hello";
cout << s1 << endl; //hello
//支持字符的赋值
s1 = 'x';
cout << s1 << endl; //x
return 0;
}
代码结果:
operator+=
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
string s2("hello");
//支持string类的复合赋值
s1 += s2;
cout << s1 << endl; //hello
//支持字符串的复合赋值
s1 += " CSDN";
cout << s1 << endl; //hello CSDN
//支持字符的复合赋值
s1 += '!';
cout << s1 << endl; //hello CSDN!
return 0;
}
代码结果:
operator+
基本用法:
- 字符串与字符串相加
- 字符串与C风格字符串相加
- 字符串与字符相加
代码演示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
string s1("super");
string s2("man");
char str[] = "woman";
char ch = '!';
//string类 + string类
s = s1 + s2;
cout << s << endl; //superman
//string类 + 字符串
s = s1 + str;
cout << s << endl; //superwoman
//字符串 + string类
s = str + s1;
cout << s << endl; //womansuper
//string类 + 字符
s = s1 + ch;
cout << s << endl; //super!
//字符 + string类
s = ch + s1;
cout << s << endl; //!super
return 0;
}
代码结果:
operator>> 和 operator<<
operator<<
(插入运算符):
功能: 该运算符用于将数据插入到输出流中。最常见的用途是在
std::cout
上,用于打印变量的值或者字符串到控制台或其他输出设备。语法:
:std::cout << expression1 << expression2 ...;
示例:
int age = 25; std::string name = "Alice"; std::cout << "Name: " << name << ", Age: " << age << std::endl;
上述代码会输出:
Name: Alice, Age: 25
operator>>()
(提取运算符):
功能::该运算符用于从输入流中提取(读取)数据到变量中。最常用的输入流是
std::cin
,它通常用于接收用户键盘输入。语法:
:std::cin >> variable1 >> variable2 ...;
示例:
int number; std::string inputText; std::cout << "Enter an integer: "; std::cin >> number; std::cout << "Enter some text: "; std::cin >> inputText;
在上述代码中,程序首先提示用户输入一个整数,然后输入一段文本。
relational operators
等于 (
==
)
- 功能:检查两个字符串是否相等,即它们的字符序列完全相同。
- 示例:
if (str1 == str2) { /* 字符串str1和str2相等 */ }
不等于 (
!=
)
- 功能:检查两个字符串是否不相等。
- 示例:
if (str1 != str2) { /* 字符串str1和str2不相等 */ }
小于 (
<
)
- 功能:按照字典顺序,检查左边的字符串是否在右边的字符串之前。
- 示例:
if (str1 < str2) { /* 字符串str1在str2之前 */ }
大于 (
>
)
- 功能:按照字典顺序,检查左边的字符串是否在右边的字符串之后。
- 示例:
if (str1 > str2) { /* 字符串str1在str2之后 */ }
小于等于 (
<=
)
- 功能:检查左边的字符串是否在右边的字符串之前或与之相等。
- 示例:
if (str1 <= str2) { /* 字符串str1在str2之前或与之相等 */ }
大于等于 (
>=
)
- 功能:检查左边的字符串是否在右边的字符串之后或与之相等。
- 示例:
if (str1 >= str2) { /* 字符串str1在str2之后或与之相等 */ }
注意:这些运算符在比较字符串时,按照字符的ASCII(或Unicode)值逐个进行比较,首先是第一个字符,如果相同则继续比较下一个,直到找到不匹配的字符或一个字符串结束。
string中与迭代器相关的函数
与正向迭代器相关的函数
begin函数
函数原型:
iterator begin(); const_iterator begin() const;
功能说明:
非const版本:
begin()
返回一个迭代器,指向字符串的第一个字符。这个迭代器是可修改的,意味着你可以通过它来修改字符串的内容。const版本:在
const
上下文中(比如字符串为const std::string
类型或者被const
引用或指针引用),begin()
返回一个const_iterator
,它只能用于读取字符串内容,不能修改。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 遍历字符串
for (auto it = str.begin(); it != str.end(); ++it)
{
std::cout << *it; // 输出字符串中的每个字符
}
std::cout << std::endl;
// 在const上下文中的使用
const std::string constStr = "Example";
for (auto cit = constStr.begin(); cit != constStr.end(); ++cit)
{
std::cout << *cit; // 输出: Example
}
std::cout << std::endl;
return 0;
}
代码结果:
end函数
函数原型:
iterator end(); const_iterator end() const;
功能说明:
非const版本:返回一个迭代器,指向字符串的末端,可以用来检测遍历是否结束,但不应解引用此迭代器访问实际的字符。
const版本:在
const
上下文中,end()
返回一个const_iterator
,同样指向字符串末端,用于只读操作。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 遍历字符串
for (auto it = str.begin(); it != str.end(); ++it)
{
std::cout << *it; // 输出字符串中的每个字符
}
std::cout << std::endl;
// 在const上下文中的使用
const std::string constStr = "Example";
for (auto cit = constStr.begin(); cit != constStr.end(); ++cit)
{
std::cout << *cit; // 输出: Example
}
std::cout << std::endl;
return 0;
}
代码结果:
与反向迭代器相关的函数
rbegin函数
函数原型:
reverse_iterator rbegin(); const_reverse_iterator rbegin() const;
功能说明:
非const版本:返回一个反向迭代器,初始时指向字符串的最后一个字符。这个迭代器允许你从字符串的末尾向前遍历。
const版本:在
const
上下文中,rbegin()
返回一个const_reverse_iterator
,同样指向字符串的最后一个字符,但不允许修改字符串内容。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 反向遍历字符串
for (auto rit = str.rbegin(); rit != str.rend(); ++rit)
{
std::cout << *rit; // 逆序输出字符串中的每个字符
}
std::cout << std::endl;
// 在const上下文中的使用
const std::string constStr = "Example";
for (auto crit = constStr.rbegin(); crit != constStr.rend(); ++crit)
{
std::cout << *crit; // 逆序输出: !dlroW ,olleH
}
std::cout << std::endl;
return 0;
}
代码结果:
rend函数
函数原型:
reverse_iterator rend(); const_reverse_iterator rend() const;
功能说明:
非const版本:返回一个反向迭代器,逻辑上位于字符串的开始位置之前,用于标识反向遍历的终点。
const版本:在
const
上下文中,rend()
返回一个const_reverse_iterator
,同样位于开始位置之前,确保遍历时不可修改字符串。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 反向遍历字符串
for(auto rit = str.rbegin(); rit != str.rend(); ++rit)
{
std::cout << *rit; // 逆序输出字符串中的每个字符,直到遇到rend()
}
std::cout << std::endl;
// 在const上下文中的使用
const std::string constStr = "Example";
for(auto crit = constStr.rbegin(); crit != constStr.rend(); ++crit)
{
std::cout << *crit; // 类似地,逆序输出: !elpmaxE
}
std::cout << std::endl;
return 0;
}
代码结果:
string与字符串之间的转换
将字符串转换为string
#include <iostream>
#include <string>
using namespace std;
int main()
{
//方式一
string s1("hello world");
//方式二
char str[] = "hello world";
string s2(str);
cout << s1 << endl; //hello world
cout << s2 << endl; //hello world
return 0;
}
使用c_str或data将string转换为字符串
c_str():
- 功能:
c_str()
方法返回一个指向常量字符数组的指针,这个字符数组包含了std::string
对象的内容,末尾带有空字符\0
。这意味着返回的指针指向的数据是不可修改的。- 适用场景:当你需要将
std::string
传递给要求C字符串的API或者C库函数时(例如printf
),应使用c_str()
。因为这些函数期望字符串以\0
结尾,并且通常假设字符串是不可变的。data():
- 功能:
data()
方法同样返回一个指向字符数组的指针,该数组包含了字符串的内容,但直到C++11标准,data()
返回的指针是否以\0
结尾并未明确规定。从C++11开始,data()
保证了当字符串不是空字符串时,返回的指针指向的数组末尾也会有\0
。不过,与c_str()
不同的是,如果std::string
对象是可变的,通过data()
获得的指针指向的数据可能是可修改的。- 适用场景:当你只需要读取字符串内容而不需要确保字符串不可变,或者需要传递给接受
const char*
但不修改其内容的函数时,可以使用data()
。但在将字符串传递给可能修改其内容的C函数之前,应当谨慎,最好使用c_str()
或确保std::string
对象本身不可变。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, World!";
// 使用c_str()方法
const char* cStr = str.c_str();
std::cout << "Using c_str(): " << cStr << std::endl;
// 使用data()方法
const char* pData = str.data();
std::cout << "Using data(): " << pData << std::endl;
return 0;
}
代码结果:
string中子字符串的提取
使用substr函数提取string中的子字符串
函数原型:
std::string substr(size_type pos = 0, size_type n = npos) const;
参数说明:
- pos:子字符串开始提取的位置索引,默认为0,即字符串的起始位置。
- n:要提取的字符数量。如果省略或设置为
npos
(std::string::npos
表示最大可能值,通常用作结束标志),则提取从pos
开始到字符串结束的所有字符。返回值:
返回一个新的
std::string
对象,包含从原字符串中提取的子字符串。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string originalString = "Hello, World!";
// 提取从位置3开始的5个字符
std::string subStr1 = originalString.substr(3, 5);
std::cout << "Substring 1: " << subStr1 << std::endl; // 输出: lo, W
// 提取从位置7到字符串结束的子字符串
std::string subStr2 = originalString.substr(7);
std::cout << "Substring 2: " << subStr2 << std::endl; // 输出: World!
// 提取整个字符串(等效于pos=0, n=npos)
std::string subStr3 = originalString.substr();
std::cout << "Substring 3: " << subStr3 << std::endl; // 输出: Hello, World!
return 0;
}
代码结果:
使用copy函数将string的子字符串复制到字符数组中
代码演示:
#include <iostream>
#include <string>
#include <algorithm> // 包含std::copy
#include <iterator> // 包含std::begin, std::end
int main()
{
std::string str = "Hello, World!";
char charArray[10]; // 目标字符数组
// 使用substr获取子字符串
std::string subStr = str.substr(0, 5); // 获取前5个字符 "Hello"
// 使用std::copy将子字符串复制到字符数组
std::copy(subStr.begin(), subStr.end(), charArray);
// 确保字符串末尾加上空字符
charArray[subStr.size()] = '\0';
std::cout << "Copied substring: " << charArray << std::endl;
return 0;
}
代码结果:
string中的getline函数
函数原型:
std::istream& getline(std::istream& is, std::string& str, char delim = '\n');
参数说明:
- is:输入流对象,通常为
std::cin
,但也可以是其他输入流对象,如文件流std::ifstream
。- str:
std::string
对象的引用,用于存储读取到的行内容。- delim:可选参数,指定的分隔符,默认为
\n
(换行符)。读取会停止于该分隔符,但分隔符本身不会被存储在字符串中。
代码演示:
#include <iostream>
#include <string>
int main()
{
std::string userInput;
std::cout << "请输入一行文本: ";
// 读取整行文本直到遇到换行符
std::getline(std::cin, userInput);
std::cout << "你输入的是: " << userInput << std::endl;
// 另一个例子,使用自定义分隔符
std::cout << "使用自定义分隔符读取(以#结束): ";
std::getline(std::cin, userInput, '#');
std::cout << "你输入的是: " << userInput << std::endl;
return 0;
}
代码演示: