簡體   English   中英

比較Qsort使用的函數 - 比較(char **)

[英]Compare Function used by Qsort - Comparing (char **)

這是比較功能:

int compare(const void *a, const void *b) {
    char* *s = (char* *) a;
    char* *t = (char* *) b;
    return sort_order * strcmp(*s, *t); // sort_order is -1 or 1
}

現在我的問題是投射到特定類型的double pointer背后的原因是什么? 或者更確切地說, 為什么需要雙指針轉換以及如何在內部使用它

使用的其他變量: char **wordlist; int nbr_words; (數組元素是) char *word;

Ex qsort調用: qsort(wordlist, nbr_words, sizeof(char *), compare);

如果你展示wordlist的定義會有所幫助,但很可能它被定義為char ** compare()函數接收指向列表中每個元素的指針。 如果列表中的每個元素都是char *類型,那么compare()將接收兩個指向char *指針,或者char **句話就是兩個char **

轉換為char ** (注意,實際將是多余的,在這種特殊情況下,如果你不從去const空指針,以非const char ** )本身是必要的,因為qsort()有處理任何類型的類型,因此參數在傳遞之前轉換為void * 你無法尊重void *所以你必須先將它們轉換回原來的類型,然后再對它們做任何事情。

例如:

#include <stdio.h>

int compare_int(void * a, void * b) {
    int * pa = a;
    int * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_double(void * a, void * b) {
    double * pa = a;
    double * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_any(void * a, void * b, int (*cfunc)(void *, void *)) {
    return cfunc(a, b);
}

int main(void) {
    int a = 1, b = 2;
    if ( compare_any(&a, &b, compare_int) ) {
        puts("a and b are not equal");
    } else {
        puts("a and b are equal");
    }

    double c = 3.0, d = 3.0;
    if ( compare_any(&c, &d, compare_double) ) {
        puts("c and d are not equal");
    } else {
        puts("c and d are equal");
    }

    return 0;
}

輸出:

paul@local:~/src/c/scratch$ ./comp
a and b are not equal
c and d are equal
paul@local:~/src/c/scratch$

compare_any()函數將比較所支持的任何類型,在本例中為intdouble ,因為我們可以將函數指針傳遞給它。 但是,傳遞函數的簽名必須相同,因此我們不能聲明compare_int()接受兩個int *參數,而compare_double()取兩個double * 我們必須聲明它們都是兩個void *參數,當我們這樣做時,我們必須將這些void *參數轉換為這些函數中有用的東西,然后才能使用它們。

在你的情況下發生的事情是完全相同的,但數據本身是指針,所以我們傳遞指針指針,所以我們需要將void *轉換為,在你的情況下, char **

編輯:為了解釋有關qsort()如何工作的原始問題的評論中的一些混淆,這里是qsort()簽名:

void qsort(void *base, size_t nmemb, size_t size,
           int(*compar)(const void*, const void*))

base是指向數組第一個元素的指針, nmemb是該數組的成員數, size是每個元素的大小。

qsort()調用compar on,比如數組的第一個和第二個元素時,它將發送第一個元素的地址(即base本身)和元素的地址(即base + size )。

如果base最初被聲明為int數組,那么compare函數必須將它接收的那些指針解釋為指向int指針,如int * 如果base最初被聲明為字符串數組,作為char ** ,則compare函數必須將這些指針解釋為char *指針,即char **

在所有情況下,compare函數都會獲得指向元素的指針。 如果你有一個int數組,那么你必須在比較函數中將這些指針解釋為int * 如果你有一個char *數組,那么你必須將它們解釋為char ** ,依此類推。

在這種情況下,如果你只是將普通的char *參數傳遞給compare函數,你顯然可以調用strcmp() 但是,因為qsort()是通用的,它只能傳遞指向compare函數的指針,它實際上不能傳遞元素的值 - 它是使用void *允許它是通用的,因為任何類型的對象指針都可以轉換為void * ,但沒有可以轉換任何非指針值的等效數據類型。 因此,它必須以常規類型(如intdouble ,帶指針和結構)以相同的方式工作,並且使其與所有可能類型正確工作的唯一方法是讓它處理指向元素的指針,不是元素本身,即使元素本身也是指針。 出於這個原因,在這里看起來似乎得到了一個不必要的間接層,但實際上它必要的,以便qsort()能夠以它的通用方式運行。

如果我修改上面的代碼,你可以更清楚地看到這一點,這樣compare_any()更類似於qsort() ,並且不需要兩個指針,而是一個指向各種類型的雙元素數組的單個指針(稍微做作的例子,但是我們保持簡單):

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

int compare_int(void * a, void * b) {
    int * pa = a;
    int * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_double(void * a, void * b) {
    double * pa = a;
    double * pb = b;
    if ( *pa < *pb ) {
        return -1;
    } else if ( *pa > *pb ) {
        return 1;
    } else {
        return 0;
    }
}

int compare_string(void * a, void * b) {
    char ** pa = a;
    char ** pb = b;
    return strcmp(*pa, *pb);
}

int compare_any(void * arr, size_t size, int (*cfunc)(void *, void *)) {
    char * first = arr;
    char * second = first + size;
    return cfunc(first, second);
}

int main(void) {
    int n[2] = {1, 2};
    if ( compare_any(n, sizeof(*n), compare_int) ) {
        puts("a and b are not equal");
    } else {
        puts("a and b are equal");
    }

    double d[2] = {3.0, 3.0};
    if ( compare_any(d, sizeof(*d), compare_double) ) {
        puts("c and d are not equal");
    } else {
        puts("c and d are equal");
    }

    char * s[] = {"abcd", "bcde"};
    if ( compare_any(s, sizeof(*s), compare_string) ) {
        puts("'abcd' and 'bcde' are not equal");
    } else {
        puts("'abcd' and 'bcde' are equal");
    }

    return 0;
}

輸出:

paul@local:~/src/c/scratch$ ./comp
a and b are not equal
c and d are equal
'abcd' and 'bcde' are not equal
paul@local:~/src/c/scratch$

正如您所看到的, compare_any()無法同時接受int數組和char *數組,而compare_string()函數不會獲得需要將其視為char **的指針,因為指針算術它對數組元素執行。 沒有這種額外的間接級別, compare_int()compare_double()都不起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM