字符串变量
传统的C风格的字符串是用字符数组(char[])来表示:
长度固定(声明后不可变),结尾符显式需要 \0 结尾,长度获取strlen(s)
C++ std::string 的存储方式, 长度动态可变,结尾符内部处理,不计入长度,拼接可以使用+或+=运算符,长度获取是:s.size() 或 s.length()
例如:创建一个字符串变量
string geeting= "hello" cout<<sizeof(geeting).
下面一下程序输出结果为?
1 2 3 4 5 6 7 8 9 10 11 12 | #include <iostream> using namespace std; int main() { string firstName ="Isaac"; string lastName ="Newton"; string fullName; fullName=firstName+lastName; cout << fullName; return 0; } |
string类型也可以用下标来操作,最后一个字符也是’\0′ (C++11标准)
1 2 3 4 5 6 7 8 9 10 11 12 | #include <iostream> #include <string> using namespace std; int main() { string myString ="Hello"; myString[0] ='J'; cout << myString<<endl; if(myString[5]=='\0')cout<<"I know you have tail"; return 0; } |
字符型变量与字符串变量
备注:
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。
strlen所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止,然后返回计数器值(长度不包含’\0′)。
strlen参数只能是char*,且必须是以’\0’结尾。
size()是string类型的成员函数,调用方式为s.size(),它返回的值是s的大小,也就是s的长度。成员函数是指某个类型的特有函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <cstring> #include <string> #include <iostream> using namespace std; int main(){ char a_string[]={'a','b','c','\0'};//c-style字符串 char b_string[]="abc"; //c-style字符串 char c_string[]={'a','b','c'}; //字符数组 string d_string="abc"; //C++ STL类型字符串 cout<< sizeof(a_string)<<' '<<strlen(a_string)<<' '<<a_string<<endl; cout<< sizeof(b_string)<<' '<<strlen(b_string)<<' '<<b_string<<endl; cout<<sizeof(c_string)<<' '; for (int i = 0; i <sizeof(c_string); i++)cout<<c_string[i]; cout<<endl; cout<< sizeof(d_string)<<' '<<d_string.size()<<' '<<d_string<<endl; } |
C++ std::string 的存储方式,可以用“一处固定,两处变通”来概括。
1. 结构总结:栈与堆的协作
无论字符串多长,string 变量本身(在栈上)的大小通常是固定的(如 24 或 32 字节)。它的核心由三部分组成:指针(Data Pointer)、大小(Size)、容量(Capacity)。
2. 核心机制:SSO(短字符串优化)
这是现代 C++ 存储 string 的精髓,它会根据字符串长度自动切换模式:
- 短字符串模式(本地存储):
- 触发条件:字符串长度较短(通常在 15-22 字节以内)。
- 存储位置:直接存放在栈上的那 24 字节内部。
- 优点:不需要申请堆内存,速度极快。此时原本存放“指针”的空间被当成“字符数组”用了。
- 长字符串模式(远程存储):
- 触发条件:长度超过了内部缓冲区的上限。
- 存储位置:在**堆(Heap)**上申请一块连续空间存放字符。
- 优点:可以存储海量数据,理论上限仅受系统内存限制。此时栈上的“指针”会指向这块堆内存的起始地址。
3. 动态扩容策略:倍增法
当你在一个已有的字符串后面不断添加内容,导致“长度”超过“容量”时:
- 重新申请:在堆上找一块更大的新空间(通常是原容量的 1.5 倍或 2 倍)。
- 搬迁:将旧数据拷贝到新空间。
- 释放:销毁旧空间的内存。
- 更新:更新栈上的指针、Size 和 Capacity。
4. 存储特性一览表
| 特性 | 短字符串 (Short) | 长字符串 (Long) |
| 存放位置 | 栈 (Stack) | 堆 (Heap) |
| 内存开销 | 0 额外开销 (利用对象自身空间) | 随长度动态增长 |
| 访问速度 | 更快 (缓存命中率高) | 稍慢 (需要通过指针跳转) |
| sizeof(a) | 固定 (如 24) | 固定 (如 24) |
关键结论
sizeof不变:因为它只看“管理员”占多大地儿。- 地址会变:当发生扩容或从小字符串转为长字符串时,数据的内存地址会发生改变。
- 内存连续:无论在栈还是堆,
string保证内部字符是连续存储的,所以可以用下标[]随机访问。
