ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

C++参悟:标准字符串string

2026/8/18 12:28:50 拓冰建站 浏览量
C++参悟:标准字符串string

标准字符串string

  • 一、概述
  • 二、函数
    • 1. 构造函数
    • 2. 数值转换
      • 1. 转换字符串为有符号整数
      • 2. 转换字符串为无符号整数
      • 3. 转换字符串为浮点值
      • 4. 数值转字符串
      • 5. 异常处理
    • 3. 范围访问
    • 4. 迭代器
    • 5. 容量
    • 6. 操作
    • 7. 查找
    • 8. 字面量

一、概述

C++为我们提供了非常多的字符串,标准字符串 string 就是用的 char 作为 basic_string的 模板参数形成的一个字符串。

模板类 std::basic_string 通用化了,字符序列如何操作、存储、创建及析构全部的类方法与相关函数。

标准提供 std::basic_string 对常用类型的数种特化:

在 <string> 头文件中 有如下的定义 ,string 其实就是用的basic_string的模板。下面的基本上所有讨论都是基于basic_string.这里讨论的 C11标准

typedef std::basic_string<char>  std::string;   
typedef std::basic_string<wchar_t> std::wstring 
typedef std::basic_string<char16_t>  std::u16string 
typedef std::basic_string<char32_t>  std::u32string

想如果要在字符串使用中文的话或者其他语言字符串,就得使用 wstring才行,因为ASCII只有英文的字符。

二、函数

1. 构造函数

下面是几种最常用的构造函数例子

#include <iostream>
#include <cassert>
#include <iterator>
#include <string>
#include <cctype>int main()
{// 1. string::string()std::string s;assert(s.empty() && (s.length() == 0) && (s.size() == 0));// 2. string::string(size_type count, charT ch)std::string s(4, '=');std::cout << s << '\n'; // "===="std::string const other("Exemplary");// 3. string::string(string const& other, size_type pos, size_type count)std::string s(other, 0, other.length()-1);std::cout << s << '\n'; // "Exemplar"// 4. string::string(charT const* s, size_type count)std::string s("C-style string", 7);std::cout << s << '\n'; // "C-style"// 5. string::string(charT const* s)std::string s("C-style\0string");std::cout << s << '\n'; // "C-style"char mutable_c_str[] = "another C-style string";// 6. string::string(InputIt first, InputIt last)std::string s(std::begin(mutable_c_str)+8, std::end(mutable_c_str)-1);std::cout << s << '\n'; // "C-style string"std::string const other("Exemplar");std::string s(other);std::cout << s << '\n'; // "Exemplar"// 7. string::string(string&& str)std::string s(std::string("C++ by ") + std::string("example"));std::cout << s << '\n'; // "C++ by example"// 8. string(std::initializer_list<charT> ilist)std::string s({ 'C', '-', 's', 't', 'y', 'l', 'e' });std::cout << s << '\n'; // "C-style"// 9. 重载决议选择 string(InputIt first, InputIt last) [with InputIt = int]// 这表现为如同调用 string(size_type count, charT ch)std::string s(3, std::toupper('a'));std::cout << s << '\n'; // "AAA"
}// 输出:
====
Exemplar
C-style
C-style
C-style string
Exemplar
C++ by example
C-style
AAA

2. 数值转换

数值转换主要就是字符串转换为整数、浮点数之类的。以及从浮点数转为字符串。

1. 转换字符串为有符号整数

会使用如下3个函数:

int       stoi( const std::string& str, std::size_t* pos = 0, int base = 10 );
int       stoi( const std::wstring& str, std::size_t* pos = 0, int base = 10 );long      stol( const std::string& str, std::size_t* pos = 0, int base = 10 );
long      stol( const std::wstring& str, std::size_t* pos = 0, int base = 10 );long long stoll( const std::string& str, std::size_t* pos = 0, int base = 10 );
long long stoll( const std::wstring& str, std::size_t* pos = 0, int base = 10 ); 

参数的解释如下:

  • str - 要转换的字符串 ;舍弃所有空白符(以调用 isspace() 鉴别),直到找到首个非空白符,然后取尽可能多的字符组成底 n (其中 n=base )的整数表示,并将它们转换成一个整数值。不支持科学计数法哦,合法的整数值由下列部分组成:

    1. (可选)正或负号
    2. (可选)指示八进制底的前缀( 0 )(仅当底为 8 或 ​0​ 时应用)
    3. (可选)指示十六进制底的前缀( 0x 或 0X )(仅当底为 16 或 ​0​ 时应用)
    4. 一个数字序列
  • pos - 存储已处理字符数的整数的地址,也就是说这个数字由几位字符构成

  • base - 数的底 ;

    1. 底的合法集是 {0,2,3,…,36} 。合法数字集对于底 2 整数是 {0,1},对于底3整数是 {0,1,2} ,以此类推。对于大于 10 的底,合法数字包含字母字符,从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。
    2. 若 base 为 ​0​ ,则自动检测数值进制:若前缀为 0 ,则底为八进制,若前缀为 0x 或 0X ,则底为十六进制,否则底为十进制。

示例:

    std::string str1 = "45E+3";std::string str2 = "3.141 59";std::string str3 = "31337 with words";std::string str4 = "words and 2";size_t num1 = 0;size_t num2 = 0;size_t num3 = 0;int myint1 = std::stoi(str1, &num1);int myint2 = std::stoi(str2, &num2);int myint3 = std::stoi(str3, &num3);// 错误: 'std::invalid_argument'// int myint4 = std::stoi(str4);std::cout << "std::stoi(\"" << str1 << "\") is " << myint1 << " char num: " << num1<< '\n';std::cout << "std::stoi(\"" << str2 << "\") is " << myint2 << " char num: " << num2<< '\n';std::cout << "std::stoi(\"" << str3 << "\") is " << myint3 << " char num: " << num3<<'\n';//std::cout << "std::stoi(\"" << str4 << "\") is " << myint4 << '\n';// 输出
std::stoi("45E+3") is 45 char num: 2
std::stoi("3.141 59") is 3 char num: 1
std::stoi("31337 with words") is 31337 char num: 5

2. 转换字符串为无符号整数

用法和 1. 完全一致

unsigned long      stoul( const std::string& str, std::size_t* pos = 0, int base = 10 );
unsigned long      stoul( const std::wstring& str, std::size_t* pos = 0, int base = 10 );unsigned long long stoull( const std::string& str, std::size_t* pos = 0, int base = 10 );
unsigned long long stoull( const std::wstring& str, std::size_t* pos = 0, int base = 10 );

3. 转换字符串为浮点值

float       stof( const std::string& str, std::size_t* pos = 0 );
float       stof( const std::wstring& str, std::size_t* pos = 0 );double      stod( const std::string& str, std::size_t* pos = 0 );
double      stod( const std::wstring& str, std::size_t* pos = 0 );long double stold( const std::string& str, std::size_t* pos = 0 );
long double stold( const std::wstring& str, std::size_t* pos = 0 ); 
  • str - 要转换的 string;函数会舍弃任何空白符(由 std::isspace() 确定),直至找到首个非空白符。然后它会取用尽可能多的字符,以构成合法的浮点数表示,并将它们转换成浮点值。 合法的浮点值可以为下列之一:

    1. 十进制浮点数表达式。它由下列部分组成:
      • (可选) 正或负号
      • 非空的十进制数字序列,可选地包含一个小数点字符(由当前的 C 本地环境确定)(定义有效数字)
      • (可选) e 或 E ,并跟随可选的正或负号,以及非空十进制数字序列(以 10 为底定义指数)
    2. 十六进制浮点数表达式。它由下列部分组成:
      • (可选) 正或负号
      • 0x 或 0X
      • 非空的十六进制数字序列,选地包含一个小数点字符(由当前的 C 本地环境确定)(定义有效数字)
      • (可选) p 或 P ,并跟随可选的正或负号,以及非空十进制数字序列(以 2 为底定义指数)
    3. 无穷大表达式。它由下列部分组成:
      • (可选) 正或负号
      • INF 或 INFINITY ,忽略大小写
    4. 非数(NaN)表达式。它由下列部分组成:
      • (可选) 正或负号
      • NAN 或 NAN(char_sequence) ,忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
      • 任何其他可由当前 C 本地环境接受的表达式
  • pos - 存储已处理字符数的整数的地址 ,也就是说这个数字由几位字符构成

示例:

    std::string str1 = "45E+3";std::string str2 = "3.141 59";std::string str3 = "31337.43 with words";std::string str4 = "words and 2";size_t num1 = 0;size_t num2 = 0;size_t num3 = 0;double myint1 = std::stod(str1, &num1);double myint2 = std::stod(str2, &num2);double myint3 = std::stod(str3, &num3);// 错误: 'std::invalid_argument'// int myint4 = std::stoi(str4);std::cout << "std::stod(\"" << str1 << "\") is " << myint1 << " char num: " << num1<< '\n';std::cout << "std::stod(\"" << str2 << "\") is " << myint2 << " char num: " << num2<< '\n';std::cout << "std::stod(\"" << str3 << "\") is " << myint3 << " char num: " << num3<<'\n';//std::cout << "std::stoi(\"" << str4 << "\") is " << myint4 << '\n';//输出
std::stod("45E+3") is 45000 char num: 5
std::stod("3.141 59") is 3.141 char num: 5
std::stod("31337.43 with words") is 31337.4 char num: 8

4. 数值转字符串

to_string :转换整数或浮点值为 string

to_wstring:转换整数或浮点值为 wstring,这个和string基本类似

std::string to_string( int value );
std::string to_string( long value );
std::string to_string( long long value );
std::string to_string( unsigned value );
std::string to_string( unsigned long value );
std::string to_string( unsigned long long value );
std::string to_string( float value );
std::string to_string( double value );
std::string to_string( long double value );

示例代码

#include <iostream>
#include <string>int main() 
{double f = 23.43;double f2 = 1e-9;double f3 = 1e40;double f4 = 1e-40;double f5 = 123456789;std::string f_str = std::to_string(f);std::string f_str2 = std::to_string(f2); // 注意:返回 "0.000000"std::string f_str3 = std::to_string(f3); // 注意:不返回 "1e+40".std::string f_str4 = std::to_string(f4); // 注意:返回 "0.000000"std::string f_str5 = std::to_string(f5);std::cout << "std::cout: " << f << '\n'<< "to_string: " << f_str  << "\n\n"<< "std::cout: " << f2 << '\n'<< "to_string: " << f_str2 << "\n\n"<< "std::cout: " << f3 << '\n'<< "to_string: " << f_str3 << "\n\n"<< "std::cout: " << f4 << '\n'<< "to_string: " << f_str4 << "\n\n"<< "std::cout: " << f5 << '\n'<< "to_string: " << f_str5 << '\n';
}// 输出:
std::cout: 23.43
to_string: 23.430000std::cout: 1e-09
to_string: 0.000000std::cout: 1e+40
to_string: 10000000000000000303786028427003666890752.000000std::cout: 1e-40
to_string: 0.000000std::cout: 1.23457e+08
to_string: 123456789.000000

这个可能会抛出一个 std::bad_alloc 异常,我们用try catch捕获即可

5. 异常处理

数值转换的时候,出现问题的话就会有 std::invalid_argument 异常出现,都是可以用try catch 捕获异常

try {} catch (const std::invalid_argument &e) {std::cout<<e.what();
}

3. 范围访问

at(size_type pos ): 访问指定pos位置的字符,有边界检查

#include <stdexcept>
#include <iostream>
#include <string>
int main()
{std::string s("message"); // 为容量s = "abc";s.at(2) = 'x'; // okstd::cout << s << '\n';std::cout << "string size = " << s.size() << '\n';std::cout << "string capacity = " << s.capacity() << '\n';try {// 抛出,即使容量允许访问元素s.at(3) = 'x';}catch (std::out_of_range const& exc) {std::cout << exc.what() << '\n';}
}// 可能的输出:
abx
string size = 3
string capacity = 7
basic_string::at

operator[size_type pos ]:访问指定字符,没得校验,推荐使用at 函数

#include <iostream>
#include <string>
int main()
{std::string const e("Exemplar");for (unsigned i = e.length() - 1; i != 0; i /= 2)std::cout << e[i];std::cout << '\n';const char* c = &e[0];std::cout << c << '\n'; // 作为 C 字符串打印// 更改 s 的最后字符为 'y'std::string s("Exemplar ");s[s.size()-1] = 'y';std::cout << s << '\n';
}//输出:
rmx
Exemplar
Exemplary

front: 访问首字符
back: 访问最后的字符
data:返回指向字符串首字符的指针
c_str:返回字符串的不可修改的 C 字符数组版本,这个区别于data,可以说data可以修改、而c_str不能修改

4. 迭代器

返回指向字符串首字符的迭代器,迭代器就是一种特异化的指针,带’c’就是说是只读的迭代器。

含义
begin cbegin返回指向起始的迭代器
end cend返回指向末尾的迭代器
rbegin crbegin返回指向起始的逆向迭代器
rend crend返回指向末尾的逆向迭代器

在这里插入图片描述

在这里插入图片描述

#include <string>
#include <iostream>int main()
{std::string s("Exemplar");*s.begin() = 'e';std::cout << s <<'\n';auto i = s.cbegin();std::cout << *i << '\n';
//  *i = 'E'; // 错误: i 是常迭代器
}

逆序字符串示例:

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>int main()
{std::string s("Exemplar!");*s.rbegin() = 'y';std::cout << s << '\n'; // "Exemplary"std::string c;std::copy(s.crbegin(), s.crend(), std::back_inserter(c));std::cout << c << '\n'; // "yralpmexE"
}// 输出:
Exemplary
yralpmexE

5. 容量

empty: 检查字符串是否为空;若 string 为空则为 true ,否则为 false 。

size length : 返回字符数

max_size : 返回字符数的最大值

reserve : 保留存储;告诉 std::basic_string 对象大小的有计划更改,使得它能准确地管理存储分配。

  • 若 new_cap 大于当前 capacity() ,则分配新存储,并令 capacity() 大于或等于 new_cap 。

  • 若 new_cap 小于当前 capacity() ,则这是非强制的收缩请求。

  • 若 new_cap 小于当前 size() ,则这是非强制的收缩到适合 (shrink-to-fit) 请求,等价于 shrink_to_fit() (C++11 起)。

capacity : 返回当前对象分配的存储空间能保存的字符数量

shrink_to_fit: 通过释放不使用内存减少内存使用 ;也就是移除未使用的容量。

6. 操作

在每一个版本的函数有些差异。C20版本最全。

clear: 清除内容

insert: 插入字符

erase: 移除字符

push_back: 后附字符到结尾

pop_back: 移除末尾字符

append: 后附字符到结尾

operator+= : 后附字符到结尾

compare : 比较二个字符串

replace: 替换字符串的指定部分;往往搭配 find 函数一起使用

substr: 返回子串

copy: 复制字符

resize: 更改存储的字符数

swap: 交换内容

7. 查找

find: 于字符串中寻找字符

rfind: 寻找子串的最后一次出现

find_first_of:寻找字符的首次出现

find_first_not_of: 寻找字符的首次缺失

find_last_of: 寻找字符的最后一次出现

find_last_not_of: 寻找字符的最后一次缺失

#include <string>
#include <iostream>void print(std::string::size_type n, std::string const &s)
{if (n == std::string::npos) {std::cout << "not found\n";} else {std::cout << "found: " << s.substr(n) << '\n';}
}int main()
{std::string::size_type n;std::string const s = "This is a string";// 从 string 开始搜索n = s.find("is");print(n, s);// 从位置 5 开始搜索n = s.find("is", 5);print(n, s);// 寻找单个字符n = s.find('a');print(n, s);// 寻找单个字符n = s.find('q');print(n, s);
}
// 输出:
found: is is a string
found: is a string
found: a string
not found

8. 字面量

字面量就是不可以被修改的常量字符串,在程序中多个副本会指向同一个字面量。

其中的一个基础定义就是

std::string operator""s(const char *str, std::size_t len);
#include <string>
#include <iostream>int main()
{using namespace std::string_literals;std::string s1 = "abc\0\0def";std::string s2 = "abc\0\0def"s;std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";
}// 可能的输出:
s1: 3 "abc"
s2: 8 "abcdef"