简体   繁体   中英

Expression: String iterator not dereferencable

I'm having a hard time using std::string::iterators in C++. This code compiles fine (still not getting correct output, but that's my fault: TODO, fix algorithm) in Dev-C++, and I don't get runtime errors. The error is with Visual Studio Express 2008 C++, where I'm getting an error pointing to < xstring>: "Expression: string iterator not dereferencable," and points to line 112 of the < xstring> file.

My debugging tells me I might be trying to dereference past the end of the sentence input, but I can't see where. Can anyone shed some light?

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

Firstly, use operator!=() on iterators, not operator<():

while (it != sentence.end())

Secondly, this is backwards: while (*it != ' ' && it != sentence.end())

You do something with the iterator, than check if the iterator is valid. Rather, you should check if it's valid first:

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

Thirdly, you should use ++iterator over iterator++, though this isn't related to your crashing.


Fourth, a main issue is here:

*it = '\n';

Because of the preceeding check, while (it != sentence.end() , it's possible to reach that iterator dereference while being at the end. A fix would be to do this:

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

So now if you have reached the end, you stop.


After fixing the previous issue, now the only problem is this:

//skip the space
++it;

This assumes that the character you are skipping is in fact a space. But what about the end of the string? Run this function with this string:

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

And it will succeed; it skips the space, putting the iterator at end() , the loop exits and success.

However, without the space it will crash, because you have reached the end, and are skipping past the end. To fix, add a check:

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

Resulting in this final code:

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

You might notice this seems like it has a lot of redundant checks. This can be fixed:

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

Hopefully that helps!

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

changes to

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

so the second expression isn't evaluated if the first if false.

   if (nextWordLength > distanceFromWidth)

should probably change to

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

Almost certainly your error is the result of:

*it = '\n';

Since in the preceding while loop one of your stopping conditions is:

it != sentence.end()

If it == sentence.end(), then *it = '\\n' won't fly

There are more errors, but that's the one that's causing your current problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM