我从某个地方拿到了这个程序,并试图理解它。
这一行:s[j++] = s[i];
是导致崩溃的原因。我的理解是,至少程序第一次不应该崩溃,因为j将在稍后增加。第一次j和我的值将为0.
所以,这就像s [0] = s [0];
为什么会崩溃?
#include <iostream>
using namespace std;
void squeeze(char a[], char c);
int main()
{
squeeze("qwiert", 'i');
return 0;
}
void squeeze(char s[], char c)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
{
if (s[i] != c)
{
std::cout << "\ni: " << s[i];
s[j++] = s[i];
std::cout << "\nj: " << s[j];
std::cout << "\nj : " << j;
exit(0);
}
}
s[j] = '\0';
}
输出:
i: q
此后程序崩溃。
我已经使用exit语句来停止指向查找segfault的程序。
答案 0 :(得分:4)
您不得更改字符串文字,例如:
squeeze("qwiert", 'i');
这几乎涵盖了标准(a)的所有迭代:
C++03 2.13.4.String literals [lex.string] /2
; C++11 2.14.5.String literals [lex.string] /12
;和C++14 2.14.5.String literals [lex.string] /13
。每个都有相同的措辞:
是否所有字符串文字都是不同的(即存储在非重叠对象中)是实现定义的。 尝试修改字符串文字的效果未定义。
最新的C ++ 17标准中的措辞略有改变,但目前大致相同,C++17 5.13.5.String literals [lex.string] /16
:
是否所有字符串文字都是不同的(即,存储在非重叠对象中)以及是否对字符串文字的连续评估产生相同或不同的对象是未指定的。 [注意: 尝试修改字符串文字的效果未定义。 - 结束注释]
我建议您尝试类似的事情:
char str[] = "qwiert"; // Make a writable copy.
squeeze(str, 'i'); // then fiddle with that.
(a)这个答案中的ISO引用实际上提供了关于为什么这种情况的暗示。
我们并不总是拥有数GB的机器,并且通常情况下必须采取某些步骤来优化早期的编译器(C主要是由于它的初始实现而被转移到C ++中)作为C)的前端。
为此,具有相同字符的两个字符串(或以某些方式重叠字符,例如"successful"
和"unsuccessful"
)可以共享相同的内存以减少空间。
当然,这意味着你不能在不影响另一方的情况下改变一方,这就是制定这条规则的原因。
答案 1 :(得分:4)
您将字符串常量"qwiert"
传递给squeeze
函数。此函数然后尝试修改字符串常量,这是非法的。这会导致核心转储。
为此,你需要传入一个数组:
int main()
{
char str[] = "qwiert";
squeeze(str, 'i');
return 0;
}
答案 2 :(得分:3)
其他答案指出了问题以及解决方法。
我想指出,您可以通过提高编译器的警告级别来检测此类错误。
使用g++ -Wall
,我收到以下警告消息:
socc.cc: In function ‘int main()’:
socc.cc:10:26: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
squeeze("qwiert", 'i');