user4778573
user4778573

Reputation:

Why does assertion failed if both values are the same?

string removeNonAlphas(string original)
{
    for(int i = 0; i < original.size(); ++i){
        if(!(original[i] > 64 && original[i] < 91) &&
           !(original[i] > 96 && original[i] < 124)){
            original[i] = original[i] - original[i];
        }
    }
    return original;
}

//test1.cpp

string test = "abc abc";
cout << removeNonAlphas(test) << endl; // output = "abcabc"
assert(removeNonAlphas(test) == "abcabc"); // assertion failed

//Why does assertion fail above? removeNonAlphas result("abcabc") is same as //rhs "abcabc"

Upvotes: 0

Views: 686

Answers (3)

Barry
Barry

Reputation: 302643

You're not actually erasing any characters from your string. You're just assigning them the value 0. It just looks like it works - which is just the worst. The '\0' is just a non-printable character, which is why it looks like it prints the same. The == will actually check every character, even the non-printable ones, so it'll catch what you can't see.

Thankfully, the string class makes it easy to erase characters by providing just such a member function:

original.erase(i, 1); // erase a single character starting at i

Now that alone isn't enough. You erase a character, and now i is "pointing" to the next element - but you won't check it. If we had "abc12abc", after erasing the 1, we'd skip the 2. So we need to change how we iterate:

for (std::string::iterator it = original.begin();
     it != original.end();
     /* nothing */)
{
    // here's a better way to do checking
    if (!(*it >= 'A' && *it <= 'Z') &&
        !(*it >= 'a' && *it <= 'z'))
    {
        // erase(iterator ) will return the next iterator
        it = original.erase(it);
    }
    else
    {
        ++it;
    }
}

That'll work. It's also very verbose. And error-prone. Which is why we have the erase-remove idiom:

original.erase(
    std::remove_if(original.begin(),
                   original.end(),
                   [](char c) { return !std::isalpha(c); }),
    original.end()
);
return original;

Upvotes: 1

StenSoft
StenSoft

Reputation: 9609

original[i] = original[i] - original[i];

What this makes is that it repaces the character with '\0' but does not remove it. Because of that the output is not "abcabc" but "abc\0abc". '\0' is non-printable so you won't see it in the output but it is present when you compare it with ==.

Instead of replacing charactes in a string, create a new string while iterating the old one:

string removeNonAlphas(string const& original)
{
    std::string result;
    for(char c : original)
       if((c > 64 && c < 91) ||
          (c > 96 && c < 124))
           result.push_back(c);
    return result;
}

Note: prefer using std::isalpha instead of hard-coded values.

Upvotes: 3

Ben Voigt
Ben Voigt

Reputation: 283614

Both values are NOT the same, but the difference is a non-printing character, so you can't see any difference with cout and your naked eye.

Try a proper tool, like a debugger, and you will see the extra \0 character present in the function result.

Upvotes: 1

Related Questions