用指针修改一个string
这两个代码必须改变字符'4'
的字符2
int main(int argc, char *argv[]){ char *s = "hello"; *(s+2)='4'; printf( "%s\n",s); return 0; }
当我运行这个时,我得到分段错误,而当我运行这个:
int main(int argc, char *argv[]){ char *s = argv[1]; *(s+2)='4'; printf( "%s\n",s); return 0; }
我知道还有其他方法可以做到这一点。 这两个程序有什么区别?
在你的第一种情况下,你正试图修改一个string文字来面对未定义的行为 。 分段故障是UB常见的副作用之一。
在你的代码中,
char *s = "hello";
基本上把string文字 "hello"
的起始地址放在s
。 现在,你想修改*s
(或*(s+n)
,如果n
不超出范围),它实际上会试图修改该string 。 通常,string文本存储在只读存储器中, 通常不允许修改。 引用C11
,第6.4.5节, string (强调我的)
没有说明这些数组是否是不同的,只要它们的元素具有适当的值。 如果程序试图修改这样一个数组,行为是不确定的。
但是,在第二种情况下,你在做
char *s = argv[1];
将argv[1]
的值argv[1]
s
。 现在, s
指向由argv[1]
包含的string 。 这里, argv[1]
(或者argv[n]
)的内容不是只读的,可以修改。 所以,使用*s
(或*(s+n)
,如果n
不超出范围),您可以修改内容。
这种情况是定义的行为 ,因为按照§5.1.2.2.2, 程序启动
参数
argc
和argv
以及argv
数组所指向的string应该可以被程序修改 ,并在程序启动和程序终止之间保留它们的最后存储的值。
所以,第二种情况是使用argv[n]
一种特殊情况,它是由C标准规则可修改的。
正如Sourav所说,尝试修改string文字会调用未定义的行为。 如果你交替做了以下,它会正常工作。
int main(int argc, char *argv[]){ char s[] = "hello"; *(s+2)='4'; printf( "%s\n",s); return 0; }
当你这样做
char *s = "hello";
您将*s
指定为不可修改的string文本的开头。 这意味着你可以阅读那里有什么,但你不能改变它(这是为什么
*(s+2)='4';
给你一个分段错误。
在你的第二种情况下,你没有给你的指针一个string文字,所以你可以修改它。
事实上,在你的第二种情况下,你正在使用argv
,这个特殊的解释是在c标准中可以修改的。
字面意思:'你好'是只读内存,所以不能改变。
试图改变它导致seg故障事件
尝试从argv []更改string数组有同样的问题。 值是只读的
尝试更改命令行参数会导致seg故障事件。
你可以使用:'char s [] =“hello”; “因为这将把文字放在堆栈上,在那里可以改变。
你可以在获得命令行参数的长度后复制“strcpy()”,并执行该长度的malloc()+ 1