2016-09-29 9 views
0

私はC言語を使ってコード練習をしています。nullポインタによる奇妙な点の問題

はコード、

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define _CRT_SECURE_NO_WARNINGS 

int ACDSort(const void *p1, const void *p2); 
int Compare(const void *pKey, const void *pValue); 
int main(void) 
{ 
    char * strAry[4] = {"Hardware","Cookie","Boy","Power"}; 
    char * destStr = "Cookie"; 

    //qsort((void*)strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), ACDSort); 

    char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), Compare); 

    printf("%s\n", *ptrAdr); 
} 

int Compare(const void *pKey, const void *pValue) { 
    char *key = ((char*)pKey); 
    char *value = *((char**)pValue); 
    return strcmp(key, value); 
} 

int ACDSort(const void *p1, const void *p2) { 

    char * n1 = *((char**)p1); 
    char * n2 = *((char**)p2); 
    int ret; 

    if (strlen(n1) > strlen(n2)) 
     ret = 1; 
    else if (strlen(n1) < strlen(n2)) 
     ret = -1; 
    else 
     ret = 0; 
    return ret; 
} 

以下のとおり私はcookieの文字列を検索するbsearchと呼ばれます。 問題は、文字列の長さに基づいて配列をソートするために//を消去したときにエラーが発生したことです。 qsortが私のコードに重大な影響を与えることができないと思って、なぜエラーが実行されたのか分かりません。

//の消去時にエラーが発生した理由を教えてください。

ps。私はqsortbsearchを使ってポインタ変数に慣れる。

+4

'bsearch'は、配列がすでにソートされている場合にのみ機能します –

+1

通常、' qsort() 'と' bsearch() 'の両方に同じ比較関数を使うべきです。異なる機能を使用する必要がある場合は、何か問題があります。 –

+0

なぜ 'qsort()'と 'bsearch()'の両方に異なる関数を使うのですか? – sclee1

答えて

5

bsearchはバイナリ検索を使用しているためです。バイナリ検索では、データをソートする必要があります。文字列配列をアルファベット順にソートすれば正常に動作します。

副作用として、これらの余分なキャストをすべて取り除く必要があります。それは潜在的なバグを隠すことだけです。修正とクリーンアップ後のプログラムの作業

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int compare (const void* p1, const void* p2); 

int main (void) 
{ 
    const char* strAry[4] = {"Boy", "Cookie", "Hardware", "Power"}; 
    const char* key = "Cookie"; 

    char** ptrAdr = bsearch(key, 
          strAry, 
          sizeof(strAry)/sizeof(*strAry), 
          sizeof(*strAry), 
          compare); 

    printf("%s\n", *ptrAdr); 
} 

int compare (const void* p1, const void* p2) 
{ 
    const char* s1 = p1; 
    const char* s2 = *(const char* const*)p2; 

    return strcmp(s1, s2); 
} 

p2はconstの-正しさのために努力するとき、我々はその奇妙に見えるキャストを取得する理由である、const char*constのvoidポインタを終了します。 destStr

-1

タイプは例えば、strAryの種類と同じになるように変更することができます:あなたはC言語(とコンパイラ)を使用する場合

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int Compare(const void *pKey, const void *pValue) 
{ 
    char *key = *((char**)pKey); 
    char *value = *((char**)pValue); 
    return strcmp(key, value); 
} 

int main(void) 
{ 
    char * strAry[4] = { "Hardware", "Cookie", "Boy", "Power" }; 
    char * destStr[1] = { "Cookie" }; // Type changing 

    qsort(strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), Compare); 

    char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), Compare); 

    printf("%s\n", *ptrAdr); 
} 

また、2つの要素を比較し、コールバック関数として直接strcmpを使用することを検討してください。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

/*int Compare(const void *pKey, const void *pValue) 
{ 
    char *key = *((char**)pKey); 
    char *value = *((char**)pValue); 
    return strcmp(key, value); 
}*/ 

int main(void) 
{ 
    char * strAry[4] = { "Hardware", "Cookie", "Boy", "Power" }; 
    char * destStr[1] = { "Cookie" }; // Type changing 

    //qsort(strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), Compare); 
    qsort(strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), strcmp); 

    //char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), Compare); 
    char **ptrAdr = (char**)bsearch(destStr, strAry, sizeof(strAry)/sizeof(char*), sizeof(char*), strcmp); 

    printf("%s\n", *ptrAdr); 
} 

注:[デフォルトで有効になって]互換性のないポインタ型から 'bsearchは' の引数を渡す5:

このソリューションは、

警告...のように見える一つの欠点を持っています

でも動作します(GCCバージョン4.8.2とMS Visual studio 12.0で試しました)

+1

テスト時にはうまくいくかもしれませんが、コンパイラがあなたに伝えようとしているのは依然として不正です。単純なラッパーが問題を修正する際に起こりうる問題を導入する必要はありません。 Cの動作が未定義であるため、テストだけで何か問題がないかどうかを判断することはできません。 – user694733

+0

はい、それはトリックのようです。だから、代わりに使用できるコメント付きのコードを残します。 – VolAnd

+1

'int(*)(const char *)(const char *)'から 'int(*)(const void *)(const void *)'へのポインタ変換は未定義の動作を呼び出します。 'void *'と 'char *'が同じ表現をしている場合や、コードにポインタエイリアシングの最適化がない場合には、2つの間に呼び出し規約の相違がない場合に運がうまくいくでしょう。 – Lundin