回文字符串问题:为啥我必须放 +1 而不是 -1 才能使这段代码工作?

Posted

技术标签:

【中文标题】回文字符串问题:为啥我必须放 +1 而不是 -1 才能使这段代码工作?【英文标题】:Palindrome string problem: Why did I have to put +1 instead of -1 to make this code work?回文字符串问题:为什么我必须放 +1 而不是 -1 才能使这段代码工作? 【发布时间】:2019-01-31 18:51:33 【问题描述】:

我正在编写一个程序来检查一个字符串是否是回文并且它一开始没有工作,随机做了一些事情让它工作,现在我不知道它为什么工作。

代码如下:

#include <iostream>
#include <string>

using namespace std;

int main()

string s, copie; //copie means copy in romanian
int i, aux, OK;
cout<<"Enter the string/word: "; cin>>s;
copie=s;
for(i=0; i<=copie.length()+1; i++)

    aux=copie[i];
    copie[i]=copie[copie.length()-i+1];
    copie[copie.length()-i+1]=aux;

OK=1;

for(i=0; i<s.length(); i++)
    if(s[i]!=copie[i])
        OK=0;
if(OK==1)
    cout<<"yes";
else
    cout<<"no";
return 0;

现在通常应该是

for(i=0; i<=copie.length()-1; i++) 

for(i=0; i < copie.length(); i++) 

因为字符串是从 0 开始索引的,字符串的最后一个字符是它的长度减 1。但一开始它不起作用,所以我添加了一些 couts 来检查错误(我们可以说是出于调试目的)和副本错过了前两个字符。例如,如果我输入“cojoc”,我会得到“@joc”。就像wtf?然后将

【问题讨论】:

for(i=0; i&lt;=copie.length()+1; i++) -- 这永远无法正常工作,尤其是在for 循环内,你有copie[i]。如果您需要说服它完全错误,请将您对[ ] 的使用替换为对at() 的调用。你会得到一个out_of_range 异常抛出,并且没有输出来思考“为什么它工作”。 @PaulMcKenzie 那为什么它在我的编译器上对任何字符串都能完美运行? 使用[ ] 访问是未定义的行为。你很幸运它有效。去掉“运气”,at() 函数会告诉你你错了。 @paulmckenzie 他知道自己错了:问题是为什么...... 考虑未定义的行为是 IMO 浪费时间。 【参考方案1】:

这是你的问题:

for(i=0; i<=copie.length()+1; i++)

    aux=copie[i];
    copie[i]=copie[copie.length()-i+1]; // <<<<<
    copie[copie.length()-i+1]=aux;

通过计算此索引 ([copie.length()-i+1]),您减去 i,然后将长度加 1。你可能认为你减去了i 和 1 的总和,但减法在数学或编程中并不像这样。

使用括号将解决您的问题:

for(i=0; i < copie.length(); i++)

    aux=copie[i];
    copie[i]=copie[copie.length()-(i+1)]; // <<<<<
    copie[copie.length()-(i+1)]=aux;

也就是说,您的代码可能会更高效。但是,因为它看起来像家庭作业,所以这不是问题的重点。

【讨论】:

补充:我忘了在 for(i=0; i “也就是说,你的代码可能更有效。但是,因为它看起来像家庭作业,所以这与问题无关。”出于好奇,它怎么能更有效?我想学习。 @Sirmyself 可以直接比较[first char] == [last char][second char] == [second last char]等直到中间。一旦你得到不同,它就不是回文【参考方案2】:

您的程序适用于所有字符串的原因是因为在您的循环中,您正在遍历字符串中的每个字符因为您正在交换字符。这意味着,一旦您通过了中间点,您正在对已经交换并再次交换它们的角色进行操作。本质上,您通过再次反转字符串来撤消反转。

另外,正如@PaulMcKenzie 所说,您使用copie.length() 作为循环的上限,这只是自找麻烦。对于普通数组,i 的最后一个值将访问数组外的元素,这将引发错误或访问未定义的值(取决于您在哪个平台上运行此代码。它仍在工作的原因这是因为 C+ 使用隐式空字符 (\0) 终止字符串,这就是您在使用 copie[copie.length()] 时访问的内容。通常这会在您将空字符与第一个字符交换时导致问题,但是因为您稍后将它们交换回来,此行为会自行纠正。

相反,您应该做的是遍历输入字符串的一半,以便进行反转然后停止。另外,在处理任何字符串或数组时使用copie.length()-1 来获取最后一个索引中的元素:

for(i = 0; i < copie.length() / 2; i++)

  aux=copie[i];
  copie[i]=copie[copie.length()-1-i];
  copie[copie.length()-1-i]=aux;

【讨论】:

以上是关于回文字符串问题:为啥我必须放 +1 而不是 -1 才能使这段代码工作?的主要内容,如果未能解决你的问题,请参考以下文章