修改const char*数组时的未定义行为及相关技术疑问
问题解答
1. 代码行为差异的原因
这是悬垂指针和C++字符串的**小字符串优化(SSO)**共同导致的:
std::string::c_str()返回的指针,仅在对应std::string对象存活期间有效。你的temp1、temp2定义在if代码块里,当代码执行完这个if块后,这两个字符串对象会被销毁,它们内部的字符存储也会被释放。- 当字符串较短时,很多C++标准库实现会启用SSO:把字符串内容直接存在
std::string对象的栈上缓冲区里,而不是堆上。当if块结束后,栈上的这块内存虽然不再被使用,但暂时还没被其他数据覆盖,所以你通过悬垂指针还能读到之前的内容,看起来“正常”。 - 当字符串长度超过SSO的阈值(通常是15-16个字符,包含末尾的
\0),std::string会在堆上分配内存存储字符。对象销毁后,堆内存被归还给系统,此时再访问之前c_str()返回的指针,就是访问已经释放的内存——这属于未定义行为,结果就是打印垃圾值。 - 而直接赋值字符串字面量时,字符串字面量是存储在程序的只读数据段中的,生命周期和整个程序一致,所以指针始终有效,不会出现问题。
2. const char*为何能修改值的误解
const char*的含义是:不能通过这个指针修改它指向的字符内容,但指针本身是可以被修改的。
你的first是const char*类型的数组,数组里的每个元素是一个指针,指向const char类型的字符序列。你代码中做的是修改数组里的指针(让它指向temp1.c_str()或者字符串字面量),而不是修改指针指向的字符内容。比如你不能写(*first[0]) = 'x'(这会试图修改指针指向的字符,编译器会报错),但完全可以修改指针本身,让它指向新的地址。
内容的提问来源于stack exchange,提问作者Ujjwal Gupta
相关产品推荐
相关产品推荐

