用C++的string::size()和string::length()返回值做比較

樓主今天在自己實現kmp算法的c++代碼時,發現了一個問題。我先把代碼貼上來。

//kmp search
#include <iostream>
#include <vector>
using namespace std;

vector<int> GetNext(string pattern)
{
    vector<int> next(pattern.size(), -1);
    int i = 0;
    int j = -1;
    while(i < pattern.size())
    {
        if(j == -1 || pattern[i] == pattern[j])
        {
            i++;
            j++;
            if(pattern[i] != pattern[j])
                next[i] = j;
            else
                next[i] = next[j];
        }
        else
        {
            j = next[j];
        }
    }
    return next;
}

int KmpSearch(string text, string pattern)
{
    if(text.size() <= 0 || pattern.size() <= 0)
        return -1;
    vector<int> next = GetNext(pattern);
    int i = 0;
    int j = 0;
    int slen = text.size();
    int plen = pattern.size();
    while(i < slen && j < plen)//while(i < text.size() && j < pattern.size())
    {
        if(j == -1 || text[i] == pattern[j])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    if(j == pattern.size())
        return i-j;
    return -1;
}

int main(int argc, char const *argv[])
{
    string txt = "BBCAAAAB ABCDAB ABCDABCDABDE";
    string pat = "ABCDABD";
    cout << "index = " << KmpSearch(txt, pat) << endl;
    return 0;
}

請注意第39行,我原來寫的循環條件是如註釋一樣的。後來發現無論如何循環都只跑一遍,然後就退出了,不能得到正確的結果,思前想後都不知道到底是哪裏出了問題。然後纔將text.size()替換成了一個signed int型的數字,這才解決了問題。
這個時候我就猜可能是string::size()的返回值的問題,跑去cpp reference string::size()查看,赫然發現這樣一句話:

The number of bytes in the string.
size_t is an unsigned integral type (the same as member type string::size_type).

瞬間明白了:string::size()返回的是一個無符號的整數。
並由此推導出:當它的返回值和一個有符號數比較時,有符號數會被隱式轉換成無符號數。(不是取絕對值,而是對將最高爲(MSB)當成數字處理,不再表示符號)

KMP算法裏,遊標j可能爲-1,因此當判斷條件j < text.size()中的j爲-1時,它的二進制補碼爲0xFFFFFFFF,而作爲無符號數它被轉化爲了4294967295,因此沒有按我本來的意思執行。
我做的實驗如下:

//test for string::size() and string::length()
#include <iostream>

int main(int argc, char const *argv[])
{
    string test("abcd");
    int slen = test.size();
    int llen = test.length();

    signed int i = -1;
    unsigned int K = 4294967295;
    int minus_one = 0xFFFFFFFF;
    cout << minus_one << endl;
    cout << 0xFFFFFFFF << endl;

    if(K >= i)
        cout << "K > i true" << endl;
    else
        cout << "K > i false" << endl;

    if(test.size() > i)
        cout << "test.size() > i true" << endl;
    else
        cout << "test.size() > i false" << endl;

    if(slen > 0)
        cout << "slen > 0 true" << endl;
    else
        cout << "slen > 0 false" << endl;
    if(llen > 0)
        cout << "llen > 0 true" << endl;
    else
        cout << "llen > 0 false" << endl;
    if(slen > -1)
        cout << "slen > -1 true" << endl;
    else
        cout << "slen > -1 false" << endl;
    if(llen > -1)
        cout << "llen > -1 true" << endl;
    else
        cout << "llen > -1 false" << endl;

    if(test.size() > 0)
        cout << "test.size() > 0 true" << endl;
    else
        cout << "test.size() > 0 false" << endl;
    if(test.length() > 0)
        cout << "test.length() > 0 true" << endl;
    else
        cout << "test.length() > 0 false" << endl;

    //pay attention to the following lines
    if(test.size() > -1)
        cout << "test.size() > -1 true" << endl;
    else
        cout << "test.size() > -1 false" << endl;
    if(test.length() > -1)
        cout << "test.length() > -1 true" << endl;
    else
        cout << "test.length() > -1 false" << endl;
    return 0;
}

打印的內容也充分地說明了這一點,同時還說明了string::length()的行爲與string::size()是完全相同的。

-1
4294967295
K > i true
test.size() > i false
slen > 0 true
llen > 0 true
slen > -1 true
llen > -1 true
test.size() > 0 true
test.length() > 0 true
test.size() > -1 false
test.length() > -1 false

提醒自己:不要將string類型的size()和length()方法的返回值直接用來比較,可能會產生預計之外的情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章