一、string基本概念
string
是C++STL中的字符串容器。本质上是一个封装了char*
的动态字符串类 ,管理堆区分配的字符串数组,提供一系列字符串操作方法。
在底层,std::string
维护了几个重要成员:
char*
指针(指向存储字符串的动态数组)- 长度
size_t size
(字符串的当前大小) - 容量
size_t capacity
(字符串当前分配的最大空间) - 字符存储区(在堆区分配的存储空间)
特点
- 自动管理内存
- 动态扩展
- 提供丰富的成员函数
- 兼容C风格字符串
- STL兼容性
二、string构造函数
1. 默认构造(空字符串)
创建一个空字符串,长度为0,但仍可以动态扩展。
cpp
std::string str;
std::cout << "空字符串:\"" << str << "\"" << std::endl;
输出内容:

2. C风格字符串构造
直接使用C语言的const char*(char[])
初始化std::string
cpp
std::string str1("Hello,World!");
std::cout << "字符串:" << str1 << std::endl;
输出内容:

3. 拷贝构造
用已有的std::string
创建新字符串,内容完全相同。
cpp
std::string str1("Hello,World!");
string str2(str1);
cout << "拷贝构造:" << str2 << endl;
输出内容:

4.指定长度的字符串构造
使用char*
创建字符串,但只取前n个字符。
cpp
string str3("Hello,World!", 5);
cout << "部分截取:" << str3 << endl;
输出内容:

5. 重复字符构造
使用n个相同字符初始化string
。
cpp
string str4(10, 'A');
cout << "重复字符:" << str4 << endl;
输出内容:

6. 迭代器构造(从容器中取一部分字符串)
使用迭代器从original
中截取部分内容。
cpp
string original = "ABCDEFG";
string str5(original.begin() + 2, original.begin() + 5);
cout << "部分字符串:" << str5 << endl;
输出内容:

7. 移动构造
std::move
允许std::string
进行资源转移。
cpp
string tempVar = "Hello";
string str6 = move(tempVar);
cout << "移动后的tempVar:" << tempVar << endl;
cout << "移动到str6:" << str6 << endl;
输出内容:

三、string赋值操作
常见的赋值操作包括:
operator =
赋值运算符assign()
赋值函数
1. 赋值运算符operator=
可以将字符串赋值给string
对象,有几种不同的情况:
(1) 直接赋值C风格字符(char*)
将C风格字符串"Hello,World!"
赋值给string
。
cpp
string str;
str = "Hello,World!";
cout << str << endl;
输出内容:

(2) 赋值给另一个string
str2
拷贝str1
的内容,不会影响str1
。
cpp
string str1 = "Hello";
string str2;
str2 = str1;
cout << str2 << endl;
输出内容:

(3) 赋值单个字符
string
支持单个字符赋值(char a='A'
),它会被自动转换string("A")
。
cpp
string str3;
str3 = 'A';
cout << str3 << endl;
输出内容:

(4) 使用move()进行移动赋值
将str4
的数据转移到str5
,避免拷贝,提高效率。
cpp
string str4 = "Hello";
string str5;
str5 = move(str4);
cout << "str4: " << str4 << endl; // str1 变为空
cout << "str5: " << str5 << endl; // str2 获得 "Hello"
输出内容:

2. assign()赋值函数
assign()
是string
专门提供的赋值函数,可以灵活地从字符串 、字符 、迭代器范围等方式进行赋值。
(1) 赋值C风格字符串
assign()
作用和operator =
一样,但更灵活。
cpp
string str;
str.assign("Hello,World!");
cout << str << endl;
输出内容:

(2) 赋值部分C风格字符串
从char*
开头取n
个字符赋值。
cpp
string str1;
str.assign("Hello,World!", 5);
cout << str1 << endl;
输出内容:

(3) 赋值另一个string
等价于str4=str3
。
cpp
string str3 = "Hello";
string str4;
str4.assign(str3);
cout << str4 << endl;
输出内容:

#### (4) 赋值重复字符
创建5个'A'组成的字符串。
```cpp
string str5;
str5.assign(5, 'A');
cout << str5 << endl;
输出内容:

(5) 赋值迭代器范围
使用迭代器范围截取部分字符串赋值。
cpp
string str6 = "ABCDEFG";
string str7;
str7.assign(str6.begin() + 2, str6.begin() + 5);
cout << str7 << endl;
输出内容:

assign()函数原型
cpp
string& assign(const string & str); // 赋值另一个 string
string& assign(const string & str, size_t pos, size_t len = npos); // 截取部分赋值
string& assign(const char* s); // 赋值 C 风格字符串
string& assign(const char* s, size_t n); // 取 C 字符串的前 n 个字符
string& assign(size_t n, char c); // 赋值 n 个字符 c
template <class InputIterator>
string& assign(InputIterator first, InputIterator last); // 迭代器范围赋值
四、 string字符串拼接
在C++string容器中,字符串拼接有多种方式,主要包括:
- 使用
+
运算符 - 使用
+=
运算符 - 使用
append()
函数
1.使用+运算符
+
用于拼接两个字符串,可以拼接string
和char*
,但不能char
和string
直接相加。
示例:
cpp
string str1 = "I";
string str2 = " love";
string result1 = str1 + str2; //拼接两个字符串
cout << result1 << endl;
string result2 = result1 + " you!";//拼接string和C字符串
cout << result2 << endl;
输出结果:

注意:string
不能直接拼接单个字符。
错误示例:
cpp
string result3 = "Hello" + 'A';
cout << result3 << endl;
输出结果:

为什么?这是因为代码中存在类型不匹配和指针运算(指针偏移)问题。
问题分析:
"Hello"
的类型:"Hello"
是一个C风格字符串(const char*
类型)。'A'
的类型:'A'
是一个字符(char
类型),其ASCll值为65。"Hello"+'A'
实际上等价于:const char* ptr ="Hello"+65
;
也就是说,它让"Hello"
的指针向后移动了65个字节,但"Hello"
实际上只有6个字节(包括\0
),因此访问到了随机的内存地址,导致了未定义行为(可能输出Fancyptr
或者是其他的值,也可能崩溃)
正确做法:
string result3 =string("Hello")+'A';
//显示转换为string再拼接
或者
string result3 = "Hello"+string(1,'A');
//先把'A'变成string再拼接
2.使用+=运算符
+=直接在原字符串上追加内容,可以拼接string
、char*
和char
。
示例:
cpp
string str = "Closed off";
str += " from love"; //拼接C风格字符串
cout << str << endl;
str += '!';//追加单个字符
cout << str << endl;
输出内容:

注意事项:不能拼接数字类型。
错误示范:str += 123;
那么会输出什么?

为什么会输出一个'{'?
关键问题:
123是整数(int
),但string
的operator+=
没有定义直接接收int
作为参数。因此,C++
试图找到一个兼容的重载,但没有匹配的string::operator+=(int)
。隐式转换发生了,int
被转换成char
,而char(123)
的ASCll码对应的字符是'{
'。
正确做法:
str += to_string(123);
//先转换为字符串
输出内容:
不要忘记头文件#include<string>
3.使用append()函数
append()
适用于更复杂的拼接需求,支持拼接部分字符串、指定数量字符等。
追加整个字符串
cpp
string str = "I didn't";
str.append(" need the pain");
cout << str << endl;
输出内容:
- 追加部分字符串
cpp
string str1 = "Once or twice";
str1.append(" was enough and", 11);//只追加前11个字符
cout << str1 << endl;
输出内容:
- 追加重复字符
cpp
string str2 = "and it was all vain";
str2.append(3, '!');//追加3个'!'
cout << str2 << endl;
输出内容:
- 追加另一个string的部分内容
cpp
string str3 = "Time starts to";
string str4 = " pass before";
str3.append(str4, 0, 5);//追加str4的前5个字符
cout << str3 << endl;
输出内容:

string::append()函数原型
cpp
string& append(const string & str); // 追加整个字符串
string& append(const string & str, size_t subpos, size_t sublen); // 追加 str 的一部分
string& append(const char* s); // 追加 C 风格字符串
string& append(const char* s, size_t n); // 追加 C 字符串前 n 个字符
string& append(size_t n, char c); // 追加 n 个字符 c
template <class InputIterator>
string& append(InputIterator first, InputIterator last); // 追加迭代器范围内容
五、 string查找和替换
在C++string容器中,我们可以使用一系列成员函数来查找子字符串的位置,并进行替换。
1.find()--查找子字符串
find()
用于查找子字符串在当前string
对象中的起始位置。
函数原型
cpp
size_t find(const string & str, size_t pos = 0) const;
size_t find(const char* s, size_t pos = 0) const;
size_t find(char ch, size_t pos = 0) const;
str/s
:要查找的字符串或字符
pos
:从字符串的pos位置 开始查找(默认为0)
返回值:
- 找到:返回子串第一个匹配字符的索引
- 未找到:返回
string::npos
示例
cpp
string str = "Before you know it you're frozen";
//查找子字符串"know"
size_t pos = str.find("know");
if (pos != string::npos)
cout << "找到\"know\",位置:" << pos << endl;
else
cout << "未找到\"know\"" << endl;
//查找字符'o',从索引5开始查找
pos = str.find('o', 5);
cout << "找到'o',位置:" << pos << endl;
输出结果

在上述例子有看到使用的类型是size_t,那么这个是否可以替换为int?那就要先说一说它们之间的区别:
size_t
是无符号整数类型,通常表示内存大小、数值索引等非负值。int
是有符合整数,可以存储负数、范围更小。
那么可以替换吗?
也不建议。虽然在小型程序中,如果没有太大的字符串(最大索引不超过int
范围),那么可能不会导致错误。如果找到了,那没什么问题,但若没找到,find()
函数返回的是std::string::npos
,是一个特殊的常量,它的类型是size_t
,通常是一个非常大的无符号整数,在32为系统通常是(2^32-1),其二进制表示与-1的二进制补码相同。那么如果用int
回被表示成-1。在64位系统,如果赋值给int,会导致溢出,结果是未定义的。
2. rfind()--逆向查找
与find()
相同,但从字符串的末尾向前查找,返回最后一次出现的位置。
示例
cpp
string str1 = "But something";
size_t pos1 = str1.rfind('n');
cout << "最后一次'n'出现的位置:" << pos1 << endl;
输出

3.find_first_of()--查找多个字符中的第一个匹配项
查找字符串中任意一个字符首次出现的位置
示例
cpp
string str2 = "happened for";
size_t pos2 = str2.find_first_of("pe");
cout << "字符 'p' 或 'e' 第一次出现的位置:" << pos2 << endl;
输出

4.find_last_of()--逆向查找多个字符
查找字符串中任意一个字符最后一次出现的位置。
示例
cpp
string str3 = "the very firt time with you";
size_t pos3 = str.find_first_of("ry");
cout<<"字符 'r' 或 'y' 最后一次出现的位置: " << pos3 << endl;
输出

5. replace()--替换子字符串
可以用新字符串替换已有字符串的某部分。
函数原型
cpp
string& replace(size_t pos, size_t len, const string & str);
string& replace(size_t pos, size_t len, const char* s);
pos
:要替换的起始位置len
:要替换的长度str/s
:用于替换的新字符串
示例
cpp
string str4 = "My liver melted to the ground";
//替换"liver"为"heart"
str4.replace(str4.find("liver"), 5, "heart");
cout << str4 << endl;
输出

6. erase()--删除子字符串
可以删除string中的某部分内容
函数原型
cpp
string& erase(size_t pos = 0, size_t len = npos);
pos
:删除的起始位置len
:删除的字符数(默认为npos,即删除到末尾)
示例
cpp
string str5 = "Founddd something true";
str5.erase(5, 2);
cout << str5 << endl;
输出

六、string字符串比较
在C++中,string
提供了多种比较方式。主要比较方式包括:
- 使用==、!=、<、>等运算符
- 使用
compare()
函数进行字符串比较
1.运算符比较
C++string
类重载了"==、!=、<、>、<=、>="这些运算符,比较方式如下:
- 按ASCll码顺序逐字符比较
- 若某个字符不同,则比较ASCll码的大小
- 若前缀相同,则短字符串小于长字符串。
示例
cpp
//运算符比较
string str1 = "apple";
string str2 = "banana";
string str3 = "apple";
//比较相等
cout << (str1 == str2) << endl; //0(false)
cout << (str1 == str3) << endl; //1(true)
//比较不相等
cout << (str1 != str2) << endl; //1(true)
//大小比较(按ASCll码表顺序)
cout << (str1 < str2) << endl; //1(true)
cout << (str1 > str2) << endl; //0(false)
输出
2. compare()方法
string::compare()
方法提供了更灵活的字符串比较,它返回一个整数值:
0
:两个字符串相等<0
:当前字符串小于目标字符串>0
:当前字符串大于目标字符串
compare()语法:
cpp
int compare(const string & str) const;
int compare(size_t pos, size_t len, const string & str) const;
int compare(size_t pos, size_t len, const string & str, size_t subpos, size_t sublen) const;
1. 直接比较两个字符串:
cpp
string str4 = "stand";
string str5 = "apart";
string str6 = "stand";
cout << str4.compare(str5) << endl;//正数
cout << str4.compare(str6) << endl;//0
cout << str5.compare(str4) << endl;//负数
输出

2.只比较字符串的一部分
cpp
string str7 = "abcdef";
string str8 = "cde";
// 比较 str7[2] 开始的3个字符 ("cde") 和 str8 ("cde")
cout << str7.compare(2, 3, str8) << endl; // 0,相等
// 比较 str7[2] 开始的3个字符 ("cde") 和 "cdf"
cout << str7.compare(2, 3, "cdf") << endl; // 负数,因为 'e' < 'f'
输出

七、string字符串访问和修改
1.访问字符串中的字符
1.使用[ ]下标访问
string
允许像数组一样使用[ ]访问字符:
cpp
string str = "parse";
cout << str[0] << endl; //p
cout << str[4] << endl; //e
输出
[]
不会进行范围检查,如果访问超出范围,可能会导致未定义行为。
2.使用at()方法
at()
方法与[]
类似,但它会检查索引是否超出范围,如果超出,则抛出out_of_range
异常。
cpp
string str = "parse";
cout << str.at(1) << endl;//a
cout << str.at(10) << endl;//抛出异常
输出

异常:_Xout_of_range("invalid string position");
3.访问首尾字符
cpp
string str = "parse";
cout << "首字符:" << str.front() << endl;
cout << "尾字符:" << str.back() << endl;
输出

2.修改字符串
使用[]
或at()
修改字符。
cpp
string str = "parse";
str[0] = 'H';//修改第一个字符
str.at(4) = 'h';//使用at()修改
cout << str << endl;
输出

八、 string插入和删除
1.插入字符
insert(pos,string)
insert(pos,string)
方法用于在pos
位置插入字符串:
cpp
string str = "thoug";
str.insert(5, "ht");//在索引5处插入"ht"
cout << str << endl;
输出
insert(pos,n,char)
在pos
位置插入n个相同字符:
cpp
string str = "thought";
str.insert(7, 3, '!');
cout << str << endl;
输出

2.删除字符
erase(pos,len)
从pos
开始删除len
个字符:
cpp
string str1 = "Just do it";
str1.erase(4, 6);//从索引4开始删除6个字符
cout << str1 << endl;
输出
pop_back()
删除字符串的最后一个字符:
cpp
string str2 = "Just do it!";
str.pop_back();//删除最后一个字符
cout << str << endl;
输出

九、获取string子串
1.substr()
方法
函数原型:
cpp
string substr(size_t pos = 0, size_t len = npos) const;
pos
:子串的起始位置len
:要截取的字符数量(默认npos
表示截取到末尾)- 返回值:返回指定范围的新字符串,不会修改原字符串
2.substr()基本用法
示例1:获取指定范围的子串
cpp
string str = "Hello, World!";
string sub1 = str.substr(7, 5); //从索引7开始,截取5个字符
cout << sub1 << endl; //World
输出
示例2:截取从某个位置到结尾的子串
如果不提供len
,则默认从pos
开始一直截取到字符串末尾。
cpp
string str = "C++ STL is powerful";
string sub2 = str.substr(6); //从索引6开始,一直到末尾
cout << sub2 << endl; //STL is powerful
输出
示例3:获取整个字符串(等于拷贝)
如果pos =0
,且len = npos
,等价于复制整个字符串:
cpp
string str = "Hello,C++!";
string copy_str = str.substr(); //复制整个字符串
cout << copy_str << endl;
输出

3.substr()
与find()
结合使用
可以先使用find()
定位子串的位置,再用substr()
提取。
cpp
string str = "Welcome to C++ programming";
//找到C++在字符串中的位置
size_t pos = str.find("C++");
//提取"C++"及后面的内容
string sub = str.substr(pos);
cout << sub << endl;
输出
十、原型
cpp
// <string> Forward declarations -*- C++ -*-
// Copyright (C) 2001-2023 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file bits/stringfwd.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{string}
*/
//
// ISO C++ 14882: 21 Strings library
//
#ifndef _STRINGFWD_H
#define _STRINGFWD_H 1
#pragma GCC system_header
#include <bits/c++config.h>
#include <bits/memoryfwd.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
* @defgroup strings Strings
*
* @{
*/
template<class _CharT>
struct char_traits;
template<> struct char_traits<char>;
template<> struct char_traits<wchar_t>;
#ifdef _GLIBCXX_USE_CHAR8_T
template<> struct char_traits<char8_t>;
#endif
#if __cplusplus >= 201103L
template<> struct char_traits<char16_t>;
template<> struct char_traits<char32_t>;
#endif
_GLIBCXX_BEGIN_NAMESPACE_CXX11
template<typename _CharT, typename _Traits = char_traits<_CharT>,
typename _Alloc = allocator<_CharT> >
class basic_string;
_GLIBCXX_END_NAMESPACE_CXX11
/// A string of @c char
typedef basic_string<char> string;
/// A string of @c wchar_t
typedef basic_string<wchar_t> wstring;
#ifdef _GLIBCXX_USE_CHAR8_T
/// A string of @c char8_t
typedef basic_string<char8_t> u8string;
#endif
#if __cplusplus >= 201103L
/// A string of @c char16_t
typedef basic_string<char16_t> u16string;
/// A string of @c char32_t
typedef basic_string<char32_t> u32string;
#endif
/** @} */
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // _STRINGFWD_H