0

我很难在 C++ 中使用 std::string::iterators 。这段代码在 Dev-C++ 中编译得很好(仍然没有得到正确的输出,但这是我的错:TODO,修复算法),并且我没有得到运行时错误。错误出现在 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;    
}
4

3 回答 3

15

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

while (it != sentence.end())

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

你对迭代器做一些事情,而不是检查迭代器是否有效。相反,您应该首先检查它是否有效:

while (it != sentence.end() && *it != ' ')

第三,您应该使用 ++iterator 而不是 iterator++,尽管这与您的崩溃无关。


第四,一个主要问题在这里:

*it = '\n';

由于前面的检查,while (it != sentence.end()有可能在最后到达那个迭代器取消引用。解决方法是这样做:

if (it != sentence.end() && nextWordLength > distanceFromWidth)

所以现在如果你已经到了尽头,你就停下来。


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

//skip the space
++it;

这假设您要跳过的字符实际上是一个空格。但是字符串的结尾呢?使用此字符串运行此函数:

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

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

但是,如果没有空间,它会崩溃,因为您已经到达终点,并且正在跳过终点。要修复,请添加检查:

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

产生这个最终代码:

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

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

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

希望这会有所帮助!

于 2009-06-30T06:27:21.487 回答
5
while (*it != ' ' && it != sentence.end())

更改为

while (it != sentence.end() && *it != ' ')

因此,如果第一个表达式为假,则不会评估第二个表达式。

   if (nextWordLength > distanceFromWidth)

应该可能改为

   if (it == sentence.end())
         break;
   if (nextWordLength > distanceFromWidth)
于 2009-06-30T06:10:46.990 回答
0

几乎可以肯定你的错误是由于:

*it = '\n';

由于在前面的 while 循环中,您的停止条件之一是:

it != sentence.end()

如果 it == sentence.end(),那么 *it = '\n' 不会飞

还有更多错误,但这就是导致您当前问题的错误。

于 2009-06-30T07:31:13.020 回答