Разбивая алгоритм на части. Во-первых, вы находите длину строки, не включая ограничитель нулевого символа. Это правильно, хотя можно упростить.
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 (массив переменной длины), который вы объявляете здесь (который вам не нужен и не должен использоваться, поскольку это расширение С++ и нестандартно), не учитывает и не устанавливает завершающий нулевой символ.
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
person
WhozCraig
schedule
13.08.2014
strrev
(оставлено в качестве упражнения для читателя). Используйте его, чтобы перевернуть все предложение. Затем приступайте к поиску пробелов и поиску отдельных слов. - person Igor Tandetnik   schedule 13.08.2014m
ведет обратный отсчет до 0 для каждого слова. Если я правильно понимаю, вы имели в виду, что он будет отсчитываться только до конца предыдущего слова. - person jogojapan   schedule 13.08.2014