表达式:字符串迭代器不可解除引用

jke*_*eys 0 c++ iterator dereference

我在C++中使用std :: string :: iterators很难.这段代码编译很好(仍然没有得到正确的输出,但这是我的错:TODO,修复算法)在Dev-C++中,我没有得到运行时错误.错误是使用Visual Studio Express 2008 C++,我收到指向<xstring>的错误:"Expression:string iterator not dereferencable",并指向<xstring>文件的第112行.

我的调试告诉我,我可能试图在句子输入结束时取消引用,但我看不到哪里.任何人都能解释一下吗?

std::string wordWrap(std::string sentence, int width)
{    
    std::string::iterator it = sentence.begin();

    //remember how long next word is
    int nextWordLength = 0;
    int distanceFromWidth = width;

    while (it < sentence.end())
    {
       while (*it != ' ' && it != sentence.end())
       {
          nextWordLength++;
          distanceFromWidth--;
          it++;
       }

       if (nextWordLength > distanceFromWidth)
       {
          *it = '\n';
          distanceFromWidth = width;
          nextWordLength = 0;
       }

       //skip the space
       it++;

   }

   return sentence;    
}
Run Code Online (Sandbox Code Playgroud)

GMa*_*ckG 15

首先,在迭代器上使用operator!=(),而不是运算符<():

while (it != sentence.end())
Run Code Online (Sandbox Code Playgroud)

其次,这是倒退的: while (*it != ' ' && it != sentence.end())

您使用迭代器执行某些操作,而不是检查迭代器是否有效.相反,你应该先检查它是否有效:

while (it != sentence.end() && *it != ' ')
Run Code Online (Sandbox Code Playgroud)

第三,你应该使用++迭代器而不是迭代器++,尽管这与你的崩溃无关.


第四,主要问题在这里:

*it = '\n';
Run Code Online (Sandbox Code Playgroud)

由于前面的检查,while (it != sentence.end()在结束时可以到达迭代器解除引用.修复就是这样做:

if (it != sentence.end() && nextWordLength > distanceFromWidth)
Run Code Online (Sandbox Code Playgroud)

所以,如果你已经到了最后,你就停止了.


修复上一个问题后,现在唯一的问题是:

//skip the space
++it;
Run Code Online (Sandbox Code Playgroud)

这假设你跳过的角色实际上是一个空间.但是字符串的结尾怎么样?使用此字符串运行此函数:

"a test string " // <- space at end

它会成功; 它会跳过空间,将迭代器放在end(),循环退出并成功.

然而,没有空间它会崩溃,因为你已经到了最后,并且正在跳过结束.要修复,请添加一个检查:

//skip the space
if (it != sentence.end())
{
    ++it;
}
Run Code Online (Sandbox Code Playgroud)

导致最终的代码:

std::string wordWrap(std::string sentence, int width)
{    
    std::string::iterator it = sentence.begin();

    //remember how long next word is
    int nextWordLength = 0;
    int distanceFromWidth = width;

    while (it != sentence.end())
    {
        while (it != sentence.end() && *it != ' ')
        {
            nextWordLength++;
            distanceFromWidth--;
            ++it;
        }

        if (it != sentence.end() && nextWordLength > distanceFromWidth)
        {
            *it = '\n';
            distanceFromWidth = width;
            nextWordLength = 0;
        }

        //skip the space
        if (it != sentence.end())
        {
            ++it;
        }

    }

    return sentence;    
}
Run Code Online (Sandbox Code Playgroud)

您可能会注意到这似乎有很多冗余检查.这可以修复:

std::string wordWrap(std::string sentence, int width)
{    
    std::string::iterator it = sentence.begin();

    //remember how long next word is
    int nextWordLength = 0;
    int distanceFromWidth = width;

    while (it != sentence.end())
    {
        while (*it != ' ')
        {
            nextWordLength++;
            distanceFromWidth--;

            ++it;

            // check if done
            if (it == sentence.end())
            {
                return sentence;
            }
        }

        if (nextWordLength > distanceFromWidth)
        {
            *it = '\n';
            distanceFromWidth = width;
            nextWordLength = 0;
        }

        //skip the space
        ++it;
    }

    return sentence;    
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助!


Adr*_*iuk 5

while (*it != ' ' && it != sentence.end())
Run Code Online (Sandbox Code Playgroud)

改变为

while (it != sentence.end() && *it != ' ')
Run Code Online (Sandbox Code Playgroud)

所以如果第一个表达式为false,则不计算第二个表达式.

   if (nextWordLength > distanceFromWidth)
Run Code Online (Sandbox Code Playgroud)

应该改为

   if (it == sentence.end())
         break;
   if (nextWordLength > distanceFromWidth)
Run Code Online (Sandbox Code Playgroud)