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。
頭の中で物事をまっすぐに保つのに役立つ場合、コンパレータでポインタをキャストする必要があるタイプは、qsort
に渡すデータポインタの元のタイプと同じです(qsortドキュメントではbase
と呼ばれます)。ただし、qsort
をジェネリックにするために、「実際に」何であるかに関係なく、すべてをvoid*
として処理します。
したがって、intの配列を並べ替える場合は、int*
を渡します(void*
に変換されます)。 qsortは、コンパレータへの2つのvoid*
ポインタを返します。これをint*
に変換し、逆参照して実際に比較するint
値を取得します。
ここで、int
をchar*
に置き換えます。
char*
の配列を並べ替える場合は、char**
を渡します(void*
に変換されます)。 qsortは、コンパレータへの2つのvoid*
ポインタを返します。これをchar**
に変換し、逆参照して実際に比較するchar*
値を取得します。
あなたの例では、配列を使用しているため、渡すchar**
は、最初の要素へのポインターへのchar*
の配列の「減衰」の結果です。最初の要素はchar*
であるため、それへのポインターはchar**
です。
データがdouble data[5]
だったと想像してください。
Compareメソッドは、要素(double)へのポインター(double *、void *として渡される)を受け取ります。
ここで、doubleをchar *に再度置き換えます。
qsort
は、ポインタ以外のもので構成される配列をソートするのに十分一般的です。そのため、サイズパラメータがあります。コンパイル時に配列要素の大きさがわからないため、配列要素を直接比較関数に渡すことはできません。したがって、ポインタを渡します。あなたの場合、char *
、char **
へのポインタを取得します。
比較関数は、ソートする配列内にあるオブジェクトのタイプへのポインターを取ります。配列には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を使用して比較を行います。
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 **
(つまり、文字へのポインタへのポインタ)になります。
char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };
サイズ5の文字ポインターの配列をコンパイラーに要求するステートメントです。これらのポインターを文字列リテラルに初期化しましたが、コンパイラーにとっては、5つのポインターの配列のままです。
その配列をqsort
に渡すと、C配列パラメーターの受け渡し規則に従って、ポインターの配列が最初の要素を指すポインターに減衰します。
したがって、定数を含む実際の文字配列に到達する前に、1レベルの間接参照を処理する必要があります。
@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 );
}