“烫烫烫”和“屯屯屯”源于visual studio debug模式下内存填充机制:栈内存填0xcc(gbk解码为“烫”),堆内存填0xcd(gbk解码为“屯”),未初始化char数组被当作字符串输出时即显示对应汉字。

为什么 char 数组未初始化会输出“烫烫烫”或“屯屯屯”?
这不是字符本身有问题,而是内存内容被误读的结果。在 Visual Studio 的 Debug 模式下,编译器会用 0xCC 填充未初始化的栈内存——这是微软的调试填充标记,用来快速暴露未初始化使用问题。当这段内存被当作字符串(char*)传给 printf 或 std::cout 时,0xCC 在 GBK 编码下正好对应汉字“烫”,连续多个 0xCC 就显示为“烫烫烫…”;若系统 locale 是 Big5 或其他编码,可能解出“屯”“菗”等字。
std::cout 也输出乱码?那是地址还是字符串?
std::cout 对 char* 有重载,会自动尝试按 C 字符串打印,而不是输出地址值。所以当你写 std::cout (<code>ch 是未初始化的 char),它拿到的是一个指向单个 char 的指针,但 std::cout 会从该地址开始一路读,直到遇到 '\0' 才停——而后面全是随机字节(比如一堆 0xCC),于是解码成一串中文乱码。
- 正确输出地址:必须强制转成
void*,即std::cout - 错误写法:
std::cout (触发字符串重载,危险) - 更安全的做法:避免对未初始化变量取地址后直接用于 I/O
怎么初始化才能彻底避开“烫烫烫”?
关键不是“什么时候初始化”,而是“初始化是否覆盖全部有效字节并含终止符”。C 风格字符串依赖 '<p>关键不是“什么时候初始化”,而是“初始化是否覆盖全部有效字节并含终止符”。C 风格字符串依赖 <code>'\0' 结束,哪怕只差一个字节,printf 或 std::cout 就会越界读。
printf 或 std::cout 就会越界读。- 推荐写法:
char buf[256] = {0};—— 利用聚合初始化把整个数组设为零,既清空垃圾值,又确保末尾是'\0' - 不推荐写法:
char buf[256];(完全未初始化)或char buf[256] = {'a'};(只设首字节,其余仍是随机值) - 如果后续要用
strcpy或scanf,必须确保目标缓冲区已初始化且空间足够,否则写入前就可能越界或残留乱码
VS Debug 和 Release 模式表现不同,是不是 Bug?
不是 Bug,是设计行为。Debug 模式下填 0xCC 是为了帮你暴露问题;Release 模式下这些内存是真正随机的(取决于上一次栈使用残留),可能偶尔“碰巧”以 '\0' 结尾,看起来正常,但本质仍是未定义行为——上线后随时可能崩溃或输出不可控内容。
真正容易被忽略的点是:即使你用 std::string,只要混用了 char[] 做中间缓冲(比如 sscanf、fgets),这个初始化漏洞就还在。别以为用了现代 C++ 就能绕过 C 层级的内存规则。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











