web-dev-qa-db-ja.com

Cでcharへのポインタの配列をqsortする方法は?

Cにcharへのポインタの配列があるとします。

_char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
_

そして、qsortを使用してこの配列をソートしたいと思います。

_qsort(data, 5, sizeof(char *), compare_function);
_

比較機能が思いつかない。何らかの理由でこれは機能しません:

_int compare_function(const void *name1, const void *name2)
{
    const char *name1_ = (const char *)name1;
    const char *name2_ = (const char *)name2;
    return strcmp(name1_, name2_);
}
_

多くの検索を行ったところ、qsort内で_**_を使用する必要があることがわかりました。

_int compare_function(const void *name1, const void *name2)
{
    const char *name1_ = *(const char **)name1;
    const char *name2_ = *(const char **)name2;
    return strcmp(name1_, name2_);
}
_

そして、これは機能します。

この関数での*(const char **)name1の使用について誰かが説明できますか?全くわかりません。なぜダブルポインタなのか?元の機能が機能しなかったのはなぜですか?

ありがとう、BodaCydo。

24
bodacydo

頭の中で物事をまっすぐに保つのに役立つ場合、コンパレータでポインタをキャストする必要があるタイプは、qsortに渡すデータポインタの元のタイプと同じです(qsortドキュメントではbaseと呼ばれます)。ただし、qsortをジェネリックにするために、「実際に」何であるかに関係なく、すべてをvoid*として処理します。

したがって、intの配列を並べ替える場合は、int*を渡します(void*に変換されます)。 qsortは、コンパレータへの2つのvoid*ポインタを返します。これをint*に変換し、逆参照して実際に比較するint値を取得します。

ここで、intchar*に置き換えます。

char*の配列を並べ替える場合は、char**を渡します(void*に変換されます)。 qsortは、コンパレータへの2つのvoid*ポインタを返します。これをchar**に変換し、逆参照して実際に比較するchar*値を取得します。

あなたの例では、配列を使用しているため、渡すchar**は、最初の要素へのポインターへのchar*の配列の「減衰」の結果です。最初の要素はchar*であるため、それへのポインターはchar**です。

22
Steve Jessop

データがdouble data[5]だったと想像してください。

Compareメソッドは、要素(double)へのポインター(double *、void *として渡される)を受け取ります。
ここで、doubleをchar *に再度置き換えます。

3
Henk Holterman

qsortは、ポインタ以外のもので構成される配列をソートするのに十分一般的です。そのため、サイズパラメータがあります。コンパイル時に配列要素の大きさがわからないため、配列要素を直接比較関数に渡すことはできません。したがって、ポインタを渡します。あなたの場合、char *char **へのポインタを取得します。

2
jilles

比較関数は、ソートする配列内にあるオブジェクトのタイプへのポインターを取ります。配列にはchar *が含まれているため、比較関数はchar *、別名char **へのポインターを取ります。

たぶん、私からのコード例を提供する方が簡単です。 TreeNodeの配列を並べ替えようとしていますが、コンパレータの最初の数行は次のようになっています。

int compareTreeNode(const void* tt1, const void* tt2) {
   const TreeNode *t1, *t2;
   t1=*(const TreeNode**)tt1;
   t2=*(const TreeNode**)tt2;

その後、t1とt2を使用して比較を行います。

0
Kemin Zhou

man qsortから:

The  contents of the array are sorted in ascending 
order according to a comparison function pointed to by
compar, which is called with two arguments that **point**
to the objects being compared.

したがって、比較関数は配列要素へのポインタを取得するように聞こえます。これで、char *へのポインタはchar **(つまり、文字へのポインタへのポインタ)になります。

0
Andre Holzner

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

サイズ5の文字ポインターの配列をコンパイラーに要求するステートメントです。これらのポインターを文字列リテラルに初期化しましたが、コンパイラーにとっては、5つのポインターの配列のままです。

その配列をqsortに渡すと、C配列パラメーターの受け渡し規則に従って、ポインターの配列が最初の要素を指すポインターに減衰します。

したがって、定数を含む実際の文字配列に到達する前に、1レベルの間接参照を処理する必要があります。

0
Billy ONeal

@bodacydoは、他のプログラマーが伝えようとしていることを説明するプログラムですが、これは「整数」のコンテキストになります。

#include <stdio.h>


int main()
{
    int i , j;
    int *x[2] = {&i, &j};

    i = 10; j = 20;

    printf("in main() address of i = %p, address of j = %p \r\n", &i, &j);

    fun(x);
    fun(x + 1);

    return 0;
}


void fun(int **ptr)
{
    printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr);
    printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr );
}
0
linuxstack