本章目标:std::string(最常用的类型)、string_view(C++17)、 格式化输出 print/format、读取输入。 熟练字符串,你的 C++ 就算入门一半了。
#include <string>
std::string s = "hello";
std::string t = "world";
std::string u = s + " " + t; // 拼接,u == "hello world"
s += "!"; // 追加
s.size(); // 长度(字符个数)
s.empty(); // 是否为空
s[0]; // 第 0 个字符 'h'
s.at(0); // 带边界检查,越界会抛异常
对比 C 风格的 char[],string 的三大好处:
s.substr(pos, len); // 截取子串
s.find("lo"); // 找子串位置,找不到返回 npos
s.starts_with("he"); // [C++20] 是否以 xx 开头
s.ends_with("lo"); // [C++20] 是否以 xx 结尾
s.contains("ell"); // [C++23] 是否包含子串
s.replace(pos, len, str); // 替换一段
s.insert(pos, str); // 插入
s.erase(pos, len); // 删除一段
s.push_back('x'); // 末尾加一个字符
s.pop_back(); // 删掉末尾一个字符
find 的返回值是 size_t 类型的位置;找不到时返回 std::string::npos(一个巨大的数)。用法:
auto pos = s.find("lo");
if (pos != std::string::npos) { // 找到了
std::println("位置在 {}", pos);
}
字符串转数字(C++17 起推荐 std::from_chars,性能最好, 先记 from_chars 简单版 / 或 to_number 在 C++26 可用):
int n = std::stoi("42"); // string → int(stod→double)
// C++17 高效版:
int n2;
auto [p, ec] = std::from_chars("42", "42"+2, n2); // 不抛异常
数字转字符串(C++20 起推荐 std::format,最优雅):
std::string s = std::format("{}", 42); // "42"
std::string s2 = std::format("{:06.2f}", 3.14159); // "003.14"
老写法 s = std::to_string(42) 也行,但 format 更强大。
string_view 是"别人字符串的一段视图"——不拥有数据、不拷贝。
std::string s = "hello world";
std::string_view sv(s.data() + 6, 5); // "world" 的视图
sv = s; // 整个 s 的视图
为什么要它?性能。 函数接收 string 参数时,传值会拷贝整个字符串。 传 string_view 则零拷贝——只记录"从哪开始、多长"。
现代 C++ 最佳实践:
std::string_view bad() {
std::string s = "x";
return s; // 函数结束 s 销毁,视图悬空!编译会警告
}
#include <print>
std::println("{} + {} = {}", 1, 2, 3); // 1 + 2 = 3
std::print("不换行");
格式化语法(大括号里的内容):
{} 默认格式
{:d} 十进制整数
{:x} {:X} 十六进制
{:b} 二进制(bool 也能用,输出 true/false)
{:f} 浮点:默认 6 位小数
{:.2f} 保留 2 位小数
{:>10} 右对齐,宽度 10({:<10} 左对齐)
{:05d} 宽度 5,不足用 0 补
{:%Y-%m-%d} 日期格式(配合 chrono)
例:
std::println("{:>6} {:.2f}", "price", 3.14159);
// 输出: price 3.14
printf("%s %d %.2f\n", "值", 42, 3.14);
// %s 字符串 %d 整数 %f 浮点 %.2f 两位小数
printf 的危险:类型写错会"未定义行为"(打印乱码甚至崩溃)。 新代码一律用 println,不用 printf。
#include <iostream>
std::string name;
int age;
std::cout << "名字和年龄:";
std::cin >> name >> age; // 空格/换行分隔,逐个读
一行读一整行(含空格):
std::string line;
std::getline(std::cin, line); // 读一整行
读数字直到失败/结束:
int n;
while (std::cin >> n) { // 读不到整数时返回 false
// 处理 n
}
注意 cin 与 getline 混用时的坑:cin >> 后按回车留下的换行符 会被 getline 直接读走。解决办法:cin.ignore() 清掉一个字符, 或全程用 getline 再手动解析。新手常见坑,遇到再说。
#include <fstream>
// 写文件
std::ofstream out("data.txt");
out << "hello " << 42 << std::endl;
// 读文件
std::ifstream in("data.txt");
std::string word;
while (in >> word) { /* 处理 */ }
读整个文件到字符串(C++17 风格):
std::ifstream in("data.txt");
std::string content((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
文件打开失败怎么办?检查:
if (!out) { std::println("无法打开文件!"); return 1; }
练习题