这两个代码必须更改字符2中的char'4'
int main(int argc, char *argv[]){
char *s = "hello";
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行这个时,我运行时会出现分段错误:
int main(int argc, char *argv[]){
char *s = argv[1];
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道还有其他方法可以做到这一点.两个程序有什么区别?
在第一种情况下,您通过尝试修改字符串文字来面对未定义的行为.分段错误是UB 的常见副作用之一.
在你的代码中,
char *s = "hello";
Run Code Online (Sandbox Code Playgroud)
本质上将字符串文字 的起始地址"hello"放入s.现在,是否要修改*s(或者*(s+n),提供n不出界)的内容,它实际上会尝试修改该字符串文字.通常,字符串文字存储在只读存储器中,通常不允许修改它们.引用C11,第6.4.5章,字符串文字,(强调我的)
如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的.如果程序试图修改此类数组,则行为未定义.
但是,在你的第二个案例中,你正在做
char *s = argv[1];
Run Code Online (Sandbox Code Playgroud)
这是把价值argv[1]放进去的s.现在,s指向串联的字符串argv[1].这里,argv[1](或者,argv[n]通用)的内容不是只读的,可以修改.因此,使用*s(或者*(s+n),提供n不超出范围),您可以修改内容.
这种情况是定义的行为,因为根据§5.1.2.2.2,程序启动
数组指向的参数
argc和argv字符串argv应由程序修改,并在程序启动和程序终止之间保留它们最后存储的值.
因此,第二种情况是使用时的特殊情况argv[n],这是由C标准规则可修改的.