#c
#c
Вопрос:
Я пытаюсь создать программу для решения проблемы в учебнике, который я недавно купил, и это просто сводит меня с ума.
Мне нужно создать средство преобразования предложений, поэтому я получаю следующее:
Ввод = «Делать или не делать, попытки нет». Вывод = «попробуйте. нет, это не так, делай или Do»
Вот что у меня получилось на данный момент:
void ReverseString::reversalOperation(char str[]) {
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos 1];
while (stringReadPos >= 0) {
if (str[stringReadPos] == ' ') {
wordReadPos = stringReadPos 1;
buffer[writePos ] = str[stringReadPos--];
while (str[wordReadPos] != ' ') {
buffer[writePos] = str[wordReadPos];
writePos ;
wordReadPos ;
}
} else {
stringReadPos--;
}
}
cout << str << endl;
cout << buffer << endl;
}
Я был уверен, что нахожусь на правильном пути, но все, что я получаю на выходе, — это самое первое слово («попробуйте»). Я так долго смотрел на этот код, что не могу продвинуться ни на шаг. Изначально я проверял во внутреннем while look также наличие символа ‘/ 0’, но, похоже, ему это не понравилось, поэтому я удалил его.
Комментарии:
1. Вы на C , так что откажитесь от всей этой болтовни с указателями!
2. И если вы придерживаетесь неправильного указателя, пожалуйста, исправьте утечку памяти!
Ответ №1:
Если вы не чувствуете себя мазохистом, выбросьте существующий код и начните с std::vector
и std::string
(предпочтительно std::vector<std::string>
). Добавьте std::copy
с помощью вектора rbegin
и rend
, и вы в значительной степени закончили.
Ответ №2:
В C это очень просто с помощью стандартной библиотеки:
std::vector< std::string > sentence;
std::istringstream input( str );
// copy each word from input to sentence
std::copy(
(std::istream_iterator< std::string >( input )), std::istream_iterator< std::string >()
, std::back_inserter( sentence )
);
// print to cout sentence in reverse order, separated by space
std::copy(
sentence.rbegin(), sentence.rend()
, (std::ostream_iterator< std::string >( std::cout, " " ))
);
Ответ №3:
В интересах науки я попытался заставить ваш код работать как есть. Да, на самом деле это не совсем C способ делать что-то, но, тем не менее, поучительно.
Конечно, это только один из миллиона способов выполнить работу. Я оставлю это в качестве упражнения для вас, чтобы удалить пробел, который этот код оставляет в выходных данных 😉
Я прокомментировал свои изменения с помощью «РЕДАКТИРОВАТЬ».
char* buffer;
int stringReadPos, wordReadPos, writePos = 0;
// Position of the last character is length -1
stringReadPos = strlen(str) - 1;
buffer = new char[stringReadPos 1];
while (stringReadPos >= 0) {
if ((str[stringReadPos] == ' ')
|| (stringReadPos == 0)) // EDIT: Need to check for hitting the beginning of the string
{
wordReadPos = stringReadPos (stringReadPos ? 1 : 0); // EDIT: In the case we hit the beginning of the string, don't skip past the space
//buffer[writePos ] = str[stringReadPos--]; // EDIT: This is just to grab the space - don't need it here
while ((str[wordReadPos] != ' ')
amp;amp; (str[wordReadPos] != '')) // EDIT: Need to check for hitting the end of the string
{
buffer[writePos] = str[wordReadPos];
writePos ;
wordReadPos ;
}
buffer[writePos ] = ' '; // EDIT: Add a space after words
}
stringReadPos--; // EDIT: Decrement the read pos every time
}
buffer[writePos] = ''; // EDIT: nul-terminate the string
cout << str << endl;
cout << buffer << endl;
Комментарии:
1. Ой, ты меня опередил. Забавное упражнение, однако. 🙂
2. Вы также должны выделить strlen 1 для буфера, а не только strlen.
3. @konrad.kruczynski, отличное замечание. Моя ошибка в предположении, что 1 было добавлено в терминаторе. редактировать: и если бы я не изменил его, чтобы добавить пробел для каждого слова, это не было бы проблемой. Поэтому вместо того, чтобы редактировать это, я оставлю это с комментарием.
4. Большое вам спасибо! Я знаю, что есть другие вещи, которые я мог бы использовать (векторы и т.д.), Которые сделали бы это намного проще, Но смысл упражнения в том, чтобы просто использовать то, что у меня здесь есть.
Ответ №4:
Я вижу следующие ошибки в вашем коде:
- последнему символу буфера не присвоено значение 0 (это вызовет сбой в cout<
- во внутреннем цикле вы должны проверить
str[wordReadPos] != ' ' amp;amp; str[wordReadPos] != 0
иначе при сканировании первого слова он никогда не найдет завершающий пробел
Ответ №5:
Поскольку вы используете массив символов, вы можете использовать библиотеку строк C. Это будет намного проще, если вы используете strtok:http://www.cplusplus.com/reference/clibrary/cstring/strtok /
Для этого потребуется использовать указатель, но это значительно облегчит вашу жизнь. Вашим разделителем будет «».
Ответ №6:
В чем проблемы с вашим кодом и какие есть более cplusplusish способы выполнения, пока хорошо написано. Я хотел бы, однако, добавить, что методология
- напишите функцию / программу для реализации алгоритма;
- посмотрим, сработает ли это;
- если этого не происходит, просматривайте код, пока не поймете, в чем проблема
не слишком продуктивно. Что может помочь вам решить эту проблему здесь и многие другие проблемы в будущем, так это отладчик (и отладчик для бедных людей printf). Это позволит вам поэтапно увидеть, как на самом деле работает ваша программа, что происходит с данными и т.д. Другими словами, вы сможете увидеть, какие его части работают так, как вы ожидаете, а какие ведут себя иначе. Если вы используете * nix, не стесняйтесь попробовать gdb.
Ответ №7:
Вот еще одна версия на C . Хотя я думаю, что в данном случае простота важнее стиля. Базовый алгоритм достаточно прост: поменяйте местами слова, а затем переверните всю строку.
Вы могли бы написать код на C, который был бы столь же очевиден, как и версия на C . Я не думаю, что обязательно неправильно писать код, который здесь не является демонстративно C .
void word_reverse(std::string amp;val) {
size_t b = 0;
for (size_t i = 0; i < val.size(); i ) {
if (val[i] == ' ') {
std::reverse(amp;val[b], amp;val[b] (i - b));
b = i;
}
}
std::reverse(amp;val[b], amp;val[b] (val.size() - b));
std::reverse(amp;val[0], amp;val[0] val.size());
}
TEST(basic) {
std::string o = "Do or do not, there is no try.";
std::string e = "try. no is there not, do or Do";
std::string a = o;
word_reverse(a);
CHECK_EQUAL( e , a );
}
Наличие нескольких начальных или завершающих пробелов может быть вырожденным случаем в зависимости от того, как вы на самом деле хотите, чтобы они вели себя.