字符串变量

传统的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. 重新申请:在堆上找一块更大的新空间(通常是原容量的 1.5 倍或 2 倍)。
  2. 搬迁:将旧数据拷贝到新空间。
  3. 释放:销毁旧空间的内存。
  4. 更新:更新栈上的指针、Size 和 Capacity。

4. 存储特性一览表

特性短字符串 (Short)长字符串 (Long)
存放位置栈 (Stack)堆 (Heap)
内存开销0 额外开销 (利用对象自身空间)随长度动态增长
访问速度更快 (缓存命中率高)稍慢 (需要通过指针跳转)
sizeof(a)固定 (如 24)固定 (如 24)

关键结论

  • sizeof 不变:因为它只看“管理员”占多大地儿。
  • 地址会变:当发生扩容或从小字符串转为长字符串时,数据的内存地址会发生改变。
  • 内存连续:无论在栈还是堆,string 保证内部字符是连续存储的,所以可以用下标 [] 随机访问。

Scroll to Top