使用指针修改字符串

jou*_*r92 2 c string

这两个代码必须更改字符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)

我知道还有其他方法可以做到这一点.两个程序有什么区别?

Sou*_*osh 6

在第一种情况下,您通过尝试修改字符串文字来面对未定义的行为.分段错误是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,程序启动

数组指向的参数argcargv字符串argv应由程序修改,并在程序启动和程序终止之间保留它们最后存储的值.

因此,第二种情况是使用时的特殊情况argv[n],这是由C标准规则可修改的.

  • 对于新手来说,这个答案很难理解. (2认同)