这两个代码必须更改字符<ul>
<li>
<a href='#'>Main</a>
<ul>
<li>
<a href='#'>Submenu 1</a>
</li>
<li>
<a href='#'>Submenu 2</a>
</li>
<li>
<a href='#'>Submenu 3</a>
</li>
</ul>
</li>
</ul>
2
'4'
当我运行时,我在运行时会出现分段错误:
int main(int argc, char *argv[]){
char *s = "hello";
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
我知道还有其他方法可以做到这一点。两个程序有什么区别?
答案 0 :(得分:6)
在第一种情况下,您通过尝试修改字符串文字来面对undefined behaviour。分段错误是UB常见的副作用之一。
在您的代码中,
char *s = "hello";
基本上将字符串文字 "hello"
的起始地址放入s
。现在,您是否要修改*s
(或*(s+n)
的内容,前提是n
不超出范围),它实际上会尝试修改字符串文字< / em>的。通常,字符串文字存储在只读存储器中,它们通常不允许被修改。引自C11
,章节§6.4.5,字符串文字,(强调我的)
如果这些数组的元素具有适当的值,则未指定这些数组是否相同。 如果程序试图修改此类数组,则行为未定义。
然而,在你的第二个案例中,你正在做
char *s = argv[1];
将argv[1]
的值放入s
。现在,s
指向{em>字符串,并附有argv[1]
。这里,argv[1]
(或argv[n]
的内容不是只读的,可以修改。因此,使用*s
(或*(s+n)
,提供的n
不会超出范围),您可以修改内容。
此案例是已定义的行为,因为根据§5.1.2.2.2,程序启动
参数
argc
和argv
以及argv
数组指向的字符串应由程序修改,并保留其最后存储的值在程序启动和程序终止之间。
所以,第二种情况是使用argv[n]
时的特殊情况,这是C标准规则,可以修改。
答案 1 :(得分:4)
正如Sourav所说,尝试修改字符串文字会调用未定义的行为。如果您交替执行以下操作,则可以正常工作。
function clearOptions(select) {
var selectParentNode = select.parentNode;
if (selectParentNode) {
var newSelect = select.cloneNode(false); // Make a shallow copy
selectParentNode.replaceChild(newSelect, select);
return newSelect;
}
return undefined;
}
function appendSelectHtml(data, target) {
var selectHtml = [];
$(data.items).each(function () {
var selected = this.Selected ? ' selected' : '';
var option = "<option value='" + this.Value + "'" + selected + ">" + this.Text + "</option>";
selectHtml.push(option);
});
target = $(clearOptions(target[0])); //The item that was contained in the selector isn't in the DOM anymore
target.append(selectHtml.join(""));
}
答案 2 :(得分:3)
当你这样做时
char *s = "hello";
您指定*s
指向字符串文字的开头,不可修改。这意味着您可以读取那里有什么但你无法改变它(这就是为什么
*(s+2)='4';
给你一个分段错误。
在你的第二种情况下,你没有给你的指针一个字符串文字,所以你可以修改它。
事实上,在您的第二种情况下,您使用的argv
具体解释为可在c标准中修改。
答案 3 :(得分:0)
字面值:'hello'在只读内存中,因此无法更改。
尝试更改它会导致seg错误事件
尝试从argv []更改字符串数组有同样的问题。值只读
尝试更改命令行参数会导致seg fault事件。
您可以使用:'char s [] =“hello”; '因为这会把文字放在堆栈上,可以改变它。
您可以在获取命令行参数的长度并为该长度执行malloc()后复制'strcpy()<1