C++ string中'\0'表现差异及sizeof(string)为32的问题咨询
问题1:两种场景下std::string行为差异的原因
首先明确核心规则:C++的std::string是「长度前置」的容器类型,本身不依赖'\0'判断字符串结束,'\0'对它来说只是一个普通的可存储字符,和'a'、'1'没有本质区别,两种场景的差异完全来自赋值阶段的逻辑不同:
- 第一段代码的赋值逻辑:
你使用C风格字符串字面量"he\0llo"给std::string初始化。C风格字符串的原生规则就是「遇到第一个'\0'视为字符串结束」,std::string接收const char*参数的构造函数,默认会按照C风格字符串的规则解析输入:扫描到第一个'\0'就停止读取,所以最终只有"he"被存入string对象,length属性直接被设为2,后面的llo完全没有进入string的存储范围,自然打印的时候只能输出2个字符。
如果需要把带中间'\0'的字符串字面量完整存入std::string,可以调用带长度参数的构造函数,例如:
string s("he\0llo", 6); // 明确指定要读取6个字符
此时s的length会是6,打印的时候会输出所有内容('\0'在终端为不可见字符)。
- 第二段代码的赋值逻辑:
你通过cin >> s输入内容时,cin会把读取到的所有非空白字符完整存入string,同时将length属性设置为实际输入的字符数(比如你输入hello的话,length就是5)。后续你修改s[1] = '\0',仅仅是修改了string存储的字符数组中下标为1的字符值,完全不会修改string内部维护的length属性。
而std::string重载的<<输出运算符,逻辑是「输出length属性指定数量的字符」,而非遇到'\0'就停止,所以会把5个字符全部输出:h+ 不可见的'\0' +l+l+o,终端不会显示'\0',所以最终你看到的输出就是hllo,length也依然是5。
问题2:为什么两种场景下sizeof(string)都是32
sizeof是编译期运算符,计算的是类型本身占用的栈内存大小,和对象运行时存储的内容完全无关。
目前主流64位版本编译器(如GCC、Clang)的std::string实现都自带小字符串优化(SSO):string对象本身的结构是固定大小的,包含长度计数、容量计数、以及一个共用体(要么存储指向堆内存的指针,要么存储16字节的栈上缓冲区用来放短字符串,避免频繁申请堆内存),几个部分加起来的总大小刚好是32字节。不管你的string是空的、存短字符串还是存需要开堆的长字符串,这个对象本身的栈上占用大小是固定的,所以两种场景下sizeof(s)的结果都是32。
内容的提问来源于stack exchange,提问作者Subhodeep
相关产品推荐
相关产品推荐

