C++ 中string的用法
1.6.1 string类概述
string 是 C++ 标准库(STL)提供的字符串处理类,封装了字符串的存储、修改、查找等功
能,相⽐传统的 char[] (C ⻛格字符串),具有⾃动内存管理、丰富的成员函数、类型安全等优
势,是⽇常开发中处理字符串的⾸选⼯具。
今天围绕 string 核⼼⽤法展开,结合代码⽰例解析关键功能,覆盖初始化、转换、输⼊输出、容量、控制、修改、查找、⽐较等场景。
1.6.2 string的初始化与赋值
string 提供多种初始化⽅式,赋值操作也⽀持不同类型的右值,灵活性⾼。
1.6.2.1 初始化⽅式(4 种核⼼场景)
void func(int a, int b = 20){...}
void func(int a){...}
void main()
{
// func(10); // 错误:编译器无法确定调用哪个(产生歧义)
}
字⾯量初始化
string
str1("hello");
⽤ C ⻛格字符串(const char*)初始化
拷⻉初始化(构 造)
string str2(str1); ⽤另⼀个 string 对象拷⻉创建(调⽤拷⻉构造函数)赋值初始化
string str3 = str1; 等价于拷⻉初始化,语法糖形式直接赋值字⾯量
string str4 = "world"; ⽤ C ⻛格字符串直接赋值初始化
1.6.2.2 赋值操作
初始化后可通过 = 重新赋值,⽀持两种赋值源:
注意:赋值会覆盖原字符串内容,且string会⾃动管理内存(⽆需⼿动释放旧内容)
1.6.3 string与char*的转换
C++中部分场景需要 char* 类型(如 printf 、C语⾔接⼝),string提供 c_str() 实现转换。
// string初始化
string str;
string str2 = "world"; // world
// 用另一个string对象赋值
str = str2; // world
// 用c风格字符串复制
str = "123123";
1.6.3.1 核⼼⽅法:c_str()
功能:返回⼀个指向string内部字符数组的 const char* 指针,该数组以 \0 结尾(兼容C⻛格字符串)
代码⽰例:
关键注意事项:
1. 返回值是 const char* ,禁⽌强制转换为 char* 后修改内容,否则会触发[未定义⾏ 为](如内存错误)。
❌ 错误⽰例:
(破坏 string 内部结构)。
2. 指针有效期:仅在 string 对象未被修改(如 append / erase )且未被销毁时有效。若 string 被修改,指针可能失效(内存重新分配)。
1.6.4 string的输⼊与输出
string⽀持C++标准IO流( cin/cout ),但需要注意输⼊的分隔符特性。
#include <iostream>
#include <cstdio>
string str3("yueqian");
const char* ptr = str3.c_str();
printf("%s\n",ptr);
char* ptr = (char*)str.c_str(); ptr[0] = 'a';
1.6.4.1 输出:cout << string
直接通过 cout 输出,⽆需处理 \0 ,简洁直观:
1.6.4.2 输⼊:cin >> string于getline
① cin >> string:默认分隔符输⼊
规则:以(空格、制表符、换⾏符)为分隔符,仅读取第⼀个分隔符前的内容。
⽰例:
② getline(cin,string):整⾏输⼊
场景:需要读取包含空格的整⾏字符串
⽰例:
注意:若 getline 前使⽤过 cin >> , cin 会将换⾏符留在输⼊缓冲区,导致 getline 读取空串,需⽤ cin.ignore() 清除缓冲区。
string str("hello string");
cout << str << endl; // 输出:hello string
string str;
cin >> str; // 若输入:“hello world”, str仅存储 hello
cout << str << endl; // 输出:hello
string str;
cin.ignore(); // 若之前用了cin >> 需要清除缓冲区残留的换行符。类似于c语言中的
while(getchar() != '\n')
getline(cin, str); // 若输入:“hello world”, str存储 hello world
返回值
size() 返回字符串有效字符个数(不 含 '\0')str.size()
length () 与 size() 完全等价(历史兼 容接⼝)
str.length()
capacity() 返回当前内存可容纳的最⼤字 符数(不扩容)
str.capacity()
max_size()返回理论最⼤可容纳字符数(系统 / 编译器限制)
str.max_size()
约 2^31-1(32位系统)
empty() 判断是否为空(size() == 0),返回 bool
str.empty()
false
clear( )
清空有效字符(size() 置0,不释放内存)
str.clear();
str.size()
1.6.5 string的容量与状态查询
string 提供多个成员函数查询和控制容量,核⼼包括 size() / length() 、 capacity() 、 max_
size() 、 empty() 、 clear() 。
1.6.5.1 核⼼容量函数对⽐
1.6.5.2 关键概念辨析【扩展】
Size vs capacity:
size :实际使⽤的字符数(⽤⼾关⼼的 “⻓度”)。
capacity :当前内存已分配的空间(避免频繁扩容),当 size 超过 capacity 时,
string 会⾃动扩容(通常扩容为原容量的 1.5 倍或 2 倍)。
clear () 不释放内存: clear() 仅将 size() 设为 0, capacity() 不变,若需释放内存,可结合 shrink_to_fit() (C++11+):
1.6.6 string的修改操作
string 提供 erase() 、 replace() 、 swap() 等成员函数修改内容,覆盖删除、替换、交换场 景。
1.6.6.1 删除字符:erase(pos, count)
功能:从索引 pos (0开始)处,删除 count 个字符。
代码⽰例:
重载版本:还⽀持通过迭代器删除单个字符(如 str.erase(str.begin() + 2) 删除索引2的字符)
1.6.6.2 替换字符:replace(pos, count, new_str)
功能:从索引 pos 处,删除 count 个字符,再插⼊ new_str ( new_str ⻓度可与 count 不同)。
string str("123456");
str.clear(); // size=0, capacity=6
str.shrink_to_fit(); // capacity 变为 0(释放内存)
string str4("0123456789abcdef");
cout << str4 << endl;
cout << "size = " << str4.size() << ",capacity = " << str4.capacity() <<
endl; // size = 16,capacity = 16
str4.erase(4,8); // 从索引4开始连续删除8个字符
cout << str4 << endl;
cout << "size = " << str4.size() << ",capacity = " << str4.capacity() <<
endl; // size = 8,capacity = 16
1.6.6.3 交换字符串:swap(s1,s2)
功能:交换两个 string 对象的内容,效率极⾼(仅交换内部指针和容量,不拷⻉数据)。
代码⽰例:
1.6.7 string的查找与截取
string 提供 find() 、 find_last_of() 等查找函数,以及 substr() 截取⼦串,满⾜字符串检索需求。
1.6.7.1 查找函数:find() 与 find_last_of()
(1)find(sub_str, pos = 0):正向查找
功能:从索引 pos (默认 0)开始,查找 sub_str (完整匹配)第⼀次出现的位置,返回索引;未找到返回 string::npos (静态常量,表⽰⽆效位置)。
// 替换
string str5("0123456789abcdef");
cout << "替换前:" << str5 << endl; // 替换前:0123456789abcdef
str5.replace(3,8,"HELLOWORLD"); // 替换后:012HELLOWORLDbcdef
cout << "替换后:" << str5 << endl;
string s1("郭德纲");
string s2("于谦");
cout << "交换前:" << s1 << "," << s2 << endl;
swap(s1,s2); // 第1种写法
cout << "交换后:" << s1 << "," << s2 << endl;
s1.swap(s2); // 第2种写法
cout << "交换后:" << s1 << "," << s2 << endl;
(2)find_last_of(sub_str):反向查找字符集
功能:查找 sub_str 中任意⼀个字符最后⼀次出现的位置(⾮完整匹配,⽽是字符集匹配)。
1.6.7.2 截取⼦串:substr(pos, count = string::npos)
功能:从索引 pos 开始,截取 count 个字符;若 count 未指定或超过剩余字符数,截取
到字符串末尾。
代码⽰例:
// 正向查找,返回第一次出现的位置
string s3("invaid conversion from 'const char*' to 'char*'");
// 1. 从头开始开始查找 from
cout << s3.find("from") << endl; // 找到返回第一次出现的索引,找不到返回-1
// 2. 从指定索引位置开始查找 from
cout << s3.find("from", 18) << endl;
// 3. 判断是否找到
if (s3.find("test") != string::npos)
{
cout << "找到 test" << endl;
}
else
{
cout << "未找到 test" << endl;
}
string str("from 123 from 456");
cout << str.find_last_of("from"); // 找 'f'/'r'/'o'/'m' 最后出现的位置,输
出 12(第二个 "from" 的 'm')
注意:若 pos 超过 size() ,会抛出 out_of_range 异常,需确保 pos 合法。
1.6.8 string的连接与⽐较
字符串的连接和⽐较是⾼频操作,string⽀持运算符重载与成员函数两种⽅式。
1.6.8.1 字符串连接
① +运算符:创建新字符串
功能:连接两个字符串,返回新的string对象(原对象不变)
代码⽰例:
缺点:会创建临时对象,频繁连接时效率较低。
② append() 成员函数:原地追加
// 字符串截取
string s4 = "0123456789abcdef";
// 从索引10开始,截取5个字符
string sub = s4.substr(s4.find("a"),5);
cout << sub << endl; // 输出:abcde
// 从索引12开始,截取到末尾
string sub2 = s4.substr(12);
cout << sub2 << endl; // 输出:cdef
// + 字符串拼接
string ss1("西安");
string ss2("粤嵌科技");
string ss3 = ss1 + ss2;
string sa = "a", sb = "b", sc = "c";
cout << ss3 << " " << (ss1 + ss2) << endl; // 输出:西安粤嵌科技 西安粤嵌科技
cout << (sa + sb + sc) << endl;
功能:在当前字符串末尾追加内容,直接修改原对象(⽆临时对象,效率⾼)
代码⽰例:
1.6.8.2 字符串⽐较
① 运算符重载:直观简洁
⽀持 == 、 != 、 < 、 > 、 <= 、 >= ,按字典序(ASCII 码) ⽐较:
② compare()成员函数:灵活精细
功能:返回整数, 0 表⽰相等, 正数 表⽰当前字符串⼤, 负数 表⽰当前字符串⼩。
代码⽰例:
// append追加
string s11("0123456789abcdef");
string s12("1234");
cout << "追加前:" << s11 << "的大小是:" << s11.size() << "," << s12 << "的
大小是:" << s12.size() << endl;
cout << "追加前容量:" << s11.capacity() << endl;
s11.append(s12);
cout << "追加后:" << s11 << "的大小是:" << s11.size() << "," << s12 << "的
大小是:" << s12.size() << endl;
cout << "追加后容量:" << s11.capacity() << endl; // 容器超出后,采用二倍扩容
法
// 关系运算符比较
string s21("abc");
string s22("abc");
cout << (s21 == s22) << endl; // 0-不相等,1-相等
cout << (s21 < s22) << endl; // 0-不成立,1-成立
cout << (s21 >= "abd") << endl; // 0-不成立,1-成立
// compare()比较
string s31("abcdef");
string s32("abc123");
// 1. 完整比较
cout << s31.compare(s32) << endl; // 0-相等,大于0-大于,小于0-小于
// 2. 比较子串:s31的前3个字符 vs s32的前三个字符
cout << s31.compare(0,3,s32,0,3) << endl;
