必须包含#include <String>才能使用std::string,它不属于<iostream>且位于std命名空间;常见错误是未引入头文件导致“string未声明”;正确用法包括std::string、using std::string或using Namespace std(不推荐)。

string 不是关键字,得 #include <string> 才能用
很多人写完 std::string s = "hello"; 就报错,编译器说 string 未声明——不是你拼错了,是根本没引入头文件。c++ 标准库的 string 类不在 <iostream> 里,也不在全局命名空间,它藏在 <string> 头文件中,且属于 std 命名空间。
常见错误现象:Error: 'string' was not declared in this scope
- 必须加
#include <string>,缺一不可 - 要么写全
std::string,要么加using std::string;(不建议using namespace std;) - 别和 C 风格字符串(
char[]或const char*)混淆:它们类型不同,不能直接赋值给未初始化的std::string变量(但可以隐式构造)
初始化 string 的 4 种常见写法,别乱混用
初始化方式影响底层行为,尤其在性能敏感或移动语义启用时。比如空字符串、从 C 字符串构造、拷贝、移动,背后调用的构造函数完全不同。
使用场景:读配置、拼接日志、接收函数返回值
立即学习“C++免费学习笔记(深入)”;
-
std::string s;—— 默认构造,内部指针为空或指向小缓冲区(SSO),不分配堆内存 -
std::string s = "abc";—— 字符串字面量构造,隐式调用string(const char*) -
std::string s(other_string);—— 拷贝构造;如果other_string是右值(如函数返回值),C++11 起会自动触发移动构造,避免深拷贝 -
std::string s(std::move(temp));—— 显式移动,适用于临时对象已无用时,把内部缓冲区“转手”给新对象
容易踩的坑:std::string s = std::string("hello"); 看似无害,但可能多一次不必要的临时对象构造(编译器通常会优化掉,但别依赖)
用 c_str() 和 data() 时,注意生命周期和空字符
当你需要把 std::string 传给 C API(比如 fopen、printf、OpenGL 函数),必须转成 const char*。这时选 c_str() 还是 data()?差别很实际。
-
s.c_str()保证以' '结尾,返回值可安全用于任何要求 NULL-terminated 的 C 函数 -
s.data()在 C++11 中不保证结尾有' '(C++17 起才保证),只适合传给明确接受长度参数的函数(如write(2)、std::string_view构造) - 二者返回指针都只在
s生命周期内有效;一旦s被修改、销毁或重新分配,指针立刻失效
典型错误:const char* p = s.c_str(); s.clear(); printf("%s", p); → 未定义行为,很可能打印乱码或崩溃
== 比较安全,但 find / substr 等操作要防越界
std::string 的比较操作符(==、< 等)语义清晰,基本不会出错。真正容易翻车的是下标访问、查找、子串提取这些带索引的操作。
-
s[i]不检查越界(i ≥ s.length() 时是未定义行为),调试模式下某些 STL 实现会 abort,但发布版直接崩 -
s.at(i)会抛std::out_of_range异常,适合需要显式错误处理的场景 -
s.find("x")找不到时返回std::string::npos(一个极大值,通常是size_t(-1)),别直接当整数用:if (s.find("x") < 5)在没找到时会恒成立 -
s.substr(pos, len)中,如果pos > s.Length(),直接抛异常;len超出剩余长度则自动截断——这点反而比 C 安全
性能提示:find 是 O(N×M) 的朴素匹配,别在大文本里反复调用它做模糊搜索;真要高效查,考虑 std::string_view + KMP,或换用 std::Regex(代价更高)
string 的坑不在语法多难,而在“看起来像内置类型,实则行为受标准版本、编译器实现、甚至优化等级影响”。比如 SSO(短字符串优化)是否开启、移动构造是否真的发生、data() 是否带 ‘