指针修改字符串字面量

C语言标准规定数组的值可以改变,而修改字符串字面量的值的结果是未定义的(详见分割线后,感谢 @Sunchy321 指正)。char s和char *s这两个s不是一种东西。这个问题编译器的具体实现一般是这样的:char s = "whatever";也相当于char s = {\u0026#39;w\u0026#39;,\u0026#39;h\u0026#39;,\u0026#39;a\u0026#39;,\u0026#39;t\u0026#39;,\u0026#39;e\u0026#39;,\u0026#39;v\u0026#39;,\u0026#39;e\u0026#39;,\u0026#39;r\u0026#39;,\u0026#39;\\0\u0026#39;};会在stack分配10个字节给数组s,然后把"whatever"拷贝进去。stack是可读写的,所以你可以修改字符数组的值。char *s = "whatever";会在stack分配sizeof(char *)字节的空间给指针s,然后将s的值修改为"whatever"的地址,而这段地址一般位于只读数据段中。在现代操作系统中,可以将一段内存空间设置为“读写数据”、“只读数据”等等多种属性,一般编译器会将"whatever"字面量放到像".rodata"这样的只读数据段中,修改只读段会触发 CPU 的保护机制(#GP)从而导致操作系统将程序干掉。==========我是分割线==========ISO/IEC 9899:1999 (E) , §6.4.5 String literals (P63L5):If the program attempts to modify such an array, the behavior is undefined.修改字符串字面量的行为是Undefined Behavior,也就是说具体实现是依赖编译器的,上文所举的例子只是x86下常见的情况,但并不是C语言标准所规定的。比如,char *a = "WhatEver";char *b = "WhatEver";编译器完全可以为节约空间只存储一个"WhatEver",也就是实际上a = b,这种情况下,在没有段保护机制的系统中如果你a = "O";很可能会导致 a 变为 "WhatOver" 的同时 b 也变为 "WhatOver"。
■网友
C语言的字符串是这样。char str1 = "abc";char str2 = {\u0026#39;a\u0026#39;,\u0026#39;b\u0026#39;,\u0026#39;c\u0026#39;,\u0026#39;\\0\u0026#39;};char * str3 = "abc";因为C没有内置的string类型,所以你可以用这三种方法创建你的字符串。在C中,我们存放data的地方其实有四个1,stack,存放所有的local variable,function(运行时)。stack会随着你的function call而不停地被抹掉,重写(这也是为什么在function中创建一个变量并return其指针是一个很terrible的事情,还有就是为什么你创建数组的时候如果不初始化,数组的值为野值)2,heap,当你使用malloc,calloc等function时,会在heap中分配一块空间。由于heap和stack是分开的,所以即使是function结束(即使是整个main结束),这块空间也不会被抹去,所以每次alloc后要记得free。3,程序本身存放的地方。4,constant以及一些其他的变量存放的区域,其中有read and write: global variable, static variable. read only: string, constant variable.这个就是问题的所在。在我们创建(初始化)string的时候,如果用前两种方法,这个str会被创建在stack中,也就是说是可以被修改的。而第三种方法的str被创建在了我上文说的区域4,而且其实这个string是constant的,也就是绝对不能被修改的。所以,当题主准备修改ptr的时候,会出现错误。建议按照我上文的方法创建string,然后打出他们的地址。题主会发现,str1和str2会离得很近,而str3根本就和前两者在两个次元。=======================================================================我继续补充一句好了。char str1 = "abc";char str2 = {\u0026#39;a\u0026#39;,\u0026#39;b\u0026#39;,\u0026#39;c\u0026#39;,\u0026#39;\\0\u0026#39;};char str3 = {\u0026#39;a\u0026#39;,\u0026#39;b\u0026#39;,\u0026#39;c\u0026#39;};注意看str2和str3.我想说的是,char的array!=string。在我们创建一个array的时候,我们要记住两个东西。1,这个array的地址。2,这个array的长度。C中array的长度是不能通过array直接获得的(有方法是sizeof)。而且C不会限制去更改指针的地址。那么问题来了,如果我创建了一个array然后我想通过一个loop去访问每一个变量,我就必须知道这个array的长度,否则就会出现数组越界。而我前文提到的char array != string的原因是,当我们处理string的时候其实并不需要知道string的长度(你用printf的时候应该没输入过string的长度吧),那么这一点是怎么做到的呢。其实就是有一个约定:string的最后一个char必须是’\\0’。当程序读到这个字符的时候,会默认读到了string的结尾。所以str1,str2是string(可以看成string)而str3绝对不可以。而str1和str2其实是等价的。那么问题又来了,如果我这么创建string,


推荐阅读