Вращение слов в C ++ и получение ошибок - PullRequest
0 голосов
/ 09 апреля 2020

Я пытаюсь создать программу в соответствии с подсказкой ниже, но продолжаю получать ошибку Caught std::exception, what(): basic_string::at: __n (which is 0) >= this->size() (which is 0), хотя я был solid на C ++, но я думаю, что время берет свое. Мой код ниже. По сути, сначала я анализирую строку по пробелу и сохраняю их в vector<string>, после чего проверяю, больше ли слово, чем 5, и переворачиваю его, если оно есть, и ничего не делаю, если это не так. Если это не последнее слово, я добавляю пробел в конце. Bing bang boom, быстрое завершение или, по крайней мере, я думал.

std::string spinWords(const std::string &str)
    {
      std::vector<std::string> words;
      std::string spinnedWord;
      int count = 0;
      for(unsigned int i = 0; i < str.length(); i++)
      {
          char currentChar = str.at(i);

          if (currentChar == ' ')
          {
              count++;
              continue;
          }
          else if((int)words.size() == count)
          {
              words.push_back(&currentChar);
          }
          else
          {
              words[count] += currentChar;
          }
      }
      for(unsigned int i = 0; i < words.size(); i++)
      {
          if(words[i].size() >= 5)
          {

              for (unsigned int j = words[i].length() - 1; j >= 0; j--)
              {
                  spinnedWord += words[j].at(i);
              }
          }
          if(i + 1 != words.size())
          {
              spinnedWord += ' ';
          }
      }
      return spinnedWord;
    }// spinWords

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

Edit1: я изменил words[j].at(i); на words[i].at(j); и изменил words.push_back(&currentChar); на words.push_back(std::string(1, currentChar));

Из того, что я сейчас понимаю, когда я отталкивался &currentChar, я вызывал неопределенное поведение. Я посмотрю, как этого избежать в будущем. Тем не менее, ошибка до сих пор сохраняется, поэтому вопрос остается без ответа

Ответы [ 3 ]

4 голосов
/ 09 апреля 2020
for (unsigned int j = words[i].length() - 1; j >= 0; j--)
{
   spinnedWord += words[j].at(i);
}

Вы поменялись j и i здесь. Это должно быть words[i].at(j). Также j, вероятно, не должно быть здесь без знака, потому что условие l oop j >= 0 всегда верно для целых чисел без знака.

EDIT: значение UB для строки words.push_back(&currentChar) также допустимо. Чтобы исправить это, нужно явно создать строку из char:

words.push_back(std::string(1, currentChar));
1 голос
/ 09 апреля 2020
          words.push_back(&currentChar);

Вы пытаетесь создать std::string из указателя на один символ. Это компилируется, потому что есть соответствующий конструктор, но он принимает строку в стиле C, которой не является ваш указатель на один символ.

0 голосов
/ 09 апреля 2020

Честно говоря, я даже не понимаю ваш код. Например, что переменная count делает в программе. Или почему вы используете дополнительный контейнер типа std::vector, когда все может быть и должно быть сделано с объектом типа std::string, потому что у него есть все ресурсы для выполнения задачи.

Контейнер std::vector требуется только в том случае, если назначение состоит в том, чтобы разбить строку на слова и вернуть слова в объект типа std::vector<std::string>. Но ваша задача совершенно иная.

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

Ваша функция не имеет смысла, например, когда исходная строка начинается с пробела персонаж. В этом случае count будет равен 1 из-за этого, если оператор

      if (currentChar == ' ')
      {
          count++;
          continue;
      }

, но размер вектора будет равен 0, так как words.size() не равен count тогда будет выполняться оператор else

      else if((int)words.size() == count)
      {
          words.push_back(&currentChar);
      }
      else
      {
          words[count] += currentChar;
      }

, что приводит к неопределенному поведению.

Я могу предложить следующее решение. В демонстрационной программе ниже я не использую стандартный алгоритм std :: reverse, потому что я думаю, что вы должны повернуть слово собственным кодом.

Вот, пожалуйста.

#include <iostream>
#include <string>
#include <utility>

std::string spinWords( const std::string &s, std::string::size_type length = 5 )
{
    std::string t( s );
    const char *delim = " \t";

    for ( std::string::size_type i = 0; i != t.size();  )
    {
        auto pos = t.find_first_not_of( delim, i );

        if ( pos != std::string::npos )
        {
            i = t.find_first_of( delim, pos );

            if ( i == std::string::npos ) i = t.size();

            if ( length < i - pos )
            {
                auto n = i - pos;

                for ( std::string::size_type j = 0; j < n / 2; j++ )
                {
                    std::swap( t[pos + j], t[i - j - 1] );
                }
            }
        }
        else
        {
            i = t.size();
        }
    }

    return t;
}

int main() 
{

    std::string s( "1 12 123 1234 12345 123456 1234567 123456789 1234567890" );

    std::cout << s << '\n';
    std::cout << spinWords( s ) << '\n';

    return 0;
}

Выход программы:

1 12 123 1234 12345 123456 1234567 123456789 1234567890
1 12 123 1234 12345 654321 7654321 987654321 0987654321
...