4

qsort を使用して文字列の配列をソートする方法を学んでいるときに、困惑した質問があります。たとえば、次のように並べ替えるにはs

 char *s[] = {
                   "Amit",
                   "Garima",
                   "Gaurav",
                   "Vaibhav"
                };

qsort を使用するには、次の関数のような比較関数を提供する必要がありますcstring_cmp。qsort 関数では、関数に渡されるパラメーターの型cstring_cmpchar**. を に変換する方法char**void*? を に変換できるのはなぜchar**ですかvoid*?

    int cstring_cmp(const void *a, const void *b)
    {
        const char **ia = (const char **)a;
        const char **ib = (const char **)b;
        return -strcasecmp(*ia, *ib);
        /* return the negative of the normal comparison */
    }
4

3 に答える 3

2

qsort()あなたが提供する例は、charポインターの配列(char *)をソートするように要求するようにセットアップされています。あなたが提供しているこのコンパレーターには、アルゴリズムが必要とする項目の「ペア」ごとに addressが与えられます。2 つの char ポインター。使用するアドレスは、指定qsort()したルート アドレスに基づいており、「アイテム」ごとにサイズ バイトが追加されます。各「項目」は char* であるため、各項目のサイズは実際にはポインターのサイズです。

コンパレーターを変更して、何が比較され、どのアドレスが渡されるかを示しました。これらはすべて、すべての char * を含む配列のベースアドレスからのインクリメントであることがわかります。

char *mystrings[] =
{
    "This",
    "is",
    "a",
    "test",
    "of",
    "pointers",
    "to",
    "strings"
};

int cstring_cmp(const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    printf("%p:%s - %p:%s\n", a, *ia, b, *ib);
    return -strcasecmp(*ia, *ib);
}

int main(int argc, char *argv[])
{
    printf("Base address of our pointer array: %p\n\n", mystrings);
    qsort(mystrings, sizeof(mystrings)/sizeof(mystrings[0]), sizeof(char*), cstring_cmp);
    for (size_t i=0; i<sizeof(mystrings)/sizeof(mystrings[0]);i++)
        printf("%s\n", mystrings[i]);
    return 0;

}

次の出力が生成されます。

Base address of our pointer array: 0x100006240

0x100006240:This - 0x100006260:of
0x100006260:of - 0x100006278:strings
0x100006240:This - 0x100006278:strings
0x100006248:is - 0x100006240:strings
0x100006278:This - 0x100006240:strings
0x100006250:a - 0x100006240:strings
0x100006270:to - 0x100006240:strings
0x100006258:test - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006268:pointers - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006240:test - 0x100006248:This
0x100006248:test - 0x100006250:to
0x100006240:This - 0x100006248:to
0x100006260:of - 0x100006268:pointers
0x100006268:of - 0x100006270:a
0x100006270:a - 0x100006278:is
0x100006268:of - 0x100006270:is
to
This
test
strings
pointers
of
is
a
于 2012-11-05T03:57:48.940 に答える
2

あなたの質問は少し漠然としていますが、とにかくやってみます。どのように答えるかというと、単純にキャストするだけで、C の任意のポインター型を他の任意のポインター型に変換できます。その理由に答えるために、それがCの定義方法です。

関数にはqsort()、指定されたプロトタイプ (with const void *) パラメーターを持つ関数が必要です。これは、が並べ替えている実際のqsort()データ型を認識しておらず、比較コールバックに一貫した関数プロトタイプを使用する必要があるためです。比較コールバックは、パラメーターを配列内の実際の型へのポインターに変換する責任があります。const void *const char **

于 2012-11-05T03:31:05.943 に答える
0

さらに視覚化されていないもの:

int cstring_cmp(const void *a, const void *b){
    return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}

しかし、あなたは見ることができ、aそれらは逆参照され、になり、に渡されます。bchar **char *strcasecmp


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

int cstring_cmp(const void *a, const void *b){
    return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
}

int main(){
    char *s[] = {  "Amit",
                   "Garima",
                   "Vaibhav",
                   "Gaurav"};
    qsort(s, 4, sizeof(char *), cstring_cmp);
    printf("%s\n%s\n%s\n%s\n", s[0], s[1], s[2], s[3]);
    return 0;
}

出力:

Vaibhav
Gaurav
Garima
Amit

メモリ (RAM または仮想) バイトへのポインタを意味するため、任意のポインタをchar *orにキャストすることは合法です。void *void *

于 2012-11-05T04:23:04.423 に答える