我从某个地方获取了该程序,并试图理解它。
这行:s[j++] = s[i];是崩溃的原因。 我的理解是,至少第一次程序不会崩溃,因为j以后会增加。 第一次j和i的值将为0。
因此,这将类似于s [0] = s [0];
为什么会崩溃?
#include
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 <
i:" << s[i];
s[j++] = s[i];
std::cout <
j:" << s[j];
std::cout <
j :" << j;
exit(0);
}
}
s[j] = '\0';
}
输出:
i: q
之后,程序崩溃。
我已经将exit语句停止了指向该段的程序。
为s保留的地址空间可以写保护吗?因为在main()中,它的定义类似于常量,因此编译器可以将其放入特殊的内存区域。但这只是一个猜测。
是的,那是原因。 @KillPinguin
编译时收到以下警告:" ISO C ++禁止将字符串常量转换为char * [-Wwrite-strings]"。一些编译器会完全拒绝此操作(从技术上来说,所有人都应该如此),并给您一个错误。该程序将带有警告编译,但是警告表示某些东西不是完全符合犹太洁食原则,并且该程序很可能不会按照您期望的方式运行。
@ user4581301,实际上标准中没有任何内容强制要求完全拒绝UB。虽然这可能是一个好功能,但您可能应该区分需要什么和有用。
在C ++ 11中@paxdiablo将字符串文字直接转换为char*的操作被正式禁止,但是,是的,我不知道Aquarius_Girl编译的标准是什么。
@ user4581301,C ++ 03中存在相同的措词,尽管在2.13.4中存在了很长时间。病态更新我的答案,以包括在内。
@ paxdiablo我也找不到。 Ive遇到编译器错误,并有一般评论将其称为事实,但我无法在最近的标准中找到彻底的禁令。并不意味着2003年有一个例外,它允许进行2011年没有的转换,但我无法使用C ++ 2014之前的任何版本。
Ive还一直在研究隐式转换和初始化规则。
在附录C(di?.lex):char* p ="abc"; valid in C, invalid in C++中找到了它,但在阅读它引用进行此调用的规则时,无法建立相同的连接。
您正在将字符串常量"qwiert"传递给squeeze函数。然后,此函数尝试修改该字符串常量,这是非法的。这会导致核心转储。
为此,您需要传递一个数组:
int main()
{
char str[] ="qwiert";
squeeze(str, 'i');
return 0;
}
刚刚尝试过。 问题已解决。 非常感谢您。
您不得使用以下方式更改字符串文字:
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。
每个中存在相同的措词:
Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation-defined. The effect of attempting to modify a string literal is undefined.
在最新的C ++ 17标准中,措词已稍有变化,但大致相同,目前为C++17 5.13.5.String literals [lex.string] /16:
Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified. [Note: The effect of attempting to modify a string literal is undefined. - end note]
我建议您尝试类似的方法:
char str[] ="qwiert"; // Make a writable copy.
squeeze(str, 'i'); // then fiddle with that.
(a)该答案中的ISO引号实际上是在暗示为什么会这样。
我们并不总是拥有数千兆字节的机器,通常情况下,在早期的编译器中必须采取某些步骤来进行优化(大多数情况下使用C语言,但由于其最初的实现是C语言的前端,因此已延续到C ++中)。
为此,具有相同字符(或以某些方式重叠的字符,例如"successful"和"unsuccessful")的两个字符串可以共享相同的内存以减少空间。
当然,这意味着您不能在不影响另一个的情况下更改一个,这就是为什么要应用此规则的原因。
其他答案指出了问题以及如何解决。
我想指出,您可以通过提高编译器的警告级别来检测此类错误。
使用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');