Expression: String iterator not dereferencable
-
21-08-2019 - |
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;
}
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.