天天看點

strcmp函數實作及分析

最近看C,看到strcmp函數,對它的實作原型不很清楚,于是到網上搜。網上算法一大堆,看了很多代碼後自己做了一下總結

 strcmp函數是C/C++中基本的函數,它對兩個字元串進行比較,然後傳回比較結果,函數形式如下:

int strcmp(const char* str1, const char* str2);

其中str1和str2可以是字元串常量或者字元串變量,傳回值為整形。傳回結果如下規定:

① str1小于str2,傳回負值或者-1(VC傳回-1);                   

② str1等于str2,傳回0;

③ str1大于str2,傳回正值或者1(VC傳回1);

strcmp函數實際上是對字元的ASCII碼進行比較,實作原理如下:首先比較兩個串的第一個字元,若不相等,則停止比較并得出兩個ASCII碼大小比較的結果;如果相等就接着 比較第二個字元然後第三個字元等等。無論兩個字元串是什麼樣,strcmp函數最多比較到其中一個字元串遇到結束符'/0'為止,就能得出結果。strcmp算法的可以有多種,不過我覺的可以把這麼多算法分為兩種,一種是利用減法運算判斷結果,另一種是利用比較運算(==)得出結果。

減法運算的實作的代碼如下:

int strcmp(const char* str1, const char* str2)  

{  

    int ret = 0;  

    while(!(ret=*(unsigned char*)str1-*(unsigned char*)str2) && *str1)  

    {  

        str1++;  

        str2++  

    }  

    if (ret < 0)  

        return -1;  

    else if (ret > 0)  

        return 1;  

    return 0;  

}  

這個函數要注意一下幾點

①使用*(unsigned char*)str1而不是用*str1。這是因為傳入的參數為有符号數,有符号字元值的範圍是-128~127,無符号字元值的範圍是0~255,而字元串的ASCII沒有負值,若不轉化為無符号數這回在減法實作時出現錯誤。

例如 str1的值為1,str2的值為255。

作為無符号數計算時ret = -254,結果為負值,正确

作為有符号數計算時ret = 2,結果為正值,錯誤

②While循環中ret=*(unsigned char*)str1-*(unsigned char*)str2) && *str1,最後與上str1也可以換成str2,因為前面已經做了相減,無論哪個先為‘\0’都會退出。因為最後與上str1是為了判斷str1是否結束,即是否為‘\0’。

③這個函數沒有判斷參數為NULL時的情況,是以當傳入NULL時程式會崩潰。網上看别人說商業化代碼都會在調用strcmp前先判斷是否為NULL,是以可以不用判斷NULL;我在VC6上測試string.h中的strcmp(NULL,NULL),程式也會崩潰。這裡可以根據實際情況來決定。

若要判斷NULL按下面方法更改代碼,可以在這個函數最前面加入斷言

assert((NULL != str1) && (NULL != str2))

但要注意斷言assert 是僅在Debug 版本起作用的宏,是在Debug時做的無害測試。若想在Release 版也可

以判斷NULL,那我們必須用别的代碼來判斷。

可以在程式前面加入if判斷

if ((NULL != str1) && (NULL != str2))

{

return 0;

}

我用CFree 5測試sting.h中的strcmp(NULL,NULL),程式傳回值為0(strcmp(NULL,str1)崩潰),這裡我們可以傳回其他的值如 -2。

我們也可以在函數前面加入while判斷

while ((NULL != str1) && (NULL != str2))

//strcmp實作代碼

利用while就可以把每個字元都進行判斷。

利用比較運算(==)算法如下

    while ((*str1) && (*str1 == *str2))  

        str2++;  

    if (*(unsigned char*)str1 > *(unsigned char*)str2)  

    else if (*(unsigned char*)str1 < *(unsigned char*)str2)  

    else  

        return 0;  

    }    

函數注意點和上面一樣,有一點要注意不要為了簡潔而寫成下面

int strcmp(const char *str1,const char *str2)  

    while ((*str1) && (*str1++ == *str2++)) //這裡++會引起錯誤  

    NULL;  

    }   

當str1為abcd,st2為abfd時,由于判斷到第三個字元時while推出,而str指針又加了1,str都指向第四個字元輸出結果為0,顯然這是錯誤的。

這個函數也可以用for來實作

int strcmp(const char *str1, const char *str2)  

    for ( ; *str1 == *str2; str1++, str2++)  

    {     

        if (*str1 == '\0')  

    //如果隻傳回正負的話可以用 return *(unsigned char*)str1 - *(unsigned char*)str2;  

}  

轉載連結:http://blog.csdn.net/wgenek/article/details/7257435

繼續閱讀