绝大多数情况下应直接使用string;仅在明确出现性能瓶颈、内存超限或需对接C风格接口时才考虑char[]。

绝大多数情况下,直接用 string;只有明确遇到性能瓶颈、内存超限或必须对接 C 风格接口时,才考虑 char[]。
什么时候 string 会拖慢程序?
不是“慢”,而是某些场景下开销不可忽略:
- 高频拼接(比如在循环里反复
+=一个短字符串):每次扩容可能触发内存重分配,char[]+strcat更可控(但得自己管边界) - 字符串长度接近
1e6以上且题目卡内存(MLE):string内部有额外指针+容量字段,而char s[N]就是纯 N 字节 - 需要传给老式函数如
fopen、scanf、手写 KMP 的next[]数组:它们要的是const char*或裸地址,string.c_str()虽能转,但多一次检查/拷贝
为什么 char s[100] 容易崩?
崩的不是语法,是运行时行为——越界写入不报错,只悄悄覆盖相邻变量或栈帧:
-
scanf("%s", s)遇到超长输入直接溢出,s[100]最多存 99 个字符 +'\0',但用户输 120 个就踩内存 -
strcpy(s, long_str)不检查目标长度,源字符串多长它就拷多长 -
strlen(s)从头扫到第一个'\0',如果中间被意外清零或没写'\0',就会越界读 - 定义
char s[10]却用gets(s)(已弃用)或fgets(s, 20, stdin):第二个参数填错就白搭
string 真的安全?那为什么竞赛老手还手写 char[]?
安全是相对的:string 不会越界访问,但会抛异常(如 at() 下标越界)或静默截断(如 substr 起始位置超长),而竞赛默认关闭异常、不检查越界,所以实际行为和 char[] 类似——只是崩溃概率低些。
立即学习“C++免费学习笔记(深入)”;
老手选 char[] 的真实原因很务实:
- 题干明确说 “字符串长度 ≤ 10⁶”,他们直接
char s[1000005],省去string动态分配的微小延迟 - 需要频繁取子串起始地址做指针运算(比如后缀数组里传
&s[i]),string的&s[i]在 C++11 后才保证连续,旧编译器(如 GNU 4.8)不保 - 整道题全是单字符处理(如统计括号匹配),
s[i]访问速度略快于string::operator[]的内联开销(虽然差不到 1ns,但卡 500ms 时限时会算)
一个折中写法:用 string,但控制底层行为
既不想手写边界检查,又怕 string 慢,可以这样:
- 提前预留空间:
string s; s.reserve(1000000);避免多次扩容 - 关同步流:
ios::sync_with_stdio(false); cin.tie(0);后cin >> s和scanf速度几乎无差别 - 需要 C 接口时,优先用
s.data()(C++11 起,非空时等价于c_str(),且不强制加'\0') - 避免
+=循环拼接,改用append()或一次性构造:string res = s1 + s2 + s3;
真正难的不是选哪个类型,而是判断“这题到底卡不卡常”——而这往往取决于你上次用 string 多跑了一次 TLE。


















