Ответы до сих пор предоставили альтернативные алгоритмы, которые можно отсортировать по двум классам:
- полностью изменить предложение и полностью изменить все слова в нем. Некоторые версии сначала меняют слова, в то время как другие сначала меняют предложение; порядок применения этих разворотов не имеет значения. Чистый эффект состоит в том, что слова появляются в обратном порядке, но символы в каждом слове находятся в их обычном порядке.
- Поместите слова в стек, затем снова извлеките их из стека, чтобы последнее слово стало первым.
Вместо того, чтобы предлагать еще один альтернативный алгоритм (который, вероятно, подпадает под одну из двух вышеупомянутых категорий), я объясню, почему код в исходном вопросе не работает должным образом.
Во-первых, обратите внимание, что код в вопросе на самом деле является вариантом класса 1. Сначала он полностью переворачивает предложение, а затем переворачивает каждое слово:
/* Outer loop goes backwards through the array, effectively reversing the sentence */
for(i = 99; i >= 0; i--) {
if(sentence[i] == ' ') {
/* Inner loop goes forward, reversing the word again */
while(sentence[i + j] != ' ') {
printf("%c", sentence[i + j]);
j++;
}
j = 1;
printf(" ");
}
}
Помимо некоторых ошибок новичка, это на самом деле оптимальный способ перевернуть слова предложения. Он не использует никакой дополнительной памяти и не тратит время.
Аскер отметил, что алгоритм работает так, как задумано, за исключением того, что он не печатает первое слово исходного предложения (которое должно стать последним словом). Причина этого в том, что обход массива останавливается на ' '
в обоих направлениях. Когда внешний цикл достигает начала предложения, он не находит пробела, потому что первый символ пользовательского ввода перезаписывает пробел в sentence[0]
:
/* ... */
char sentence[100] = { ' ' }, c, tc;
/* ... */
int i = 0, j = 1, size = 0;
/* Get the sentence */
printf("Enter a sentence: \n");
for(c = getchar(); (c != '.') && (c != '!') &&
(c != '?') && (c != '\n'); c = getchar(), i++) {
sentence[i] = c; /* Store the current character in the array */
size++; /* Increase the sentence's size */
}
Следовательно, когда i
становится 0
во внешнем цикле, пробела нет, и внутренний цикл, который должен печатать слово, начинающееся с sentence[0]
, никогда не вводится. i
затем уменьшается до -1
и внешний цикл завершается.
Вы можете проверить это без изменения кода, просто запустив программу от имени пользователя. Если вы введете пробел в качестве первого символа, ответ программы будет правильным:
Enter a sentence:
you can cage a swallow can't you?
you can't swallow a cage can you?
Существует два способа принудительного включения первого слова в ваш код. Первый - просто всегда ставить пробел в начале массива sentence
. Вы можете сделать это, начав копировать пользовательский ввод с i = 1
вместо i = 0
:
/**
* Declare a loop counter already initialized at 1, an incremental
* variable, as well as the size of the read sentence
*/
int i = 1, j = 1, size = 0;
Другой, немного менее элегантный способ - просто повторить внутренний цикл после завершения внешнего цикла:
/**
* Go backward through the array, printing each sequence of characters
* between spaces
*/
for(i = 99; i >= 0; i--) {
if(sentence[i] == ' ') {
while(sentence[i + j] != ' ') {
printf("%c", sentence[i + j]);
j++;
}
j = 1; /* Reset the incremental variable */
printf(" "); /* Print a tailing space */
}
}
/* print the last word */
while(sentence[i + j] != ' ') {
printf("%c", sentence[i + j]);
j++;
}
Вы можете сделать это менее повторяющимся, выделив внутренний цикл для новой функции. Вот весь алгоритм с внутренним циклом, выделенным для функции print_word
, пропуская комментарии и пустые строки:
#include<stdio.h>
void print_word(char[] sentence, int i) {
int j = 1;
while(sentence[i + j] != ' ') {
printf("%c", sentence[i + j]);
j++;
}
}
int main(void) {
char sentence[100] = { ' ' }, c, tc;
int i = 0, j = 1, size = 0;
printf("Enter a sentence: \n");
for(c = getchar(); (c != '.') && (c != '!') &&
(c != '?') && (c != '\n'); c = getchar(), i++) {
sentence[i] = c; /* Store the current character in the array */
size++; /* Increase the sentence's size */
}
tc = c; /* Get the terminating character */
for(i = 99; i >= 0; i--) {
if(sentence[i] == ' ') {
print_word(sentence, i);
printf(" "); /* Print a tailing space */
}
}
print_word(sentence, i);
printf("\b%c\n", tc);
return 0; /* Return 0 upon successful program execution */
}
В качестве последнего замечания, есть еще одна вещь, которую вы могли бы сделать лучше. Прямо сейчас внешний цикл начинается с i = 99
, последнего возможного символа в массиве sentence
. Однако, читая пользовательский ввод, вы обновили i
, чтобы указывать на следующую позицию ввода, поэтому непосредственно перед началом внешнего цикла i
уже указывает на первый символ после предложения. Почему бы не использовать это и просто начать с i - 1
?