Reputation: 557
I have this peculiar requirement where I need to remove all space characters before a specific character which is a pipe'|'. I have written a test code for it which is actually printing the right output but additionally gifting me a core file :(
My code is below:
int main()
{
string line="1 2 |3 4| hbvhwf wjff wenf|hjbcwbfw ejwef efwk dfkwe|jsv |";
cout <<line<<endl;
string::iterator ite =(line.begin());
int counter=0;
int index=0;
int start=0;
while(ite != (line.end()))
{
if(*ite == '|' && counter > 0)
{
line.erase(start,counter);
counter=0;
cout<<line<<endl;
}
if(ite!=line.end())
{
if(isalnum(*ite))
{
counter=0;
}
if(*ite==' ')
{
if(!counter)
{
start=index;
}
counter++;
}
ite++;
index++;
}
}
cout<<line<<endl;
}
I am just going nuts in finding the root cause of the core dump. Could anybody please help? expected output is:
1 2|3 4| hbvhwf wjff wenf|hjbcwbfw ejwef efwk dfkwe|jsv|
Upvotes: 1
Views: 135
Reputation: 7990
As Krzysztof's answer says, the reason of the core dump is the erase()
invalidated the iterators. To solve this, you need to reset the iterator correctly, use the range version of erase()
, your will get an iterator referring to the character that now occupies the position of the first character erased, and assign it to ite. Change the first if statement to the code below, it should work fine.
if(*ite == '|' && counter > 0)
{
ite = line.erase(ite - counter, ite);
counter=0;
cout<<line<<endl;
}
Upvotes: 1
Reputation: 10252
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
int main()
{
string line="1 2 |3 4| hbvhwf wjff wenf|hjbcwbfw ejwef efwk dfkwe|jsv |";
cout <<line<<endl;
string res;
size_t length = line.size();
bool flag = false;
for (int i = length - 1; i >= 0 ; --i)
{
if (line[i] == '|')
{
res.push_back(line[i]);
flag = true;
}
else if (flag && line[i] == ' ')
{
}
else
{
res.push_back(line[i]);
flag = false;
}
}
copy(res.rbegin(), res.rend(), ostream_iterator<char>(cout, ""));
cout<<endl;
}
The ouput is:
1 2 |3 4| hbvhwf wjff wenf|hjbcwbfw ejwef efwk dfkwe|jsv |
1 2|3 4| hbvhwf wjff wenf|hjbcwbfw ejwef efwk dfkwe|jsv|
Upvotes: 0
Reputation: 4325
Calling erase()
on a string invalidates all iterators into the string, including ite
.
Specifically, when line.erase(start,counter);
executes, ite
is invalidated - it is no longer guaranteed to refer to a valid position in the string. If it's not equal to line.end()
, it can be dereferenced in the condition isalnum(*ite)
. Because ite
is invalidated at that point, it can refer to memory which is already freed (e.g. if the string was reallocated after being erased). Therefore this line causes a segfault.
Here is a simpler version of your code, which does not have the problem.
std::string line = ...;
unsigned space_run = 0;
for (unsigned i = 0; i < line.size(); ++i) {
if (line[i] == ' ') {
++space_run;
} else if (line[i] == '|') {
line.erase(i - space_run, space_run);
i -= space_run;
space_run = 0;
} else {
space_run = 0;
}
}
Upvotes: 1