楼主:
wtchen (没有存在感的人)
2016-05-14 16:45:0304. 你不可以试图用 char* 去更改一个"字串常数"
试图去更改字串常数(string literal)的结果会是undefined behavior。
错误例子:
char* pc = "john"; /* pc 现在指著一个字串常数 */
*pc = 'J'; /* undefined behaviour,结果无法预测*/
pc = "jane"; /* 合法,pc指到在别的位址的另一个字串常数*/
/* 但是"john"这个字串还是存在原来的地方不会消失*/
因为char* pc = "john"这个动作会新增一个内含元素为"john\0"的static char[5],
然后pc会指向这个static char的位址(通常是唯读)。
若是试图存取这个static char[],Standard并没有定义结果为何。
pc = "jane" 这个动作会把 pc 指到另一个没在用的位址然后新增一个
内含元素为"jane\0"的static char[5]。
可是之前那个字串 "john\n" 还是留在原地没有消失。
通常编译器的作法是把字串常数放在一块read only(.rdata)的区域内,
此区域大小是有限的,所以如果你重复把pc指给不同的字串常数,
是有可能会出问题的。
正确例子:
char pc[] = "john"; /* pc 现在是个合法的阵列,里面住着字串 john */
/* 也就是 pc[0]='j', pc[1]='o', pc[2]='h',
pc[3]='n', pc[4]='\0' */
*pc = 'J';
pc[2] = 'H';
说明:字串常数的内容应该要是"唯读"的。您有使用权,但是没有更改的权利。
若您希望使用可以更改的字串,那您应该将其放在合法空间
错误例子:
char *s1 = "Hello, ";
char *s2 = "world!";
/* strcat() 不会另行配置空间,只会将资料附加到 s1 所指唯读字串的后面,
造成写入到程式无权碰触的内存空间 */
strcat(s1, s2);
正确例子(2):
/* s1 宣告成阵列,并保留足够空间存放后续要附加的内容 */
char s1[20] = "Hello, ";
char *s2 = "world!";
/* 因为 strcat() 的返回值等于第一个参数值,所以 s3 就不需要了 */
strcat(s1, s2);
C++对于字串常数的严格定义为const char* 或 const char[]。
但是由于要相容C,char* 也是允许的写法(不建议就是)。
不过,在C++试图更改字串常数(要先const_cast)一样是undefined behavior。
const char* pc = "Hello";
char* p = const_cast<char*>(pc);
p[0] = 'M'; // undefined behaviour
备注:
由于不加const容易造成混淆,
建议不管是C还是C++一律用 const char* 定义字串常数。
补充资料:
http://en.cppreference.com/w/c/language/string_literal
http://en.cppreference.com/w/cpp/language/string_literal
字串函数相关:#1IOXeMHX
undefined behavior : 精华区 z -> 3 -> 3 -> 23