#include<bits/stdc++.h>
#include<string>
using namespace std;
int main(){
std::string s;
cin>>s;
// write your code here......
int a = 0;
int b = 0;
int c = 0;
for(int i = 0; i<size(s); i++){
if(s[i] == 'a'){
a += 1;
}else if(s[i] == 'b'){
b += 1;
}else{
c += 1;
}
}
cout<<a<<" "<<b<<" "<<c;
return 0;
}
你发现直接通过下标遍历 std::string 就能实现字符统计,而且代码比复制到数组的写法简单太多,核心疑问是:为什么这种写法能生效?std::string 本身是不是字符数组?我来帮你把这个问题讲透。
核心结论先明确
std::string不是单纯的C风格字符数组,但它内部封装了连续的字符存储,并且特意设计了和数组完全一致的下标访问语法(s[i]),所以你的遍历写法既简洁又完全符合C++的设计初衷,也是最推荐的写法。
详细解释:为什么你的代码能生效?
1. std::string 的本质:“智能的字符容器”
std::string 是C++标准库提供的字符串类,而非原生数组,但它的内部实现会管理一块连续的字符内存(可以理解为“自动管理的字符数组”),并且对外提供了友好的访问接口:
- 内部会自动存储字符(比如你输入的
a/b/其他字符),还会在末尾隐式添加'\0'(兼容C风格字符串),但s.size()只返回“有效字符数”(不含'\0'); - 自动管理内存:比如你输入的字符串变长/变短,
std::string会自动扩容/释放内存,不用像C风格数组那样手动指定固定大小; - 支持数组式下标访问:
s[i]是std::string类重载的运算符,作用是直接访问第i个字符,和数组ss[i]的用法完全一致,这是特意为了方便开发者使用设计的。
2. 你的代码逻辑完全正确
// 遍历所有字符:i从0到s.size()-1,刚好覆盖所有有效字符
for(int i = 0; i < s.size();i++) {
if(s[i] == 'a') m++;
else if(s[i] == 'b') n++;
else p++;
}
s.size():返回字符串的实际有效字符数(比如输入aabcc,s.size()就是5),循环条件i < s.size()能确保遍历到最后一个字符(下标s.size()-1),不会遗漏也不会越界;s[i]:直接访问第i个字符,和数组下标用法完全一样,没有任何额外成本。
3. 对比“复制到数组”的写法:你的写法是最优解
之前复制到数组的写法,本质是“多此一举”——因为 std::string 本身已经提供了直接访问字符的能力,没必要把字符再复制一份到数组里。两种写法的对比:
直接遍历
| 简洁、高效(无冗余复制)、安全 | 无(这是C++推荐写法) |
复制到数组再遍历 | 兼容纯C语法 | 冗余、易踩坑(忘加
、数组越界等) |
举个直观例子
假设你输入 s = "aab123":
s.size()= 6(有效字符:a、a、b、1、2、3);s[0]= 'a',s[1]= 'a',s[2]= 'b',s[3]= '1'……s[5]= '3';- 循环
i从0到5,刚好遍历所有字符,统计结果m=2, n=1, p=3,完全正确。
总结
std::string不是普通C风格字符数组,而是封装了字符存储的类,但支持数组式下标访问(s[i]);- 直接遍历
std::string的下标是最简洁、最高效、最安全的写法,无需额外复制到数组; s.size()能准确获取有效字符数,配合i < s.size()循环,可完美遍历所有字符,避免越界风险。
你的这段代码其实就是这个需求的“标准答案”——简单、高效、符合现代C++规范,比之前复制到数组的写法好太多啦。

京公网安备 11010502036488号