【问题标题】:Expression: String iterator not dereferencable表达式:字符串迭代器不可取消引用
【发布时间】:2009-06-30 06:02:48
【问题描述】:

我很难在 C++ 中使用 std::string::iterators。这段代码在 Dev-C++ 中编译得很好(仍然没有得到正确的输出,但这是我的错:TODO,修复算法),而且我没有遇到运行时错误。错误出现在 Visual Studio Express 2008 C++ 中,我收到指向 的错误:“Expression: string iterator not dereferencable”,并指向 文件的第 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;    
}

【问题讨论】:

    标签: c++ iterator dereference


    【解决方案1】:

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

    while (it != sentence.end())
    

    其次,这是倒退:while (*it != ' ' &amp;&amp; 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 " // &lt;- 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;    
    }
    

    希望对您有所帮助!

    【讨论】:

    • +1。我已经更正了第 2 点中的代码,使其与完整的代码块和解释一致。
    • 谢谢。我知道 ++it(所以编译器知道复制掉额外的迭代器),以及使用 !=。使用 != 编译时出现错误,我让自己休息一下,因为我知道字符串是连续的。我不会对堆栈之类的东西做同样的事情。一个问题:在你的代码中,如果你在循环之外抛出异常不是更好吗?在您的解决方案中,您只需返回。这似乎可以掩盖一些严重的问题。
    • 我不确定我是否理解外部循环的含义。上面的代码是安全的,不需要抛出任何异常。
    【解决方案2】:
    while (*it != ' ' && it != sentence.end())
    

    更改为

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

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

       if (nextWordLength > distanceFromWidth)
    

    应该改成

       if (it == sentence.end())
             break;
       if (nextWordLength > distanceFromWidth)
    

    【讨论】:

      【解决方案3】:

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

      *it = '\n';
      

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

      it != sentence.end()
      

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

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

      【讨论】:

        猜你喜欢
        • 2012-07-25
        • 1970-01-01
        • 2012-10-30
        • 2017-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-11
        相关资源
        最近更新 更多