Средство преобразования простых предложений в C

#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 );
}
  

Наличие нескольких начальных или завершающих пробелов может быть вырожденным случаем в зависимости от того, как вы на самом деле хотите, чтобы они вели себя.