分解你的算法。首先,您找到字符串的长度,不包括空字符终止符。这是正确的,尽管可以简化。
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
这可以很容易地写成:
size_t len = 0;
while (sentence[len])
++len;
接下来,您反转整个字符串,但第一个缺陷表面。您在此处声明的 VLA(可变长度数组)(您不需要也不应该使用,因为它是 C++ 扩展且非标准)不考虑也不设置终止空字符。
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
根本不需要这个临时缓冲区字符串。您没有理由不能就地完成整个操作。一旦我们计算len
正确,您只需执行以下操作即可反转整个序列,从而将空字符终止符保留在适当的位置:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
接下来我们转到您尝试反转每个内部单词的地方。同样,就像以前一样,缓冲区长度不正确。应该是len+1
。更糟糕的是(难以想象),当你找到一个单词的结尾时,你永远不会记得你离开的地方。该位置应该是您开始检查和跳过空白的下一个点。在不保留从当前点一直复制到字符串开头的情况下。这基本上爆炸cats
了dogs
。
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
再一次,这可以毫无困难地就地完成。一种这样的算法看起来像这样(并注意反转实际单词的循环与反转整个缓冲区的算法并不巧合):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
把它们放在一起
尽管使用指针比所有这些索引变量要简单得多,但以下内容将就地完成您正在尝试的操作。
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
输出
dogs like cats
cats like dogs