如果两个值相同,为什么断言失败?

时间:2015-07-08 19:50:44

标签: c++ string assertion

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

//为什么断言失败? removeNonAlphas结果(&#34; abcabc&#34;)与 // rhs&#34; abcabc&#34;

3 个答案:

答案 0 :(得分:3)

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

这使得它使用'\0'重新定位角色,但不删除它。因此,输出不是"abcabc"而是"abc\0abc"'\0'不可打印,因此您不会在输出中看到它,但在将其与==进行比较时会显示。

不是替换字符串中的字符,而是在迭代旧字符串时创建一个新字符串:

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

注意:更喜欢使用std::isalpha而不是硬编码值。

答案 1 :(得分:1)

两个值都不相同,但区别在于非打印字符,因此您无法看到与cout和肉眼有任何差异。

尝试使用适当的工具(如调试器),您将看到函数结果中存在额外的\0字符。

答案 2 :(得分:1)

您实际上并没有删除字符串中的任何字符。你只是给它们赋值0.它只是看起来有效 - 这是最糟糕的。 '\0'只是一个不可打印的字符,这就是为什么它看起来像是打印相同的。 ==实际上会检查每个角色,即使是不可打印的角色,所以它会捕捉到你看不到的东西。

值得庆幸的是,string类通过提供这样的成员函数,使erase字符变得容易:

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

现在仅凭这还不够。你删除一个字符,现在i“指向”下一个元素 - 但你不会检查它。如果我们有"abc12abc",则在删除1后,我们会跳过2。所以我们需要改变迭代的方式:

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

那会有用。它也非常冗长。而且容易出错。这就是为什么我们有擦除 - 删除习语:

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