Question

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;    
}
Was it helpful?

Solution

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!

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top